Skip to content

fix: revert SetPassword disable, restore with admin auth#1125

Merged
caixr23 merged 1 commit into
linuxdeepin:masterfrom
caixr23:master
May 25, 2026
Merged

fix: revert SetPassword disable, restore with admin auth#1125
caixr23 merged 1 commit into
linuxdeepin:masterfrom
caixr23:master

Conversation

@caixr23
Copy link
Copy Markdown
Contributor

@caixr23 caixr23 commented May 25, 2026

  1. Restore SetPassword DBus method implementation, as it is used by dde-control-center when creating new users
  2. Require polkitActionUserAdministration authentication to prevent unauthorized password changes
  3. Keep the chpasswd injection guard in ModifyPasswd

Log: SetPassword DBus method is restored for new user creation

Influence:

  1. creating a new user via control center should set password successfully
  2. non-admin user calling SetPassword should still be denied

PMS: TASK-390039

fix: 恢复 SetPassword 接口,保留管理员鉴权

  1. 恢复 SetPassword DBus 方法实现,因为控制中心创建新用户 时需要调用该接口
  2. 要求 polkitActionUserAdministration 鉴权,防止未授权 修改密码
  3. 保留 ModifyPasswd 中的 chpasswd 注入防护

Log: SetPassword DBus 方法已恢复,用于新用户创建场景

Influence:

  1. 通过控制中心创建新用户时应能成功设置密码
  2. 非管理员用户调用 SetPassword 仍应被拒绝

1. Restore SetPassword DBus method implementation, as it is
   used by dde-control-center when creating new users
2. Require polkitActionUserAdministration authentication to
   prevent unauthorized password changes
3. Keep the chpasswd injection guard in ModifyPasswd

Log: SetPassword DBus method is restored for new user creation

Influence:
1. creating a new user via control center should set password
   successfully
2. non-admin user calling SetPassword should still be denied

PMS: TASK-390039

fix: 恢复 SetPassword 接口,保留管理员鉴权

1. 恢复 SetPassword DBus 方法实现,因为控制中心创建新用户
   时需要调用该接口
2. 要求 polkitActionUserAdministration 鉴权,防止未授权
   修改密码
3. 保留 ModifyPasswd 中的 chpasswd 注入防护

Log: SetPassword DBus 方法已恢复,用于新用户创建场景

Influence:
1. 通过控制中心创建新用户时应能成功设置密码
2. 非管理员用户调用 SetPassword 仍应被拒绝
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Sorry @caixr23, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

你好!我是CodeGeeX。我已仔细审查了你提供的Git Diff代码。这段代码实现了一个 SetPassword 方法,包含权限校验、循环等待影子文件就绪、修改密码、清理密钥环以及解锁用户等功能。

整体来看,代码逻辑基本完整,但在语法逻辑、代码质量、代码性能和代码安全方面存在一些需要改进的隐患。以下是详细的审查意见和改进建议:

1. 语法与逻辑

  • 空密码逻辑存在歧义与安全风险
    if password == "" {
        return nil
    }
    当传入空密码时,直接返回 nil(表示成功),但实际上并没有执行任何修改密码的操作。这会导致调用方认为密码修改成功,而用户密码并未改变。如果意图是“清空密码”,应该调用相应的系统命令;如果空密码是不合法的,应该返回错误。在安全实践中,强烈建议禁止设置空密码
  • 循环中的错误返回值可能为nil
    _, err := users.GetShadowInfo(u.UserName)
    // ...
    if count == 0 {
        return dbusutil.ToError(err)
    }
    如果循环了10次仍然失败,此时返回 err。但在极端情况下,如果最后一次循环恰好 err == nil(虽然逻辑上如果==nil会break,但代码结构上存在隐患),或者 err 被覆盖,可能会返回 nil。更清晰的做法是返回一个明确的超时错误。

2. 代码性能

  • 固定时间的 time.Sleep 阻塞
    for {
        // ...
        time.Sleep(time.Second)
    }
    使用 time.Sleep(time.Second) 进行轮询,最差情况下会阻塞当前 goroutine 长达 10 秒。在 D-Bus 服务中,长时间的阻塞会严重影响服务的并发处理能力。
    建议:使用指数退避或更短的重试间隔,或者基于事件/文件的监听机制。如果必须轮询,建议将间隔缩短至 100~200 毫秒。

