1
0
mirror of https://blitiri.com.ar/repos/chasquid synced 2025-12-17 14:37:02 +00:00

Turn chasquid-userdb into chasquid-util

This patch removes chasquid-userdb and adds a more generic and extensive
chasquid-util, that supports various operations on user databases as well as
aliases lookups.

The code is not very pretty but for now I took a more practical approach, the
tool is ancillary and can be tidied up later.
This commit is contained in:
Alberto Bertogli
2016-09-24 00:44:13 +01:00
parent 859d4733f8
commit 3d06fb3a78
6 changed files with 205 additions and 101 deletions

View File

@@ -60,6 +60,7 @@ func main() {
if err != nil { if err != nil {
glog.Fatalf("Error reading config") glog.Fatalf("Error reading config")
} }
config.LogConfig(conf)
// Change to the config dir. // Change to the config dir.
// This allow us to use relative paths for configuration directories. // This allow us to use relative paths for configuration directories.

View File

@@ -1,92 +0,0 @@
package main
import (
"bytes"
"flag"
"fmt"
"os"
"syscall"
"golang.org/x/crypto/ssh/terminal"
"blitiri.com.ar/go/chasquid/internal/userdb"
)
var (
dbFname = flag.String("database", "", "database file")
adduser = flag.String("add_user", "", "user to add")
password = flag.String("password", "",
"password for the user to add (will prompt if missing)")
disableChecks = flag.Bool("dangerously_disable_checks", false,
"disable security checks - DANGEROUS, use for testing only")
)
func main() {
flag.Parse()
if *dbFname == "" {
fmt.Printf("database name missing, forgot --database?\n")
os.Exit(1)
}
db, err := userdb.Load(*dbFname)
if err != nil {
if *adduser != "" && os.IsNotExist(err) {
fmt.Printf("creating database\n")
} else {
fmt.Printf("error loading database: %v\n", err)
os.Exit(1)
}
}
if *adduser == "" {
fmt.Printf("database loaded\n")
return
}
if *password == "" {
fmt.Printf("Password: ")
p1, err := terminal.ReadPassword(syscall.Stdin)
fmt.Printf("\n")
if err != nil {
fmt.Printf("error reading password: %v\n", err)
os.Exit(1)
}
fmt.Printf("Confirm password: ")
p2, err := terminal.ReadPassword(syscall.Stdin)
fmt.Printf("\n")
if err != nil {
fmt.Printf("error reading password: %v\n", err)
os.Exit(1)
}
if !bytes.Equal(p1, p2) {
fmt.Printf("passwords don't match\n")
os.Exit(1)
}
*password = string(p1)
}
if !*disableChecks {
if len(*password) < 8 {
fmt.Printf("password is too short\n")
os.Exit(1)
}
}
err = db.AddUser(*adduser, *password)
if err != nil {
fmt.Printf("error adding user: %v\n", err)
os.Exit(1)
}
err = db.Write()
if err != nil {
fmt.Printf("error writing database: %v\n", err)
os.Exit(1)
}
fmt.Printf("added user\n")
}

View File

@@ -0,0 +1,198 @@
// chasquid-util is a command-line utility for chasquid-related operations.
package main
import (
"fmt"
"io/ioutil"
"os"
"syscall"
"bytes"
"blitiri.com.ar/go/chasquid/internal/aliases"
"blitiri.com.ar/go/chasquid/internal/config"
"blitiri.com.ar/go/chasquid/internal/userdb"
"github.com/docopt/docopt-go"
"golang.org/x/crypto/ssh/terminal"
)
// Usage, which doubles as parameter definitions thanks to docopt.
const usage = `
Usage:
chasquid-util adduser <db> <username> [--password=<password>]
chasquid-util removeuser <db> <username>
chasquid-util authenticate <db> <username> [--password=<password>]
chasquid-util check-userdb <db>
chasquid-util aliases-resolve <configdir> <address>
`
// Command-line arguments.
var args map[string]interface{}
func main() {
args, _ = docopt.Parse(usage, nil, true, "", false)
commands := map[string]func(){
"adduser": AddUser,
"removeuser": RemoveUser,
"authenticate": Authenticate,
"check-userdb": CheckUserDB,
"aliases-resolve": AliasesResolve,
}
for cmd, f := range commands {
if args[cmd].(bool) {
f()
}
}
}
func Fatalf(s string, arg ...interface{}) {
fmt.Printf(s+"\n", arg...)
os.Exit(1)
}
// chasquid-util check-userdb <db>
func CheckUserDB() {
_, err := userdb.Load(args["<db>"].(string))
if err != nil {
Fatalf("Error loading database: %v", err)
}
fmt.Println("Database loaded")
}
// chasquid-util adduser <db> <username> [--password=<password>]
func AddUser() {
db, err := userdb.Load(args["<db>"].(string))
if err != nil {
if os.IsNotExist(err) {
fmt.Println("Creating database")
} else {
Fatalf("Error loading database: %v", err)
}
}
password := getPassword()
err = db.AddUser(args["<username>"].(string), password)
if err != nil {
Fatalf("Error adding user: %v", err)
}
err = db.Write()
if err != nil {
Fatalf("Error writing database: %v", err)
}
fmt.Println("Added user")
}
// chasquid-util authenticate <db> <username> [--password=<password>]
func Authenticate() {
db, err := userdb.Load(args["<db>"].(string))
if err != nil {
Fatalf("Error loading database: %v", err)
}
password := getPassword()
ok := db.Authenticate(args["<username>"].(string), password)
if ok {
fmt.Println("Authentication succeeded")
} else {
Fatalf("Authentication failed")
}
}
func getPassword() string {
password, ok := args["--password"].(string)
if ok {
return password
}
fmt.Printf("Password: ")
p1, err := terminal.ReadPassword(syscall.Stdin)
fmt.Printf("\n")
if err != nil {
Fatalf("Error reading password: %v\n", err)
}
fmt.Printf("Confirm password: ")
p2, err := terminal.ReadPassword(syscall.Stdin)
fmt.Printf("\n")
if err != nil {
Fatalf("Error reading password: %v", err)
}
if !bytes.Equal(p1, p2) {
Fatalf("Passwords don't match")
}
return string(p1)
}
// chasquid-util removeuser <db> <username>
func RemoveUser() {
db, err := userdb.Load(args["<db>"].(string))
if err != nil {
Fatalf("Error loading database: %v", err)
}
present := db.RemoveUser(args["<username>"].(string))
if !present {
Fatalf("Unknown user")
}
err = db.Write()
if err != nil {
Fatalf("Error writing database: %v", err)
}
fmt.Println("Removed user")
}
// chasquid-util aliases-resolve <configdir> <address>
func AliasesResolve() {
configDir := args["<configdir>"].(string)
conf, err := config.Load(configDir + "/chasquid.conf")
if err != nil {
Fatalf("Error reading config")
}
os.Chdir(configDir)
r := aliases.NewResolver()
r.SuffixSep = conf.SuffixSeparators
r.DropChars = conf.DropCharacters
domainDirs, err := ioutil.ReadDir("domains/")
if err != nil {
Fatalf("Error reading domains/ directory: %v", err)
}
if len(domainDirs) == 0 {
Fatalf("No domains found in config")
}
for _, info := range domainDirs {
name := info.Name()
aliasfile := "domains/" + name + "/aliases"
r.AddDomain(name)
err := r.AddAliasesFile(name, aliasfile)
if err == nil {
fmt.Printf("%s: loaded %q\n", name, aliasfile)
} else if err != nil && os.IsNotExist(err) {
fmt.Printf("%s: no aliases file\n", name)
} else {
fmt.Printf("%s: error loading %q: %v\n", name, aliasfile, err)
}
}
rcpts, err := r.Resolve(args["<address>"].(string))
if err != nil {
Fatalf("Error resolving: %v", err)
}
for _, rcpt := range rcpts {
fmt.Printf("%v %s\n", rcpt.Type, rcpt.Addr)
}
}

View File

@@ -69,11 +69,11 @@ type Recipient struct {
Type RType Type RType
} }
type RType int type RType string
const ( const (
EMAIL RType = iota EMAIL RType = "(email)"
PIPE PIPE RType = "(pipe)"
) )
var ( var (

View File

@@ -62,11 +62,10 @@ func Load(path string) (*Config, error) {
c.DataDir = "/var/lib/chasquid" c.DataDir = "/var/lib/chasquid"
} }
logConfig(c)
return c, nil return c, nil
} }
func logConfig(c *Config) { func LogConfig(c *Config) {
glog.Infof("Configuration:") glog.Infof("Configuration:")
glog.Infof(" Hostname: %q", c.Hostname) glog.Infof(" Hostname: %q", c.Hostname)
glog.Infof(" Max data size (MB): %d", c.MaxDataSizeMb) glog.Infof(" Max data size (MB): %d", c.MaxDataSizeMb)

View File

@@ -35,10 +35,8 @@ function chasquid() {
} }
function add_user() { function add_user() {
go run ${TBASE}/../../cmd/chasquid-userdb/chasquid-userdb.go \ go run ${TBASE}/../../cmd/chasquid-util/chasquid-util.go \
--database "config/domains/${1}/users" \ adduser "config/domains/${1}/users" "${2}" --password "${3}" \
--add_user "${2}" \
--password "${3}" \
>> .add_user_logs >> .add_user_logs
} }