Merge pull request #596 from pupiles/feature/cwe-090

CWE-090: Ldap Injection
This commit is contained in:
Chris Smowton
2021-11-10 11:31:36 +00:00
committed by GitHub
16 changed files with 648 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>If an LDAP query or DN is built using string concatenation or string formatting, and the
components of the concatenation include user input without any proper sanitization, a user
is likely to be able to run malicious LDAP queries.</p>
</overview>
<recommendation>
<p>If user input must be included in an LDAP query or DN, it should be escaped to
avoid a malicious user providing special characters that change the meaning
of the query. In Go, user input should be escaped with <code>EscapeFilter</code>.
A good practice is to escape filter characters
that could change the meaning of the query (https://tools.ietf.org/search/rfc4515#section-3).</p>
</recommendation>
<example>
<p>In the following examples, the code accepts both <code>filter</code> and <code>attr</code> from the user,
which it then uses to build a LDAP query and DN.</p>
<p>The following example uses the unsanitized user input directly
in the search filter and DN for the LDAP query.
A malicious user could provide special characters to change the meaning of these
components, and search for a completely different set of values.</p>
<sample src="example/example_bad.go" />
<p>In the following example, the input provided by the user is sanitized before it is included in the search filter or DN.
This ensures the meaning of the query cannot be changed by a malicious user.</p>
<sample src="example/example_good.go" />
</example>
<references>
<li>OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html">LDAP Injection Prevention Cheat Sheet</a>.</li>
<li>OWASP: <a href="https://owasp.org/www-community/attacks/LDAP_Injection">LDAP Injection</a>.</li>
<li>Go: <a href="https://github.com/go-ldap/ldap">LDAP Documentation</a>.</li>
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/LDAP_injection">LDAP injection</a>.</li>
<li>BlackHat: <a href="https://www.blackhat.com/presentations/bh-europe-08/Alonso-Parada/Whitepaper/bh-eu-08-alonso-parada-WP.pdf">LDAP Injection and Blind LDAP Injection</a>.</li>
<li>LDAP: <a href="https://ldap.com/2018/05/04/understanding-and-defending-against-ldap-injection-attacks/">Understanding and Defending Against LDAP Injection Attacks</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,19 @@
/**
* @name LDAP query built from user-controlled sources
* @description Building an LDAP query from user-controlled sources is vulnerable to insertion of
* malicious LDAP code by the user.
* @kind path-problem
* @problem.severity error
* @id go/ldap-injection
* @tags security
* external/cwe/cwe-90
*/
import go
import LDAPInjection
import DataFlow::PathGraph
from LdapInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "LDAP query parameter is derived from $@.", source.getNode(),
"a user-provided value"

View File

@@ -0,0 +1,111 @@
import go
import DataFlow::PathGraph
/**
* A sanitizer function that prevents LDAP injection attacks.
*/
abstract class LdapSanitizer extends DataFlow::Node { }
/**
* A common sanitizer function. These are name-based heuristics only.
*/
private class CommonLdapEscape extends LdapSanitizer {
CommonLdapEscape() {
exists(DataFlow::MethodCallNode m |
m.getTarget().getName() in [
"sanitizedUserQuery", "sanitizedUserDN", "sanitizedGroupFilter", "sanitizedGroupDN"
]
|
this = m.getResult(0)
)
}
}
/**
* An `EscapeFilter` function from the `go-ldap` or `ldap` packages.
*/
private class EscapeFilterCall extends LdapSanitizer {
EscapeFilterCall() {
exists(Function f |
f.hasQualifiedName([
"github.com/go-ldap/ldap", "github.com/go-ldap/ldap/v3", "gopkg.in/ldap.v2",
"gopkg.in/ldap.v3"
], "EscapeFilter")
|
this = f.getACall()
)
}
}
/**
* A sink that is vulnerable to LDAP injection vulnerabilities.
*/
abstract class LdapSink extends DataFlow::Node { }
/**
* A vulnerable argument to `go-ldap` or `ldap`'s `NewSearchRequest` function.
*/
private class GoLdapSink extends LdapSink {
GoLdapSink() {
exists(Function f |
f.hasQualifiedName([
"github.com/go-ldap/ldap", "github.com/go-ldap/ldap/v3", "gopkg.in/ldap.v2",
"gopkg.in/ldap.v3"
], "NewSearchRequest")
|
this = f.getACall().getArgument([0, 6, 7])
)
}
}
/**
* A value written to the `ldap` package's `SearchRequest.BaseDN` field.
*/
private class LdapV2DNSink extends LdapSink {
LdapV2DNSink() {
exists(Field f, Write w |
f.hasQualifiedName(["gopkg.in/ldap.v2", "gopkg.in/ldap.v3"], "SearchRequest", "BaseDN") and
w.writesField(_, f, this)
)
}
}
/**
* An argument to `go-ldap-client`'s `LDAPClient.Authenticate` or `.GetGroupsOfUser` function.
*/
private class LdapClientSink extends LdapSink {
LdapClientSink() {
exists(Method m |
m.hasQualifiedName("github.com/jtblin/go-ldap-client", "LDAPClient",
["Authenticate", "GetGroupsOfUser"])
|
this = m.getACall().getArgument(0)
)
}
}
/**
* A value written to `go-ldap-client`'s `LDAPClient.Base` field.
*/
private class LdapClientDNSink extends LdapSink {
LdapClientDNSink() {
exists(Field f, Write w |
f.hasQualifiedName("github.com/jtblin/go-ldap-client", "LDAPClient", "Base") and
w.writesField(_, f, this)
)
}
}
/**
* A taint-tracking configuration for reasoning about when an `UntrustedFlowSource`
* flows into an argument or field that is vulnerable to LDAP injection.
*/
class LdapInjectionConfiguration extends TaintTracking::Configuration {
LdapInjectionConfiguration() { this = "Ldap injection" }
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof LdapSink }
override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof LdapSanitizer }
}

View File

@@ -0,0 +1,13 @@
package main
func LDAPInjectionVulnerable(untrusted string) {
// ...
searchRequest := ldap.NewSearchRequest(
"dc=example,dc=com", // The base dn to search
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson)) + untrusted", // BAD: untrusted filter
[]string{"dn", "cn", untrusted}, // BAD: untrusted attribute
nil,
)
// ...
}

View File

@@ -0,0 +1,15 @@
package main
func LDAPInjectionVulnerable(untrusted string) {
// ...
safe := ldap.EscapeFilter(untrusted)
searchRequest := ldap.NewSearchRequest(
"dc=example,dc=com", // The base dn to search
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+safe, // GOOD: sanitized filter
[]string{"dn", "cn", safe}, // GOOD: sanitized attribute
nil,
)
// ...
}

View File

@@ -0,0 +1,37 @@
edges
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:59:3:59:11 | untrusted |
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:61:3:61:51 | ...+... |
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:62:3:62:33 | slice literal |
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:66:3:66:11 | untrusted |
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:68:3:68:51 | ...+... |
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:69:3:69:33 | slice literal |
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:73:3:73:11 | untrusted |
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:75:3:75:51 | ...+... |
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:76:3:76:33 | slice literal |
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:80:22:80:30 | untrusted |
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:81:25:81:33 | untrusted |
nodes
| LDAPInjection.go:57:15:57:29 | call to UserAgent : string | semmle.label | call to UserAgent : string |
| LDAPInjection.go:59:3:59:11 | untrusted | semmle.label | untrusted |
| LDAPInjection.go:61:3:61:51 | ...+... | semmle.label | ...+... |
| LDAPInjection.go:62:3:62:33 | slice literal | semmle.label | slice literal |
| LDAPInjection.go:66:3:66:11 | untrusted | semmle.label | untrusted |
| LDAPInjection.go:68:3:68:51 | ...+... | semmle.label | ...+... |
| LDAPInjection.go:69:3:69:33 | slice literal | semmle.label | slice literal |
| LDAPInjection.go:73:3:73:11 | untrusted | semmle.label | untrusted |
| LDAPInjection.go:75:3:75:51 | ...+... | semmle.label | ...+... |
| LDAPInjection.go:76:3:76:33 | slice literal | semmle.label | slice literal |
| LDAPInjection.go:80:22:80:30 | untrusted | semmle.label | untrusted |
| LDAPInjection.go:81:25:81:33 | untrusted | semmle.label | untrusted |
#select
| LDAPInjection.go:59:3:59:11 | untrusted | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:59:3:59:11 | untrusted | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
| LDAPInjection.go:61:3:61:51 | ...+... | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:61:3:61:51 | ...+... | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
| LDAPInjection.go:62:3:62:33 | slice literal | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:62:3:62:33 | slice literal | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
| LDAPInjection.go:66:3:66:11 | untrusted | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:66:3:66:11 | untrusted | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
| LDAPInjection.go:68:3:68:51 | ...+... | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:68:3:68:51 | ...+... | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
| LDAPInjection.go:69:3:69:33 | slice literal | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:69:3:69:33 | slice literal | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
| LDAPInjection.go:73:3:73:11 | untrusted | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:73:3:73:11 | untrusted | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
| LDAPInjection.go:75:3:75:51 | ...+... | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:75:3:75:51 | ...+... | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
| LDAPInjection.go:76:3:76:33 | slice literal | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:76:3:76:33 | slice literal | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
| LDAPInjection.go:80:22:80:30 | untrusted | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:80:22:80:30 | untrusted | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |
| LDAPInjection.go:81:25:81:33 | untrusted | LDAPInjection.go:57:15:57:29 | call to UserAgent : string | LDAPInjection.go:81:25:81:33 | untrusted | LDAP query parameter is derived from $@. | LDAPInjection.go:57:15:57:29 | call to UserAgent | a user-provided value |

