Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 33 additions & 5 deletions accounts1/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,12 @@ type InterfaceConfig struct {
}

const (
dsettingsAppID = "org.deepin.dde.daemon"
dsettingsAccountName = "org.deepin.dde.daemon.account"
dsettingsIsTerminalLocked = "isTerminalLocked"
gsSchemaDdeControlCenter = "com.deepin.dde.control-center"
settingKeyAutoLoginVisable = "auto-login-visable"
dsettingsAppID = "org.deepin.dde.daemon"
dsettingsAccountName = "org.deepin.dde.daemon.account"
dsettingsIsTerminalLocked = "isTerminalLocked"
gsSchemaDdeControlCenter = "com.deepin.dde.control-center"
settingKeyAutoLoginVisable = "auto-login-visable"
keyPasswordEncryptionAlgorithm = "passwordEncryptionAlgorithm"
)

//go:generate dbusutil-gen -type Manager,User manager.go user.go
Expand Down Expand Up @@ -668,6 +669,23 @@ func (m *Manager) checkGroupCanChange(name string) bool {
return gid >= 1000
}

// 从 dconfig 获取 密码加密算法的配置
func (m *Manager) getDConfigPasswdEncryptionAlgorithm() (string, error) {
if m.dsAccount == nil {
return "", errors.New("get accounts dconfig failed")
}
algoVar, err := m.dsAccount.Value(0, keyPasswordEncryptionAlgorithm)
if err != nil {
return "", fmt.Errorf("get accounts dconfig passwordEncryptionAlgorithm failed, err: %v", err)
}

alg, ok := algoVar.Value().(string)
if !ok {
return "", errors.New("algoVar.Value() is not string type")
}
return alg, nil
}

