问题排查定位记录:DDE 登录界面无密码输入框

现场故障排查记录。

本文主要介绍一次解决客户端现场反馈问题的过程,主要是觉得中间一直定位、分锅,最后发现不是自家产品的锅,反而最后把锅甩到系统本身那,觉得挺有意思的。

背景

就简单的介绍一下事情的背景吧。自家的产品是一款终端安全登录产品,功能的话大概就是:

  • 我们都知道电脑在开机或锁屏后想要进入桌面需要输入密码;

  • 我们的产品就是在此基础上,加一把KEY(类似 U 盘的东西),在进入桌面事需要输入KEY的密码,使用过程中一旦把 KEY 拔出去就会自动锁屏。

但是,这款产品到我手时已经是开发完毕(代码和功能我是一点没参与),所以我只是一个有源码的维护人员。

问题描述

客户在 UOS20 上安装了我们的终端程序,之前一直是正常使用的。最近客户端因为系统安全问题需要对UOS20系统进行升级到UOS 20 1060。升级完毕之后开机欢迎界面没有密码输入框,也就无法输入密码。现场一时间还是比较紧急的,要么系统不升级但会有安全问题,要么升级但升级后又进不去。

由于中间只进行了系统升级的操作,所以现场怀疑是我们的产品没对针对最新的UOS20系统进行适配导致的,要求排查一下进行适配。

故障定位

收到现场问题后,虽说是现场故障优先级应该要提高,但是由于现场又说只是在一两台测试PC上进行的提前实验防止大面积出现什么未知问题(这不就有问题了嘛)。所以,按照一般的步骤收集一下现场信息:

  • 现场终端产品的版本号 (XXXX)

  • 操作系统版本号,CPU 架构 (UOS20 1040 升级到 UOS20 1060,CPU:飞腾arm64)

但是家里没有arm64的机器,所以我就在下了UOS 20 amd64的镜像在本地复现一把,因为看现场这样子桌面进不去也不好远程(tty也麻烦)。

一装还真复现了,那就好办了,能复现就不是问题(啥都不怕就怕那种诡异的偶现问题)。

然后瞎几把尝试,先点击右下角的关机图标,然后再点击屏幕任意地方,诶,然后输入框就出现了。

很显然,感觉是UOS20这个窗口初始化时输入框控件没有激活。But,当我卸载我们的产品后重启发现,欸问题又没有了,这…这下怕是脱不了干系了

我想着,既然又个临时了方案能规避,就先反馈给现场吧,免得真耽误人家正常使用了。

但是呢,客户又要求要定位具体原因,给个交代啥的,不然就反馈啥啥的…..

于是,只能继续在家里复现研究了,把锅找出来。

首先,先看看产品的进程正常运行否(应该是正常的,不然咋影响)。

ps -ef |grep xxx

收集日志:

  • /var/log/xxx/

  • /var/log/message

  • /var/log/auth.log

查看代码,找到与锁屏相关的模块:

  • PAM Linux下身份鉴别模块

  • dde-lock 是UOS20的锁屏程序

相关的配置文件:

  • /etc/pam.d/deepin_pam_unix

  • /etc/pam.d/common-auth

很快就能定位到大概是产品中的pam模块和dde-lock之前出了问题,可能是pam那个地方卡死了或者咋咋了。

所以,先修改一下pam的配置文件,把我们的模块注释掉:

1
2
3
4
# here are the per-package modules (the "Primary" block)
#auth [success=done auth_err=die ignore=ignore default=bad] pam_example.so
auth    [success=2 auth_err=done new_authtok_reqd=ok ignore=ignore default=die]                             pam_deepin_authentication.so user_locale=.config/locale.conf timeout=-1
auth    [success=1 default=ignore]                                                         pam_unix.so  nullok_secure try_first_pass

然后重启发现,好像还真是好了,那看来确实是xx_pam.so 出现问题了。

翻看源码,debug,不断注释代码发现,似乎代码没毛病(把逻辑代码都注释完了)。那莫非真不是俺们的问题?