View File

@@ -0,0 +1,135 @@
package main
//go:generate depstubber -vendor github.com/go-ldap/ldap "" ScopeWholeSubtree,NeverDerefAliases,NewSearchRequest,EscapeFilter
//go:generate depstubber -vendor github.com/go-ldap/ldap/v3 "" ScopeWholeSubtree,NeverDerefAliases,NewSearchRequest,EscapeFilter
//go:generate depstubber -vendor github.com/jtblin/go-ldap-client LDAPClient
//go:generate depstubber -vendor gopkg.in/ldap.v2 "" ScopeWholeSubtree,NeverDerefAliases,NewSearchRequest,EscapeFilter
import (
"net/http"
"strings"
goldap "github.com/go-ldap/ldap"
goldapv3 "github.com/go-ldap/ldap/v3"
ldapclient "github.com/jtblin/go-ldap-client"
gopkgldapv2 "gopkg.in/ldap.v2"
)
type Ldap struct{}
func (*Ldap) sanitizedUserQuery(username string) (string, bool) {
badCharacters := "\x00()*\\"
if strings.ContainsAny(username, badCharacters) {
return "", false
}
return username, true
}
func (*Ldap) sanitizedUserDN(username string) (string, bool) {
badCharacters := "\x00()*\\"
if strings.ContainsAny(username, badCharacters) {
return "", false
}
return username, true
}
func (*Ldap) sanitizedGroupFilter(username string) (string, bool) {
badCharacters := "\x00()*\\"
if strings.ContainsAny(username, badCharacters) {
return "", false
}
return username, true
}
func (*Ldap) sanitizedGroupDN(username string) (string, bool) {
badCharacters := "\x00()*\\"
if strings.ContainsAny(username, badCharacters) {
return "", false
}
return username, true
}
func main() {}
// bad is an example of a bad implementation
func (ld *Ldap) bad(req *http.Request) {
// ...
untrusted := req.UserAgent()
goldap.NewSearchRequest(
untrusted, // BAD: untrusted dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter
[]string{"dn", "cn", untrusted}, // BAD: untrusted attribute
nil,
)
goldapv3.NewSearchRequest(
untrusted, // BAD: untrusted dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter
[]string{"dn", "cn", untrusted}, // BAD: untrusted attribute
nil,
)
gopkgldapv2.NewSearchRequest(
untrusted, // BAD: untrusted dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter
[]string{"dn", "cn", untrusted}, // BAD: untrusted attribute
nil,
)
client := &ldapclient.LDAPClient{}
client.Authenticate(untrusted, "123456") // BAD: untrusted filter
client.GetGroupsOfUser(untrusted) // BAD: untrusted filter
// ...
}
// good is an example of a good implementation
func (ld *Ldap) good(req *http.Request) {
// ...
untrusted := req.UserAgent()
escapegoldap := goldap.EscapeFilter(untrusted)
goldap.NewSearchRequest(
escapegoldap, // GOOD: sanitized dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+escapegoldap, // GOOD: sanitized filter
[]string{"dn", "cn", escapegoldap}, // GOOD: sanitized attribute
nil,
)
escapegoldapv3 := goldapv3.EscapeFilter(untrusted)
goldapv3.NewSearchRequest(
escapegoldapv3, // GOOD: sanitized dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+escapegoldapv3, // GOOD: sanitized filter
[]string{"dn", "cn", escapegoldapv3}, // GOOD: sanitized attribute
nil,
)
escapegopkgv2 := gopkgldapv2.EscapeFilter(untrusted)
gopkgldapv2.NewSearchRequest(
escapegopkgv2, // GOOD: sanitized dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+escapegopkgv2, // GOOD: sanitized filter
[]string{"dn", "cn", escapegopkgv2}, // GOOD: sanitized attribute
nil,
)
escapedusercustom, _ := ld.sanitizedUserQuery(untrusted) // GOOD: custom sanitized filter
escapedgroupcustom, _ := ld.sanitizedGroupFilter(untrusted) // GOOD: custom sanitized filter
escapeduserdncustom, _ := ld.sanitizedUserDN(untrusted) // GOOD: custom sanitized filter
escapedgroupdncustom, _ := ld.sanitizedGroupDN(untrusted) // GOOD: custom sanitized filter
client := &ldapclient.LDAPClient{}
client.Authenticate(escapedusercustom, "123456") // GOOD: sanitized filter
client.GetGroupsOfUser(escapedgroupcustom) // GOOD: sanitized filter
gopkgldapv2.NewSearchRequest(
escapeduserdncustom, // GOOD: sanitized dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+"(uid=1)",
[]string{"dn", "cn"},
nil,
)
gopkgldapv2.NewSearchRequest(
escapedgroupdncustom, // GOOD: sanitized dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+"(uid=1)",
[]string{"dn", "cn"},
nil,
)
// ...
}

