-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
2867a0
committed
Aug 7, 2023
1 parent
17d1971
commit dac8a91
Showing
8 changed files
with
280 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
//go:build !windows | ||
|
||
package cli | ||
|
||
import ( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
//go:build windows | ||
|
||
package cli | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
"goLdapTools/cli/global" | ||
"goLdapTools/cli/modify" | ||
"goLdapTools/cli/search" | ||
"goLdapTools/conn" | ||
"goLdapTools/log" | ||
"os" | ||
) | ||
|
||
func init() { | ||
//global argument | ||
rootCmd.PersistentFlags().StringP(global.DomainNameStr, "d", "", "domain name (example: test.lab)") | ||
rootCmd.PersistentFlags().StringP(global.UserStr, "u", "", "username") | ||
rootCmd.PersistentFlags().StringP(global.PassStr, "p", "", "password") | ||
rootCmd.PersistentFlags().StringP(global.HashStr, "", "", "hash") | ||
rootCmd.PersistentFlags().StringP(global.GssApiStr, "t", "", "login with current user token(example: --gssapi dc.test.lab)") | ||
rootCmd.PersistentFlags().StringP(global.BaseDnStr, "b", "", "Specify DN (ou=xx,dc=xx,dc=xx)") | ||
rootCmd.PersistentFlags().BoolP(global.SslStr, "s", false, "Use ssl to connect to ldap. default false") | ||
rootCmd.PersistentFlags().StringP(global.ExportStr, "o", "", "save result to file.") | ||
|
||
//search mode | ||
rootCmd.AddCommand(search.SearchCmd) | ||
|
||
//modify mode | ||
rootCmd.AddCommand(modify.AddCmd) | ||
} | ||
|
||
var rootCmd = &cobra.Command{ | ||
Use: "goLdapTool", | ||
Short: "golang ldap tool", | ||
Long: `An Ldap operation tool written in golang, | ||
with functions including searching and modifying Ldap entry attributes`, | ||
|
||
Run: func(cmd *cobra.Command, args []string) { | ||
config, err := global.ParseGlobalCommand(cmd) | ||
if err != nil { | ||
log.PrintErrorf("Parse global command error: %s", err.Error()) | ||
os.Exit(1) | ||
} | ||
|
||
log.PrintDebugf("Connect config:\n"+ | ||
" server: %s\n"+ | ||
" username: %s\n"+ | ||
" password: %s\n"+ | ||
" dn: %s", config.DomainName, config.UserName, config.Password, config.BaseDN) | ||
|
||
// 不使用搜索模块,仅登陆 | ||
ldapConnector, err := conn.LdapConnect(config) | ||
if err != nil { | ||
log.PrintErrorf("error: %s", err.Error()) | ||
os.Exit(1) | ||
} | ||
|
||
log.PrintSuccessf("Connect %s successes", ldapConnector.Config.DomainName) | ||
}, | ||
} | ||
|
||
func Execute() { | ||
if err := rootCmd.Execute(); err != nil { | ||
log.PrintError(err) | ||
os.Exit(1) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
//go:build !windows | ||
|
||
package global | ||
|
||
import ( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
//go:build windows | ||
|
||
package global | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"github.com/spf13/cobra" | ||
"goLdapTools/log" | ||
"strings" | ||
) | ||
|
||
const ( | ||
DomainNameStr = "domain-name" | ||
UserStr = "username" | ||
PassStr = "password" | ||
HashStr = "hash" | ||
GssApiStr = "gssapi" | ||
BaseDnStr = "base-dn" | ||
SslStr = "ssl" | ||
ExportStr = "output" | ||
) | ||
|
||
type GlobalCommand struct { | ||
DomainName string | ||
UserName string | ||
Password string | ||
PassHash string | ||
GssApiLogin string | ||
BaseDN string | ||
SSLConn bool | ||
Export string | ||
} | ||
|
||
func ParseGlobalCommand(cmd *cobra.Command) (config *GlobalCommand, err error) { | ||
domainName, err := cmd.Flags().GetString(DomainNameStr) | ||
if err != nil { | ||
log.PrintDebugf("Failed to parse --domainName-- flag %s", err) | ||
return nil, err | ||
} | ||
if domainName == "" { | ||
return nil, errors.New("domain name is not specified") | ||
} | ||
|
||
u, err := cmd.Flags().GetString(UserStr) | ||
if err != nil { | ||
log.PrintDebugf("Failed to parse --username-- flag %s", err) | ||
return nil, err | ||
} | ||
|
||
password, err := cmd.Flags().GetString(PassStr) | ||
if err != nil { | ||
log.PrintDebugf("Failed to parse --password-- flag %s", err) | ||
return nil, err | ||
} | ||
|
||
passHash, err := cmd.Flags().GetString(HashStr) | ||
if err != nil { | ||
log.PrintDebugf("Failed to parse --hash-- flag %s", err) | ||
return nil, err | ||
} | ||
|
||
gssapi, err := cmd.Flags().GetString(GssApiStr) | ||
if err != nil { | ||
log.PrintDebugf("Failed to parse --gssapi-- flag %s", err) | ||
return nil, err | ||
} | ||
|
||
domainNameArr := strings.Split(domainName, ".") | ||
baseDN, err := cmd.Flags().GetString(BaseDnStr) | ||
if err != nil { | ||
log.PrintDebugf("Failed to parse --base dn-- flag %s", err) | ||
return nil, err | ||
} | ||
if baseDN == "" { | ||
baseDN = fmt.Sprintf("dc=%s", strings.Join(domainNameArr, ",dc=")) | ||
} | ||
|
||
ssl, err := cmd.Flags().GetBool(SslStr) | ||
if err != nil { | ||
log.PrintErrorf("Failed to parse --ssl-- flag %s", err) | ||
return nil, err | ||
} | ||
|
||
export, err := cmd.Flags().GetString(ExportStr) | ||
if err != nil { | ||
log.PrintErrorf("Failed to parse --export-- flag %s", err) | ||
return nil, err | ||
} | ||
|
||
log.SaveResultStr = export | ||
|
||
var userName = u | ||
if !strings.Contains(u, "@") && !strings.Contains(u, "\\") { | ||
userName = fmt.Sprintf("%s@%s", u, domainName) | ||
} | ||
|
||
return &GlobalCommand{ | ||
DomainName: domainName, | ||
UserName: userName, | ||
Password: password, | ||
PassHash: passHash, | ||
GssApiLogin: gssapi, | ||
BaseDN: baseDN, | ||
SSLConn: ssl, | ||
Export: export, | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
//go:build !windows | ||
|
||
package conn | ||
|
||
import ( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
//go:build windows | ||
|
||
package conn | ||
|
||
import ( | ||
"crypto/tls" | ||
"fmt" | ||
"github.com/go-ldap/ldap/v3" | ||
"github.com/go-ldap/ldap/v3/gssapi" | ||
"goLdapTools/cli/global" | ||
"goLdapTools/log" | ||
"strings" | ||
) | ||
|
||
type Connector struct { | ||
Conn *ldap.Conn | ||
Config *global.GlobalCommand | ||
} | ||
|
||
func LdapConnect(globalCommand *global.GlobalCommand) (*Connector, error) { | ||
var conn *ldap.Conn | ||
var sspiConn *gssapi.SSPIClient | ||
var err error | ||
|
||
if globalCommand.GssApiLogin != "" { | ||
sspiConn, err = gssapi.NewSSPIClient() | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
//非加密连接 | ||
if !globalCommand.SSLConn { | ||
log.PrintInfof("Trying to connecting server Ldap://%s:389", globalCommand.DomainName) | ||
conn, err = ldap.Dial("tcp", fmt.Sprintf("%s:389", globalCommand.DomainName)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} else { | ||
// SSL连接 | ||
log.PrintInfof("Trying to connecting server Ldaps://%s:636", globalCommand.DomainName) | ||
conn, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:636", globalCommand.DomainName), | ||
&tls.Config{InsecureSkipVerify: true}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
if globalCommand.PassHash == "" && globalCommand.Password != "" { | ||
log.PrintInfof("Trying to binding server with password") | ||
log.PrintInfof("Domain Name: %s", globalCommand.DomainName) | ||
log.PrintInfof("username: %s", globalCommand.UserName) | ||
log.PrintInfof("password: %s", globalCommand.Password) | ||
|
||
err = conn.Bind(globalCommand.UserName, globalCommand.Password) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} else if globalCommand.UserName != "" && globalCommand.GssApiLogin == "" { | ||
req := &ldap.NTLMBindRequest{ | ||
Domain: globalCommand.DomainName, | ||
Username: strings.Split(globalCommand.UserName, "@")[0], | ||
Hash: globalCommand.PassHash, | ||
AllowEmptyPassword: true, | ||
Controls: nil, | ||
} | ||
|
||
log.PrintInfof("Trying to binding server with hash") | ||
log.PrintInfof("username: %s", strings.Split(globalCommand.UserName, "@")[0]) | ||
log.PrintInfof("pass-hash: %s", globalCommand.PassHash) | ||
|
||
_, err = conn.NTLMChallengeBind(req) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} else { | ||
log.PrintInfo("Trying to binging server with current token") | ||
|
||
err = conn.GSSAPIBind(sspiConn, fmt.Sprintf("ldap/%s", globalCommand.GssApiLogin), "") | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
log.PrintSuccess("Binding success") | ||
|
||
return &Connector{Conn: conn, Config: globalCommand}, nil | ||
} | ||
|
||
func (conn *Connector) DoModify(dn string, control []ldap.Control, attrType string, attrVals []string) error { | ||
modifyReq := ldap.NewModifyRequest(dn, control) | ||
modifyReq.Replace(attrType, attrVals) | ||
return conn.Conn.Modify(modifyReq) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters