mirror of
https://github.com/Luzifer/password.git
synced 2024-11-14 04:02:46 +00:00
283 lines
6.4 KiB
Go
283 lines
6.4 KiB
Go
// Copyright 2010 Jonas mg
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package user
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/tredoe/goutil/cmdutil"
|
|
"github.com/tredoe/goutil/reflectutil"
|
|
"github.com/tredoe/osutil/config/shconf"
|
|
"github.com/tredoe/osutil/user/crypt"
|
|
)
|
|
|
|
// TODO: handle des, bcrypt and rounds in SHA2.
|
|
|
|
// TODO: Idea: store struct "configData" to run configData.Init() only when
|
|
// the configuration files have been modified.
|
|
|
|
// == System configuration files.
|
|
|
|
const _CONF_LOGIN = "/etc/login.defs"
|
|
|
|
type conf_login struct {
|
|
PASS_MIN_DAYS int
|
|
PASS_MAX_DAYS int
|
|
PASS_MIN_LEN int
|
|
PASS_WARN_AGE int
|
|
|
|
SYS_UID_MIN int
|
|
SYS_UID_MAX int
|
|
SYS_GID_MIN int
|
|
SYS_GID_MAX int
|
|
|
|
UID_MIN int
|
|
UID_MAX int
|
|
GID_MIN int
|
|
GID_MAX int
|
|
|
|
ENCRYPT_METHOD string // upper
|
|
SHA_CRYPT_MIN_ROUNDS int
|
|
SHA_CRYPT_MAX_ROUNDS int
|
|
// or
|
|
CRYPT_PREFIX string // $2a$
|
|
CRYPT_ROUNDS int // 8
|
|
}
|
|
|
|
const _CONF_USERADD = "/etc/default/useradd"
|
|
|
|
type conf_useradd struct {
|
|
HOME string // Default to '/home'
|
|
SHELL string // Default to '/bin/sh'
|
|
}
|
|
|
|
// == Optional files.
|
|
|
|
// Used in systems derivated from Debian: Ubuntu, Mint.
|
|
const _CONF_ADDUSER = "/etc/adduser.conf"
|
|
|
|
type conf_adduser struct {
|
|
FIRST_SYSTEM_UID int
|
|
LAST_SYSTEM_UID int
|
|
FIRST_SYSTEM_GID int
|
|
LAST_SYSTEM_GID int
|
|
|
|
FIRST_UID int
|
|
LAST_UID int
|
|
FIRST_GID int
|
|
LAST_GID int
|
|
}
|
|
|
|
// Used in Arch, Manjaro, OpenSUSE.
|
|
// But it is only used by 'pam_unix2.so'.
|
|
const _CONF_PASSWD = "/etc/default/passwd"
|
|
|
|
// TODO: to see the other options of that file.
|
|
type conf_passwd struct {
|
|
CRYPT string // lower
|
|
}
|
|
|
|
// Used in systems derivated from Red Hat: CentOS, Fedora, Mageia, PCLinuxOS.
|
|
const _CONF_LIBUSER = "/etc/libuser.conf"
|
|
|
|
type conf_libuser struct {
|
|
login_defs string
|
|
crypt_style string // lower
|
|
|
|
// For SHA2
|
|
hash_rounds_min int
|
|
hash_rounds_max int
|
|
}
|
|
|
|
// * * *
|
|
|
|
var _DEBUG bool
|
|
|
|
// A configData represents the configuration used to add users and groups.
|
|
type configData struct {
|
|
login conf_login
|
|
useradd conf_useradd
|
|
|
|
crypter crypt.Crypter
|
|
sync.Once
|
|
}
|
|
|
|
var config configData
|
|
|
|
// init sets the configuration data.
|
|
func (c *configData) init() error {
|
|
_conf_login := &conf_login{}
|
|
cmdutil.SetPrefix("\n* ", "")
|
|
|
|
cfg, err := shconf.ParseFile(_CONF_LOGIN)
|
|
if err != nil {
|
|
return err
|
|
} else {
|
|
if err = cfg.Unmarshal(_conf_login); err != nil {
|
|
return err
|
|
}
|
|
if _DEBUG {
|
|
cmdutil.Println(_CONF_LOGIN)
|
|
reflectutil.PrintStruct(_conf_login)
|
|
}
|
|
|
|
if _conf_login.PASS_MAX_DAYS == 0 {
|
|
_conf_login.PASS_MAX_DAYS = 99999
|
|
}
|
|
if _conf_login.PASS_WARN_AGE == 0 {
|
|
_conf_login.PASS_WARN_AGE = 7
|
|
}
|
|
}
|
|
|
|
cfg, err = shconf.ParseFile(_CONF_USERADD)
|
|
if err != nil {
|
|
return err
|
|
} else {
|
|
_conf_useradd := &conf_useradd{}
|
|
if err = cfg.Unmarshal(_conf_useradd); err != nil {
|
|
return err
|
|
}
|
|
if _DEBUG {
|
|
cmdutil.Println(_CONF_USERADD)
|
|
reflectutil.PrintStruct(_conf_useradd)
|
|
}
|
|
|
|
if _conf_useradd.HOME == "" {
|
|
_conf_useradd.HOME = "/home"
|
|
}
|
|
if _conf_useradd.SHELL == "" {
|
|
_conf_useradd.SHELL = "/bin/sh"
|
|
}
|
|
config.useradd = *_conf_useradd
|
|
}
|
|
|
|
// Optional files
|
|
|
|
found, err := exist(_CONF_ADDUSER) // Based in Debian.
|
|
if found {
|
|
cfg, err := shconf.ParseFile(_CONF_ADDUSER)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_conf_adduser := &conf_adduser{}
|
|
if err = cfg.Unmarshal(_conf_adduser); err != nil {
|
|
return err
|
|
}
|
|
if _DEBUG {
|
|
cmdutil.Println(_CONF_ADDUSER)
|
|
reflectutil.PrintStruct(_conf_adduser)
|
|
}
|
|
|
|
if _conf_login.SYS_UID_MIN == 0 || _conf_login.SYS_UID_MAX == 0 ||
|
|
_conf_login.SYS_GID_MIN == 0 || _conf_login.SYS_GID_MAX == 0 ||
|
|
_conf_login.UID_MIN == 0 || _conf_login.UID_MAX == 0 ||
|
|
_conf_login.GID_MIN == 0 || _conf_login.GID_MAX == 0 {
|
|
|
|
_conf_login.SYS_UID_MIN = _conf_adduser.FIRST_SYSTEM_UID
|
|
_conf_login.SYS_UID_MAX = _conf_adduser.LAST_SYSTEM_UID
|
|
_conf_login.SYS_GID_MIN = _conf_adduser.FIRST_SYSTEM_GID
|
|
_conf_login.SYS_GID_MAX = _conf_adduser.LAST_SYSTEM_GID
|
|
|
|
_conf_login.UID_MIN = _conf_adduser.FIRST_UID
|
|
_conf_login.UID_MAX = _conf_adduser.LAST_UID
|
|
_conf_login.GID_MIN = _conf_adduser.FIRST_GID
|
|
_conf_login.GID_MAX = _conf_adduser.LAST_GID
|
|
}
|
|
} else if err != nil {
|
|
return err
|
|
|
|
} else if found, err = exist(_CONF_LIBUSER); found { // Based in Red Hat.
|
|
cfg, err := shconf.ParseFile(_CONF_LIBUSER)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_conf_libuser := &conf_libuser{}
|
|
if err = cfg.Unmarshal(_conf_libuser); err != nil {
|
|
return err
|
|
}
|
|
if _DEBUG {
|
|
cmdutil.Println(_CONF_LIBUSER)
|
|
reflectutil.PrintStruct(_conf_libuser)
|
|
}
|
|
|
|
if _conf_libuser.login_defs != _CONF_LOGIN {
|
|
_conf_login.ENCRYPT_METHOD = _conf_libuser.crypt_style
|
|
_conf_login.SHA_CRYPT_MIN_ROUNDS = _conf_libuser.hash_rounds_min
|
|
_conf_login.SHA_CRYPT_MAX_ROUNDS = _conf_libuser.hash_rounds_max
|
|
}
|
|
} else if err != nil {
|
|
return err
|
|
|
|
} /*else if found, err = exist(_CONF_PASSWD); found {
|
|
cfg, err := shconf.ParseFile(_CONF_PASSWD)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_conf_passwd := &conf_passwd{}
|
|
if err = cfg.Unmarshal(_conf_passwd); err != nil {
|
|
return err
|
|
}
|
|
if _DEBUG {
|
|
cmdutil.Println(_CONF_PASSWD)
|
|
reflectutil.PrintStruct(_conf_passwd)
|
|
}
|
|
|
|
if _conf_passwd.CRYPT != "" {
|
|
_conf_login.ENCRYPT_METHOD = _conf_passwd.CRYPT
|
|
}
|
|
} else if err != nil {
|
|
return err
|
|
}*/
|
|
|
|
switch strings.ToUpper(_conf_login.ENCRYPT_METHOD) {
|
|
case "MD5":
|
|
c.crypter = crypt.New(crypt.MD5)
|
|
case "SHA256":
|
|
c.crypter = crypt.New(crypt.SHA256)
|
|
case "SHA512":
|
|
c.crypter = crypt.New(crypt.SHA512)
|
|
case "":
|
|
if c.crypter, err = lookupCrypter(); err != nil {
|
|
return err
|
|
}
|
|
default:
|
|
return fmt.Errorf("user: requested cryp function is unavailable: %s",
|
|
c.login.ENCRYPT_METHOD)
|
|
}
|
|
|
|
if _conf_login.SYS_UID_MIN == 0 || _conf_login.SYS_UID_MAX == 0 ||
|
|
_conf_login.SYS_GID_MIN == 0 || _conf_login.SYS_GID_MAX == 0 ||
|
|
_conf_login.UID_MIN == 0 || _conf_login.UID_MAX == 0 ||
|
|
_conf_login.GID_MIN == 0 || _conf_login.GID_MAX == 0 {
|
|
|
|
_conf_login.SYS_UID_MIN = 100
|
|
_conf_login.SYS_UID_MAX = 999
|
|
_conf_login.SYS_GID_MIN = 100
|
|
_conf_login.SYS_GID_MAX = 999
|
|
|
|
_conf_login.UID_MIN = 1000
|
|
_conf_login.UID_MAX = 29999
|
|
_conf_login.GID_MIN = 1000
|
|
_conf_login.GID_MAX = 29999
|
|
}
|
|
|
|
config.login = *_conf_login
|
|
return nil
|
|
}
|
|
|
|
// loadConfig loads user configuration.
|
|
// It has to be loaded before of edit some file.
|
|
func loadConfig() {
|
|
config.Do(func() {
|
|
//checkRoot()
|
|
if err := config.init(); err != nil {
|
|
panic(err)
|
|
}
|
|
})
|
|
}
|