View File

@@ -0,0 +1 @@
experimental/CWE-090/LDAPInjection.ql

View File

@@ -0,0 +1,11 @@
module example.com/ldap
go 1.16
require (
github.com/go-ldap/ldap v3.0.3+incompatible
github.com/go-ldap/ldap/v3 v3.4.1
github.com/jtblin/go-ldap-client v0.0.0-20170223121919-b73f66626b33
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
gopkg.in/ldap.v2 v2.5.1
)

View File

@@ -0,0 +1,38 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for github.com/go-ldap/ldap, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/go-ldap/ldap (exports: ; functions: ScopeWholeSubtree,NeverDerefAliases,NewSearchRequest,EscapeFilter)
// Package ldap is a stub of github.com/go-ldap/ldap, generated by depstubber.
package ldap
type Control interface {
Encode() interface{}
GetControlType() string
String() string
}
func EscapeFilter(_ string) string {
return ""
}
var NeverDerefAliases int = 0
func NewSearchRequest(_ string, _ int, _ int, _ int, _ int, _ bool, _ string, _ []string, _ []Control) *SearchRequest {
return nil
}
var ScopeWholeSubtree int = 0
type SearchRequest struct {
BaseDN string
Scope int
DerefAliases int
SizeLimit int
TimeLimit int
TypesOnly bool
Filter string
Attributes []string
Controls []Control
}

View File

@@ -0,0 +1,38 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for github.com/go-ldap/ldap/v3, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/go-ldap/ldap/v3 (exports: ; functions: ScopeWholeSubtree,NeverDerefAliases,NewSearchRequest,EscapeFilter)
// Package ldap is a stub of github.com/go-ldap/ldap/v3, generated by depstubber.
package ldap
type Control interface {
Encode() interface{}
GetControlType() string
String() string
}
func EscapeFilter(_ string) string {
return ""
}
var NeverDerefAliases int = 0
func NewSearchRequest(_ string, _ int, _ int, _ int, _ int, _ bool, _ string, _ []string, _ []Control) *SearchRequest {
return nil
}
var ScopeWholeSubtree int = 0
type SearchRequest struct {
BaseDN string
Scope int
DerefAliases int
SizeLimit int
TimeLimit int
TypesOnly bool
Filter string
Attributes []string
Controls []Control
}

View File

@@ -0,0 +1,43 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for github.com/jtblin/go-ldap-client, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/jtblin/go-ldap-client (exports: LDAPClient; functions: )
// Package go_pkg is a stub of github.com/jtblin/go-ldap-client, generated by depstubber.
package go_pkg
import (
tls "crypto/tls"
)
type LDAPClient struct {
Attributes []string
Base string
BindDN string
BindPassword string
GroupFilter string
Host string
ServerName string
UserFilter string
Conn interface{}
Port int
InsecureSkipVerify bool
UseSSL bool
SkipTLS bool
ClientCertificates []tls.Certificate
}
func (_ *LDAPClient) Authenticate(_ string, _ string) (bool, map[string]string, error) {
return false, nil, nil
}
func (_ *LDAPClient) Close() {}
func (_ *LDAPClient) Connect() error {
return nil
}
func (_ *LDAPClient) GetGroupsOfUser(_ string) ([]string, error) {
return nil, nil
}

View File

@@ -0,0 +1,11 @@
module example.com/ldap
go 1.16
require (
github.com/go-ldap/ldap v3.0.3+incompatible
github.com/go-ldap/ldap/v3 v3.4.1
github.com/jtblin/go-ldap-client v0.0.0-20170223121919-b73f66626b33
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
gopkg.in/ldap.v2 v2.5.1
)

View File

@@ -0,0 +1,79 @@
package main
import (
"encoding/gob"
"flag"
"fmt"
"os"
"reflect"
"github.com/github/depstubber/model"
pkg_ "gopkg.in/ldap.v2"
)
var output = flag.String("output", "", "The output file name, or empty to use stdout.")
func main() {
flag.Parse()
types := []struct{
sym string
typ reflect.Type
}{
}
values := []struct{
sym string
val reflect.Value
}{
{ "Authenticate", reflect.ValueOf(pkg_.Authenticate) },
{ "GetGroupsOfUser", reflect.ValueOf(pkg_.GetGroupsOfUser) },
}
// NOTE: This behaves contrary to documented behaviour if the
// package name is not the final component of the import path.
// The reflect package doesn't expose the package name, though.
pkg := model.NewPackage("gopkg.in/ldap.v2", false)
for _, t := range types {
err := pkg.AddType(t.sym, t.typ)
if err != nil {
fmt.Fprintf(os.Stderr, "Reflection: %v\n", err)
os.Exit(1)
}
}
for _, v := range values {
err := pkg.AddValue(v.sym, v.val)
if err != nil {
fmt.Fprintf(os.Stderr, "Reflection: %v\n", err)
os.Exit(1)
}
}
outfile := os.Stdout
if len(*output) != 0 {
var err error
outfile, err = os.Create(*output)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to open output file %q", *output)
}
defer func() {
if err := outfile.Close(); err != nil {
fmt.Fprintf(os.Stderr, "failed to close output file %q", *output)
os.Exit(1)
}
}()
}
if err := gob.NewEncoder(outfile).Encode(model.PackPkg(pkg)); err != nil {
fmt.Fprintf(os.Stderr, "gob encode: %v\n", err)
os.Exit(1)
}
}

View File

@@ -0,0 +1,38 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for gopkg.in/ldap.v2, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: gopkg.in/ldap.v2 (exports: ; functions: ScopeWholeSubtree,NeverDerefAliases,NewSearchRequest,EscapeFilter)
// Package ldap is a stub of gopkg.in/ldap.v2, generated by depstubber.
package ldap
type Control interface {
Encode() interface{}
GetControlType() string
String() string
}
func EscapeFilter(_ string) string {
return ""
}
var NeverDerefAliases int = 0
func NewSearchRequest(_ string, _ int, _ int, _ int, _ int, _ bool, _ string, _ []string, _ []Control) *SearchRequest {
return nil
}
var ScopeWholeSubtree int = 0
type SearchRequest struct {
BaseDN string
Scope int
DerefAliases int
SizeLimit int
TimeLimit int
TypesOnly bool
Filter string
Attributes []string
Controls []Control
}

View File

@@ -0,0 +1,15 @@
# github.com/go-ldap/ldap v3.0.3+incompatible
## explicit
github.com/go-ldap/ldap
# github.com/go-ldap/ldap/v3 v3.4.1
## explicit
github.com/go-ldap/ldap/v3
# github.com/jtblin/go-ldap-client v0.0.0-20170223121919-b73f66626b33
## explicit
github.com/jtblin/go-ldap-client
# gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d
## explicit
gopkg.in/asn1-ber.v1
# gopkg.in/ldap.v2 v2.5.1
## explicit
gopkg.in/ldap.v2