于是让ChatGPT写一段pam的example代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// gen by chatgpt.
#include <security/pam_modules.h>
#include <security/pam_ext.h>
#include <string.h>
#include <stdio.h>
// PAM模块入口函数,实现用户认证功能
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    const char *username = NULL;
    const char *password = NULL;
    int retval;

    // 获取用户名和密码
    retval = pam_get_user(pamh, &username, "Username: ");
    if (retval != PAM_SUCCESS) {
        return retval;
    }

    retval = pam_get_authtok(pamh, PAM_AUTHTOK, &password, "Password: ");
    if (retval != PAM_SUCCESS || password == NULL) {
        return retval;
    }

    // 进行身份验证
    if (strcmp(password, "123abc") != 0) {
    printf("[Ohh Demo] password incorrect....");
        return PAM_AUTH_ERR;
    }

    return PAM_SUCCESS;
}

这里提一下UOS的文档:

身份鉴别系统如何接入UOS的PAM框架 - deepin开发者平台

然后编译,修改配置文件启用我们的example_pam.so模块,重启。

编译

1
gcc -fPIC -fno-stack-protector -shared -o pam_example.so pam_example.c

运行

1
sudo cp pam_example.so /lib/x86_64-linux-gnu/security/

编辑pam配置文件

sudo vim  /etc/pam.d/deepin_pam_unix

1
2
3
4
5
# /etc/pam.d/deepin_pam_unix
# here are the per-package modules (the "Primary" block)
auth    [success=done default=bad ignore=ignore auth_err=die] pam_example.so
auth    [success=2 default=ignore]      pam_unix.so nullok_secure try_first_pass
auth    [success=1 default=ignore]      pam_udcp.so try_first_pass

或者 sudo vim /etc/pam.d/common-auth

1
2
3
4
# here are the per-package modules (the "Primary" block)
auth [success=done auth_err=die ignore=ignore default=bad] pam_example.so
auth    [success=2 auth_err=done new_authtok_reqd=ok ignore=ignore default=die]                             pam_deepin_authentication.so user_locale=.config/locale.conf timeout=-1
auth    [success=1 default=ignore]                                                         pam_unix.so  nullok_secure try_first_pass

还真是复现,那我现在可以说和我们的产品没有关系吗…..这样好像不好交差啊。

那只好看看UOS20是怎能加载pam模块的了。

首先,UOS 20 是 Debian 系的 Linux 系统,所以PAM+Debain,PAM+Ubuntu都能搜索到一些信息。

  • PAM :Pluggable Authentication Modules 可插拔认证模块

  • pam模块的配置文件一般在:/etc/pam.d/xxx-auth

  • 动态库文件在:/lib/security 或 /lib64/security

  • 相关进程:

    • lightdm :独立于不同桌面环境的登录管理器

      1
      2
      3
      4
      5
      6
      
      # 停止lightdm服务
      sudo systemctl stop lightdm.service
      # 查看lightdm相关的进程是否停止,如果没有请重新尝试stop lightdm.service
      ps -ef |grep lightdm
      # 重启lightdm服务
      sudo systemctl stop lightdm.service
      
    • dde-lock : UOS/deepin的锁屏界面程序

    • dde-ssesion-shell:该项目提供deepin/uos的锁屏界面、登录界面、关机界面、桌面低栏、控制中心等界面程序

    • lightdm-deepin-greeter

重启lightdm.service便会重启dde-lock。

于是,下载了dde-session-shell的源码看了一下,确实在其中发现一下认证的类型:

  • AT_None

  • AT_Password

  • AT_PAM

  • ….

估计问题是出在这个组件的。那只好编译调试一下这几个组件了。这个过程就略过吧。

跟踪一下日志和结合源码比对,发现问题的原因可能在于src\lightdm-deepin-greeter\greeterworker.cpp#line276~293, 于是我便尝试如下修改(也许并不正确),经过编译安装后便能正确的显示密码框了:

原来是这个else啥也不干导致的呀?

解决方案

方法一: 点击右下角电源键之后,点击屏幕任意位置

方法二: 降级dde-session-shell,目前无问题,但我无法确定降级是否存在其他问题.

最后,我发邮件给UOS的人员请求修复一下,在等了一两天后得到的回复是:

然后隔天就看到公众号

至此,终于可以给客户一个交代了。

总结

通过这次现场故障的排查,顺便不仅熟悉了一下Linux PAM认证的机制,还顺带厘清了一下UOS20桌面环境下的一些进程关系。

  • dde-lock

  • dde-session-ui

  • dde-shell

  • dde-greater

  • lightdm

还好不是俺的锅。

哦吼是一首歌。
Built with Hugo
Theme Stack designed by Jimmy