func (m *Manager) initAccountDSettings() {
m.cfgManager = configManager.NewConfigManager(m.sysSigLoop.Conn())

Expand All @@ -692,6 +710,16 @@ func (m *Manager) initAccountDSettings() {
if data, ok := v.Value().(bool); ok {
m.IsTerminalLocked = data
}
users.PasswdAlgoDefault, _ = m.getDConfigPasswdEncryptionAlgorithm()
m.dsAccount.InitSignalExt(m.sysSigLoop, true)
m.dsAccount.ConnectValueChanged(func(key string) {
switch key {
case keyPasswordEncryptionAlgorithm:
users.PasswdAlgoDefault, _ = m.getDConfigPasswdEncryptionAlgorithm()
logger.Warning("password encrypt algo changed:", users.PasswdAlgoDefault)
}
})

}

const (
Expand Down
79 changes: 65 additions & 14 deletions accounts1/users/passwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,78 @@
#define ERROR_NULLPOINTER -1;
#define ERROR_NOERROR 0;

char *mkpasswd(const char *words) {
unsigned long seed[2];
char salt[] = "$6$........";
const char *const seedchars = "./0123456789ABCDEFGHIJKLMNOPQRST"
"UVWXYZabcdefghijklmnopqrstuvwxyz";
#ifndef CRYPT_GENSALT_OUTPUT_SIZE
#define CRYPT_GENSALT_OUTPUT_SIZE 192
#endif

typedef struct {
const char *name;
const char *prefix;
} PasswordAlgorithm;

static const PasswordAlgorithm SUPPORTED_ALGORITHMS[] = {
{"sm3", "$sm3$"},
{"yescrypt", "$y$"},
{"sha512", "$6$"},
{"sha256", "$5$"},
{NULL, NULL}
};

#define DEFAULT_ALGORITHM 0

static char *try_encrypt_password(const char *words, const char *prefix) {
char output[CRYPT_GENSALT_OUTPUT_SIZE];
char *setting;
char *password;

setting = crypt_gensalt_rn(prefix, 0, NULL, 0, output, sizeof(output));
if (setting == NULL || setting[0] == '*') {
return NULL;
}

password = crypt(words, setting);
if (password == NULL || password[0] == '*') {
return NULL;
}

return password;
}

char *mkpasswd_with_algo(const char *words, const char *algo) {
char *password;
int i;
const PasswordAlgorithm *selected_algo = NULL;

if (algo != NULL && algo[0] != '\0') {
for (i = 0; SUPPORTED_ALGORITHMS[i].name != NULL; i++) {
if (strcmp(algo, SUPPORTED_ALGORITHMS[i].name) == 0) {
selected_algo = &SUPPORTED_ALGORITHMS[i];
break;
}
}
}

// Generate a (not very) random seed. You should do it better than this...
seed[0] = time(NULL);
seed[1] = getpid() ^ (seed[0] >> 14 & 0x30000);
if (selected_algo == NULL) {
selected_algo = &SUPPORTED_ALGORITHMS[DEFAULT_ALGORITHM];
}

// Turn it into printable characters from `seedchars'.
for (i = 0; i < 8; i++) {
salt[3 + i] = seedchars[(seed[i / 5] >> (i % 5) * 6) & 0x3f];
password = try_encrypt_password(words, selected_algo->prefix);
if (password != NULL) {
return password;
}

// DES Encrypt
password = crypt(words, salt);
for (i = 0; SUPPORTED_ALGORITHMS[i].name != NULL; i++) {
if (&SUPPORTED_ALGORITHMS[i] == selected_algo) {
continue;
}

return password;
password = try_encrypt_password(words, SUPPORTED_ALGORITHMS[i].prefix);
if (password != NULL) {
return password;
}
}

return NULL;
}

int lock_shadow_file() {
Expand Down
16 changes: 15 additions & 1 deletion accounts1/users/passwd.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,25 @@ var (
wLocker sync.Mutex
)

var PasswdAlgoDefault = "sm3"

func EncodePasswd(words string) string {
return CryptUserPassword(words, PasswdAlgoDefault)
Comment on lines +35 to +38
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Global PasswdAlgoDefault can be written and read concurrently, causing a data race

This variable is updated from the DConfig signal callback in manager.go and read from EncodePasswd without any synchronization. Please protect it with a mutex, use atomic.Value, or funnel updates through a single owning goroutine so all reads are race-free and see a consistent value.

}

func CryptUserPassword(words string, algo string) string {
cwords := C.CString(words)
defer C.free(unsafe.Pointer(cwords))

return C.GoString(C.mkpasswd(cwords))
calgo := C.CString(algo)
defer C.free(unsafe.Pointer(calgo))

result := C.mkpasswd_with_algo(cwords, calgo)
if result == nil {
return ""
}

return C.GoString(result)
}

func ExistPwUid(uid uint32) int {
Expand Down
7 changes: 6 additions & 1 deletion accounts1/users/passwd.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
#ifndef __PASSWORD_H__
#define __PASSWORD_H__

char *mkpasswd(const char *words);
#define PASSWD_ALGO_SHA512 "sha512"
#define PASSWD_ALGO_SHA256 "sha256"
#define PASSWD_ALGO_YESCRYPT "yescrypt"
#define PASSWD_ALGO_SM3 "sm3"

char *mkpasswd_with_algo(const char *words, const char *algo);

int lock_shadow_file();
int unlock_shadow_file();
Expand Down
10 changes: 10 additions & 0 deletions misc/dsg-configs/org.deepin.dde.daemon.account.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@
"description": "Whether to allow local unlocking of the terminal",
"permissions": "readwrite",
"visibility": "private"
},
"passwordEncryptionAlgorithm": {
"value": "sm3",
"serial": 0,
"flags": ["global"],
"name": "passwordEncryptionAlgorithm",
"name[zh_CN]": "密码加密算法",
"description": "Password encryption algorithm (sha512, sha256, yescrypt, sm3(default))",
"permissions": "readonly",
"visibility": "private"
}
}
}