You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
4.3 KiB
Go
176 lines
4.3 KiB
Go
package main
|
|
|
|
//nolint:gosec
|
|
import (
|
|
"bufio"
|
|
"crypto/sha1"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
|
|
"go.dev.pztrn.name/inn2-fudforum-auth/configuration"
|
|
"go.dev.pztrn.name/inn2-fudforum-auth/database"
|
|
)
|
|
|
|
// This structure holds necessary data after parsing stdin or passed
|
|
// by flags.
|
|
type passedParameters struct {
|
|
Username string
|
|
Password string
|
|
}
|
|
|
|
// This structure holds data for database requests.
|
|
type databaseParams struct {
|
|
Username string `db:"login"`
|
|
Password string `db:"passwd"`
|
|
Salt string `db:"salt"`
|
|
}
|
|
|
|
//nolint:gocognit,cyclop
|
|
func main() {
|
|
configuration.Initialize()
|
|
|
|
//nolint:exhaustruct
|
|
params := &passedParameters{}
|
|
|
|
flag.StringVar(¶ms.Username, "user", "", "Username to authenticate. You can use this flag for debugging.")
|
|
flag.StringVar(¶ms.Username, "password", "", "Password to use. You can use this flag for debugging.")
|
|
|
|
flag.Parse()
|
|
|
|
configuration.Cfg.Initialize()
|
|
database.Initialize()
|
|
|
|
if configuration.Cfg.Debug {
|
|
log.Println("Starting inn2-fudforum-auth in debug mode...")
|
|
}
|
|
|
|
// Check our running mode. If params structure isn't filled - then
|
|
// we should read from stdin.
|
|
//nolint:nestif
|
|
if params.Username != "" || params.Password != "" {
|
|
if configuration.Cfg.Debug {
|
|
log.Println("-user or -password passed, will use these parameters values for authentication.")
|
|
}
|
|
// We should have both fields filled.
|
|
if params.Username == "" {
|
|
log.Fatalln("You should provide -user parameter.")
|
|
}
|
|
|
|
if params.Password == "" {
|
|
log.Fatalln("You should provide -password parameter.")
|
|
}
|
|
} else {
|
|
if configuration.Cfg.Debug {
|
|
log.Println("-user or -password WASN'T passed, will use stdin for authentication.")
|
|
}
|
|
|
|
input := bufio.NewScanner(os.Stdin)
|
|
|
|
for {
|
|
input.Scan()
|
|
// That means inn2 stopped sending data to stdin due to
|
|
// error or timeout.
|
|
if err := input.Err(); err != nil {
|
|
break
|
|
}
|
|
|
|
// If we gathered all needed data - stop iterating.
|
|
if params.Username != "" && params.Password != "" {
|
|
break
|
|
}
|
|
|
|
inputDataRaw := input.Text()
|
|
if strings.Contains(inputDataRaw, "ClientAuthname: ") {
|
|
inputData := strings.Split(inputDataRaw, ": ")
|
|
if len(inputData) == 1 {
|
|
log.Fatalln("Empty auth name (login) passed.")
|
|
}
|
|
params.Username = inputData[1]
|
|
if configuration.Cfg.Debug {
|
|
log.Println("Username gathered: " + params.Username)
|
|
}
|
|
}
|
|
|
|
if strings.Contains(inputDataRaw, "ClientPassword: ") {
|
|
inputData := strings.Split(inputDataRaw, ": ")
|
|
if len(inputData) == 1 {
|
|
log.Fatalln("Empty password passed.")
|
|
}
|
|
params.Password = inputData[1]
|
|
if configuration.Cfg.Debug {
|
|
log.Println("Password gathered: " + params.Password)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if configuration.Cfg.Debug {
|
|
log.Printf("Got authentication data: %+v\n", params)
|
|
}
|
|
|
|
// Get data from FUDForum's database.
|
|
//nolint:exhaustruct
|
|
dbData := &databaseParams{}
|
|
|
|
if err := database.Conn.Get(dbData,
|
|
"SELECT login, passwd, salt FROM "+configuration.Cfg.Database.Prefix+"users WHERE login=$1 OR alias=$2",
|
|
params.Username,
|
|
params.Username,
|
|
); err != nil {
|
|
log.Fatalln("Failed to get data from FUDForum database: " + err.Error())
|
|
}
|
|
|
|
if configuration.Cfg.Debug {
|
|
log.Printf("Got data from FUDForum database: %+v\n", dbData)
|
|
}
|
|
|
|
// FUDForum uses sha1(salt + sha1(password)).
|
|
//nolint:gosec
|
|
passHashRaw := sha1.New()
|
|
_, _ = passHashRaw.Write([]byte(params.Password))
|
|
passHash := fmt.Sprintf("%x", passHashRaw.Sum(nil))
|
|
|
|
//nolint:gosec
|
|
saltedPassHashRaw := sha1.New()
|
|
_, _ = saltedPassHashRaw.Write([]byte(dbData.Salt + passHash))
|
|
saltedPassHash := fmt.Sprintf("%x", saltedPassHashRaw.Sum(nil))
|
|
|
|
if configuration.Cfg.Debug {
|
|
log.Printf("Password stored in database: %s, we hashed: %s (pre: %s)\n", dbData.Password, saltedPassHash, passHash)
|
|
}
|
|
|
|
if dbData.Password != saltedPassHash {
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Check groups mapping.
|
|
// This is temporary, in future versions all groups memberships
|
|
// should be managed on FUDForum side.
|
|
group := configuration.Cfg.Groups.Default
|
|
|
|
for _, groupMapping := range configuration.Cfg.Groups.Groups {
|
|
var userFound bool
|
|
|
|
for _, user := range groupMapping.Users {
|
|
if user == params.Username {
|
|
group = groupMapping.Group
|
|
userFound = true
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
if userFound {
|
|
break
|
|
}
|
|
}
|
|
|
|
//nolint:forbidigo
|
|
fmt.Printf("User:%s@%s\r\n", params.Username, group)
|
|
|
|
database.Shutdown()
|
|
}
|