3. 代码安全

  • 密码明文传输与日志泄露风险
    password string 作为参数传入,在内存中是明文。虽然代码中没有直接打印 password,但在后续调用 users.ModifyPasswd(password, u.UserName) 时,如果底层实现是调用 passwdchpasswd 命令行工具,极易通过命令行参数(如 ps -ef)或 /proc/pid/cmdline 泄露密码。建议确认底层实现是否安全(如使用 PAM API 或写入管道)。
  • 允许空密码/弱密码
    如前所述,直接放行 password == "" 是非常不安全的,这可能导致系统无密码登录。
  • 权限校验后的状态竞争
    在通过 checkAuth 校验后,到真正执行 ModifyPasswd 之间,存在时间差,可能存在TOCTOU(检查时间到使用时间)问题,但在当前上下文中属于常见做法,只需注意即可。

4. 代码质量

  • 魔法数字
    var count = 10 是一个魔法数字,建议定义为常量,并增加注释说明为什么重试10次、为什么等待这些时间。
  • 错误处理不一致
    removeLoginKeyring(u) 失败时仅打印日志,不阻断流程,这是合理的。但 ModifyPasswd 失败后直接返回了,没有清理可能产生的中间状态。
  • 日志格式不统一
    有时用 [SetPassword],有时用 DoAction:,建议统一日志前缀,方便排查问题。

改进后的代码建议

const (
    maxShadowRetries     = 10
    shadowRetryInterval  = 200 * time.Millisecond
)

func (u *User) SetPassword(sender dbus.Sender, password string) *dbus.Error {
	logger.Debug("[SetPassword] start ...")

	// 安全建议:禁止设置空密码,而非静默忽略
	if password == "" {
		return dbusutil.ToError(fmt.Errorf("setting an empty password is not allowed"))
	}

	err := u.checkAuth(sender, false, polkitActionUserAdministration)
	if err != nil {
		logger.Debug("[SetPassword] access denied:", err)
		return dbusutil.ToError(err)
	}

	// 等待影子文件就绪,使用更短的重试间隔避免长时间阻塞
	for i := 0; i < maxShadowRetries; i++ {
		_, err := users.GetShadowInfo(u.UserName)
		if err == nil {
			break
		}
		
		if i == maxShadowRetries-1 {
			// 明确返回超时/未就绪错误,避免返回可能为nil的err
			logger.Warning("[SetPassword] shadow info not ready after retries:", err)
			return dbusutil.ToError(fmt.Errorf("shadow info for user %s is not ready: %v", u.UserName, err))
		}
		
		time.Sleep(shadowRetryInterval)
	}

	// 注意:请确保 ModifyPasswd 底层实现不会将密码暴露在命令行参数中(如通过管道传递给 chpasswd)
	if err := users.ModifyPasswd(password, u.UserName); err != nil {
		logger.Warning("[SetPassword] modify password failed:", err)
		return dbusutil.ToError(err)
	}

	// 密码修改成功后,清理 keyring,即使失败也不影响主流程
	err = removeLoginKeyring(u)
	if err != nil {
		logger.Warningf("[SetPassword] remove login keyring failed: %v", err)
	}

	u.PropsMu.Lock()
	defer u.PropsMu.Unlock()

	if u.Locked {
		if err := users.LockedUser(false, u.UserName); err != nil {
			logger.Warning("[SetPassword] unlock user failed:", err)
			return dbusutil.ToError(err)
		}
		u.Locked = false
		_ = u.emitPropChangedLocked(false)
	}
	
	logger.Debug("[SetPassword] success for user:", u.UserName)
	return nil
}

主要改进点总结:

  1. 修复了空密码的逻辑漏洞:将 return nil 改为返回错误,防止产生无密码用户。
  2. 优化了轮询性能:将重试间隔从 1秒 缩短至 200毫秒,最大阻塞时间从 10秒 降至 2秒,显著提升 D-Bus 服务响应性。
  3. 消除了魔法数字:提取为常量 maxShadowRetriesshadowRetryInterval
  4. 修复了循环超时时的错误返回逻辑:确保超时时报错清晰且不会返回 nil
  5. 统一了日志前缀:将 DoAction: 统一替换为 [SetPassword],便于日志检索和追踪。

Comment thread accounts1/user_ifc.go
return nil
}

err := u.checkAuth(sender, false, polkitActionUserAdministration)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: caixr23, fly602

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@caixr23 caixr23 merged commit b3297a3 into linuxdeepin:master May 25, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants