当前位置: 首页 > news >正文

网站主体负责人查询球场 技术支持 东莞网站建设

网站主体负责人查询,球场 技术支持 东莞网站建设,无极城市在线招聘,seo诊断方案问题由来 客户需求计划列入支持第三方帐号系统#xff0c;包括Web账号。需求来源是用户想要用它们的帐号直接登录Linux Deepin操作系统。一个失败的实现方案是用户以较小的成本改造帐号管理系统发布HTTP服务#xff0c;我们开发一个PAM模块与Web服务器交互#xff0c;数据格…问题由来 客户需求计划列入支持第三方帐号系统包括Web账号。需求来源是用户想要用它们的帐号直接登录Linux Deepin操作系统。一个失败的实现方案是用户以较小的成本改造帐号管理系统发布HTTP服务我们开发一个PAM模块与Web服务器交互数据格式化采用JSON。结果遇到su提示帐号不存在的问题。在Linux Deepin系统登录界面、通过技术手段进入桌面后发现锁屏界面无法解锁等诸多问题。通过程序验证和su源代码分析验证此方案最大的局限性是su在识别到用户的信息之前不会执行PAM模块。此方案只能用程序调用pam_authenticate触发PAM模块的执行。 Linux Name Service Switch Linux NSS (Name Service Switch) 是一种在 Linux 系统中实现域名解析用户认证和授权等功能的模块化系统。它提供了一种灵活的方式来配置系统如何查找用户组密码和其他网络资源的信息。 NSS 的核心概念是所谓的 “Switch”这是一组可插入的模块它们根据一定的顺序来处理不同类型的请求。用户可以通过编辑 /etc/nsswitch.conf 文件来配置这些模块的加载顺序以达到满足自己特定需求的目的。例如您可以通过 NSS 配置更改系统的验证源以便使用 LDAP 或 Kerberos 等网络身份验证服务而不是使用本地 /etc/passwd 文件。 Linux NSS 可以支持多种不同的数据源包括本地文件、NIS、LDAP、Kerberos 等。这些模块还可以针对特定服务或应用程序进行定制化以实现更高效的查询和更安全的身份验证和授权。使用 Linux NSS系统管理员可以更灵活地管理 Linux 系统满足不同用户对系统资源和服务的需求。 本文将详细讲解开发过程实现Web账号登录Linux桌面系统。 关于getpwnam函数 NSS的作用是识别身份信息。传统的用户名和密码验证方式身份信息是一个字符串。NSS通过调用这个方法寻找这个字符串对应到系统中的用户获取它关联的UID和GID从而对它进行管理。Oracle官方文档原话 The name service switch is a file named nsswitch.conf. It controls how a client machine or application obtains network information. It is used by client applications that call any of the getXbyY() interfaces such as the following.gethostbyname() getpwuid() getpwnam() getipnodebyname()getpwnam不是直接读取读取/etc/passwd或者/etc/shadow文本文件它取决于nsswitch.conf中passwd这一行的配置。对于Linux Deepin操作系统如果配置了files或者compat那么最终由libnss_files-2.28.so或者libnss_compat-2.28.so读取这几个配置文件程序从getpwnam运行到了_nss_files_getpwnam_r或者_nss_compat_getpwnam_r。 NSS释义 这里的NSS指的是Linux Name Service Switch不是Linux Network Security Service。两者对Linux都很重要资料都很稀缺。我们可以理解为名字解析服务它实现把外部输入的用户信息与系统中的用户信息关联。它按照/etc/nsswitch.conf指定的顺序逐个模块调用如果找到了就立即返回libcsu根据返回的用户信息启动PAM流程进行身份验证。 nsswitch配置文件格式 一行写一种类型的配置每行以类型名称加冒开头以NSS模块名称列表结尾多个NSS模块名称以空格隔开。NSS总共支持16种类型的配置。常见的有passwd、group、shadow、gshadow、hosts、networks、protocols、rpc、netgroup等等。其中passwd类别实现用户身份识别。模块与类别不是一对一的关系libc给每个类型别都定义了一套接口这个接口函数名通常以_r结尾比如getpwuid_r。NSS模块的实现是动态链接库文件名必须以libnss_为前缀以.so或.so.2为后缀中间部分就是模块名称比如libnss_mjaw.so它的模块名称就是mjaw。因它实现了passwd、group、shadow、gshadow、hosts、networks、rpc、protocols这些类别的接口所以配置文件中这些类型对应的行都可以加上mjaw这个模块名称。 开发 引用Petzold Charles先生的一句名言 Do not call me, I will call you 。NSS程序设计须深刻理解这句话下面的每一个函数都不是开发者要调用的函数而是系统用户态边界一定会调用你的函数。 NSS模块要求开发者采用C语言Qt代码无法在PAM和NSS模块的上下文环境中运行。在PAM和NSS模块编程中采用C与C混合编程的方式对于Qt来说有很多问题需要解决其它的框架暂未尝试。对于HTTP可以用cURL。对于Json解析可采用cJSON对于密码加密可采用mHash。 认证数据的存储 NSS模块须自行管理认证数据。因此首先建立一个链表. 重要的头文件 #include passwd_list.h #include malloc.h #include pwd.h #include string.h#include cjson/cJSON.h #include mhash.h #include curl/curl.h创建链表 MJAW_INTERNAL pmjaw_passwd_list_t passwd_create() {pmjaw_passwd_list_t node (pmjaw_passwd_list_t)calloc(sizeof(mjaw_passwd_list_t), 1);return node; }创建认证账号 MJAW_INTERNAL passwd_t passwd_create2() {passwd_t pwd (passwd_t)calloc(sizeof(struct passwd), 1);pwd-pw_name (char *)calloc(UINT8_MAX, 1);pwd-pw_gecos (char *)calloc(UINT8_MAX, 1);pwd-pw_shell (char *)calloc(UINT8_MAX, 1);pwd-pw_dir (char *)calloc(UINT8_MAX, 1);pwd-pw_passwd (char *)calloc(UINT8_MAX, 1); }释放链表 MJAW_INTERNAL void passwd_free(pmjaw_passwd_list_t head) {pmjaw_passwd_list_t each head-next;while (each) {pmjaw_passwd_list_t del each;each each-next;passwd_free2(del-data);free(del);}free(head); }释放认证账号 MJAW_INTERNAL void passwd_free2(passwd_t data) {free(data-pw_name);free(data-pw_gecos);free(data-pw_shell);free(data-pw_dir);free(data-pw_passwd);free(data); } 获取指定索引位置的用户对象 /*** brief 获取指定索引位置的用户对象** param head* param nindex* return MJAW_INTERNAL*/ MJAW_INTERNAL passwd_t passwd_at(pmjaw_passwd_list_t head, int nindex) {if (nindex passwd_size(head)) {return NULL;}pmjaw_passwd_list_t each head-next;int neach 0;while (each neach nindex) {each each-next;neach;}return each-data; }根据用户名查找用户对象 /*** brief 根据用户名查找用户对象** param head* param username* return MJAW_INTERNAL*/ MJAW_INTERNAL passwd_t passwd_find_id_by_username(pmjaw_passwd_list_t head, const char *username) {pmjaw_passwd_list_t find head-next;while (find) {if (strcmp(find-data-pw_name, username) 0) {return find-data;}}return NULL; }根据用户ID查找用户对象 /*** brief 根据用户ID查找用户对象** param head* param uid* return MJAW_INTERNAL*/ MJAW_INTERNAL passwd_t passwd_find_username_by_id(pmjaw_passwd_list_t head, uint32_t uid) {pmjaw_passwd_list_t find head-next;while (find) {if (find-data-pw_uid uid) {return find-data;}}return NULL; } 获取指定用户ID的索引 /*** brief 获取指定用户ID的索引** param head* param uid* return MJAW_INTERNAL*/ MJAW_INTERNAL int passwd_indexof(pmjaw_passwd_list_t head, uint32_t uid) {pmjaw_passwd_list_t each head-next;int nindex 0;int bfind 0;while (each) {if (each-data-pw_uid uid) {bfind 1;break;}nindex;}if (bfind) {return nindex;}return -1; }在队列末尾增加一个用户对象 /*** brief 在队列末尾一个用户对象** param head* param data* return MJAW_INTERNAL*/ MJAW_INTERNAL void passwd_append(pmjaw_passwd_list_t head, passwd_t data) {// mjaw_log0(__FILE__, __LINE__, __func__, enter);pmjaw_passwd_list_t end head;while (end-next) {end end-next;}pmjaw_passwd_list_t node passwd_create();node-data passwd_create2();node-data-pw_uid data-pw_uid;node-data-pw_gid data-pw_gid;strncpy(node-data-pw_name, data-pw_name, UINT8_MAX);strncpy(node-data-pw_gecos, data-pw_gecos, UINT8_MAX);strncpy(node-data-pw_shell, data-pw_shell, UINT8_MAX);strncpy(node-data-pw_dir, data-pw_dir, UINT8_MAX);strncpy(node-data-pw_passwd, data-pw_passwd, UINT8_MAX);node-previous end;end-next node;// mjaw_log0(__FILE__, __LINE__, __func__, leave); } 移除指定索引位置的用户对象 /*** brief 移除指定索引位置的用户对象** param head* param nindex* return MJAW_INTERNAL*/ MJAW_INTERNAL void passwd_remove(pmjaw_passwd_list_t head, int nindex) {if (nindex passwd_size(head)) {return;}pmjaw_passwd_list_t remove head-next;int neach 0;while (remove neach nindex) {remove remove-next;neach;}remove-next-previous remove-previous;remove-previous-next remove-next;passwd_free2(remove-data);free(remove); } 获取队列大小 /*** brief 获取队列大小HEAD本身不参与计算** param head* return MJAW_INTERNAL*/ MJAW_INTERNAL uint32_t passwd_size(pmjaw_passwd_list_t head) {uint32_t nsize 0;while (head head-next) {nsize;}return nsize; } 账号克隆 /*** brief 用户信息复制** param from* param to* return MJAW_INTERNAL*/ MJAW_INTERNAL void passwd_copy(const passwd_t from, passwd_t to) {memset(to, 0, sizeof(struct passwd));to-pw_name (char *)calloc(UINT8_MAX, 1);to-pw_gecos (char *)calloc(UINT8_MAX, 1);to-pw_shell (char *)calloc(UINT8_MAX, 1);to-pw_dir (char *)calloc(UINT8_MAX, 1);to-pw_passwd (char *)calloc(UINT8_MAX, 1);to-pw_name from-pw_name;to-pw_passwd from-pw_passwd;to-pw_uid from-pw_uid;to-pw_gid from-pw_gid;to-pw_gecos from-pw_gecos;to-pw_dir from-pw_dir;to-pw_shell from-pw_shell;strncpy(to-pw_name, from-pw_name, UINT8_MAX);strncpy(to-pw_gecos, from-pw_gecos, UINT8_MAX);strncpy(to-pw_shell, from-pw_shell, UINT8_MAX);strncpy(to-pw_dir, from-pw_dir, UINT8_MAX);strncpy(to-pw_passwd, from-pw_passwd, UINT8_MAX); }Web互通 Web账号登录Linux桌面的通讯环节假定存在一个RESTful服务http://127.0.0.1:1081提供json数据接口。 cURL发起请求 兼顾处理网络错误。 /*** brief curl回调收集数据** param buffer* param size* param nmemb* param user_p* return size_t*/ static size_t mjaw_curl_login_data(void *buffer, size_t size, size_t nmemb, void *user_p) {char *wrapper (char *)user_p;// mjaw_logv(__FILE__, __LINE__, __func__, buffer size: %d, size: %d, nmemb: %d, strlen((char *)buffer), size, nmemb);strncat(wrapper, buffer, nmemb);return nmemb; }static bool network_has_error(cJSON **httpContent) {//执行网络请求查询所有用户char buffer[UINT16_MAX] {0};CURL *pcurl curl_easy_init();curl_easy_setopt(pcurl, CURLOPT_URL, http://127.0.0.1:1081/users);curl_easy_setopt(pcurl, CURLOPT_TIMEOUT, 3);curl_easy_setopt(pcurl, CURLOPT_WRITEFUNCTION, mjaw_curl_login_data);curl_easy_setopt(pcurl, CURLOPT_WRITEDATA, buffer);CURLcode icode curl_easy_perform(pcurl);//如果网络请求失败if (icode ! CURLE_OK) {mjaw_log1i(__FILE__, __LINE__, __func__, nss_cw can not access website. curl error code: %d., icode);return true;}//把HTTP返回转换成json对象cJSON *res cJSON_Parse(buffer);//json对象必须是数组if (!cJSON_IsArray(res)) {// mjaw_logv(__FILE__, __LINE__, __func__, parse http response error: %s, buffer);cJSON_Delete(res);return true;}*httpContent res;return false; }cJSON库解析账号信息 /*** brief 从指定的配置读取Web服务器上的用户列表并保存到列表** param head* return MJAW_INTERNAL*/ MJAW_INTERNAL void passwd_init(pmjaw_passwd_list_t head) {cJSON *res NULL;if (network_has_error(res)) {return;}int iSize cJSON_GetArraySize(res);for (int i 0; i iSize; i) {cJSON *obj cJSON_GetArrayItem(res, i);bool badmin cJSON_IsTrue(cJSON_GetObjectItem(obj, admin));passwd_t data passwd_create2();data-pw_uid (uint32_t)cJSON_GetObjectItem(obj, uid)-valueint;if (badmin) {data-pw_gid 0;} else {data-pw_gid data-pw_uid;}strncpy(data-pw_name, cJSON_GetObjectItem(obj, username)-valuestring, UINT8_MAX);// strcpy(data-pw_shell, /bin/bash);strcpy(data-pw_dir, /home/http/);strncat(data-pw_dir, data-pw_name, UINT8_MAX);strncpy(data-pw_gecos, data-pw_name, UINT8_MAX);//这里是约定strcpy(data-pw_passwd, !);passwd_append(head, data);}cJSON_Delete(res); } NSS核心身份识别 NSS的概念可以推广开来应用到人脸、指纹等生物特征识别。 重要的头文件 #ifdef __cplusplus #include iostream #include string #else #include stdio.h #include string.h #endif//c run time #include stdint.h #include stdlib.h #include malloc.h #include time.h #include stdarg.h//linux #include unistd.h #include nss.h #include grp.h #include pwd.h #include dlfcn.h #include sys/time.h #include sys/types.h #include syslog.h//external reference #include cjson/cJSON.h #include mhash.h #include curl/curl.h#include nss_passwd.h #include common.h 下文以NSS接口名称为标题举例说明NSS接口的实现过程。 getpwnam //all over record static int i_record_index 0; static pmjaw_passwd_list_t head_passwd NULL;static enum nss_status local_getpwnam_r(const char *name, struct passwd *result, char *buffer, size_t buflen, int *errop) {// dlopen(/usr/lib/%s-linux-gnu/libnss_files.so.2,)return NSS_STATUS_SUCCESS; }/*** brief 解析用户对象给用户赋权** param name* param result* param buffer* param buflen* param errop* return MJAW_EXPORT*/ MJAW_EXPORT nss_status _nss_mjaw_getpwnam_r(const char *name, struct passwd *result, char *buffer, size_t buflen, int *errop) {mjaw_log0(__FILE__, __LINE__, __func__, enter);if (!head_passwd) {head_passwd passwd_create();passwd_init(head_passwd);}//打开系统日志// openlog(nss_cw, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);//buffer重置为空memset(buffer, 0, buflen);//result结构体本身的内存由调用者传入if (!result) {mjaw_log0(__FILE__, __LINE__, __func__, result can not be empty.);return NSS_STATUS_NOTFOUND;}//输出开始处理的日志mjaw_logv(__FILE__, __LINE__, __func__, begin receive name: %s, uid: %d, gid: %d, name, result-pw_uid, result-pw_gid);//获取web对用户id和组id的定义passwd_t user passwd_find_id_by_username(head_passwd, name);if (user NULL) {passwd_free(head_passwd);return NSS_STATUS_NOTFOUND;}passwd_copy(user, result);//输出完成处理的日志mjaw_logv(__FILE__, __LINE__, __func__, end : %s, uid: %d, gid: %d, name, result-pw_uid, result-pw_gid);//按约定返回0非零被su判定用户不存在*errop 0;passwd_free(head_passwd);//关闭系统日志// closelog();return NSS_STATUS_SUCCESS; } setpwent 这个接口的含义是系统通知NSS模块清理内存并准备一个新的账号列表。此时是Linux Deepin本地同步远端Web账号的机会。 /*** brief init data list cache** return MJAW_EXPORT*/ MJAW_EXPORT nss_status _nss_mjaw_setpwent() {mjaw_log0(__FILE__, __LINE__, __func__, enter);if (!head_passwd || !passwd_size(head_passwd)) {head_passwd passwd_create();passwd_init(head_passwd);}mjaw_logv(__FILE__, __LINE__, __func__, data size: %d, passwd_size(head_passwd));i_record_index 0;return NSS_STATUS_SUCCESS; }MJAW_EXPORT nss_status _nss_mjaw_init() {mjaw_log0(__FILE__, __LINE__, __func__, end);return NSS_STATUS_SUCCESS; }endpwent 这个接口的含义是系统通知NSS模块清理内存结束了。 /*** brief clean data list cache** return MJAW_EXPORT*/ MJAW_EXPORT nss_status _nss_mjaw_endpwent() {mjaw_log0(__FILE__, __LINE__, __func__, enter);if (head_passwd passwd_size(head_passwd) 0)passwd_free(head_passwd);return NSS_STATUS_SUCCESS; }### getpwent 这个接口一般紧接着setpwent调用用于获取账号的详细信息。此接口返回NSS_NOT_FOUND后系统会立即调用endpwent接口。 /*** brief iterator data list** param __resultbuf* return MJAW_EXPORT*/ MJAW_EXPORT nss_status _nss_mjaw_getpwent_r(struct passwd *resultbuf, char *buffer, size_t buflen, int *errop) {if (!head_passwd)return NSS_STATUS_NOTFOUND;// memset(buffer, 0, buflen);passwd_t user passwd_at(head_passwd, i_record_index);i_record_index;if (user NULL) {return NSS_STATUS_NOTFOUND;}mjaw_logv(__FILE__, __LINE__, __func__, enter. uid: %d, cursor: %d, user-pw_uid, i_record_index);passwd_copy(user, resultbuf);*errop 0;return NSS_STATUS_SUCCESS; }getpwuid 此接口在用户鉴权时调用调用频率远高于getpwnam。用户进入桌面后每次鉴权都会调用这个接口即使用户选择使用其它账号鉴权此接口也先于getpwnam调用。 MJAW_EXPORT nss_status _nss_mjaw_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, size_t buflen, int *errop) {mjaw_log0(__FILE__, __LINE__, __func__, enter);if (!head_passwd) {head_passwd passwd_create();passwd_init(head_passwd);}//打开系统日志// openlog(nss_cw, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);//buffer重置为空memset(buffer, 0, buflen);//result结构体本身的内存由调用者传入if (!result) {mjaw_log0(__FILE__, __LINE__, __func__, result can not be empty.);return NSS_STATUS_NOTFOUND;}//输出开始处理的日志mjaw_logv(__FILE__, __LINE__, __func__, begin original uid: %d, result buffer uid: %d, gid: %d, uid, result-pw_uid, result-pw_gid);//获取web对用户id和组id的定义bool bok passwd_find_username_by_id(head_passwd, uid);if (!bok) {passwd_free(head_passwd);return NSS_STATUS_NOTFOUND;}passwd_copy(result, result);//输出完成处理的日志mjaw_logv(__FILE__, __LINE__, __func__, end original uid: %d, result buffer uid: %d, gid: %d, uid, result-pw_uid, result-pw_gid);//按约定返回0非零被su判定用户不存在*errop 0;passwd_free(head_passwd);//关闭系统日志// closelog();return NSS_STATUS_SUCCESS; } 调试 因NSS模块很接近系统内核底层稍有不慎开机或者重启系统黑屏变成了这样 原因是Linux系统内核的1号进程崩溃了。有关Linux 1号进程的资料可查阅https://man7.org/linux/man-pages/man1/init.1.html。因为root这个字符串与uid为0的这个系统用户身份没对应上程序的上下文环境没有相应的权限功能自然无法正常运转虽然给人的感觉已经是root身份。但开发过程中总是有所难免因此有些必要的调试设置在这里说明一下。 开始调试前多打开几个终端并登录开 如果环境已被NSS破坏可直接在这个终端上操作。但记住不要切换用户这些操作都会失败。也不会已经损坏的时候才开终端因为这个时候大部分图形程序都已经无法启动了。修改grub引导选项 这里建议修改/boot/grub/grub.cfg在所有的linux命令行后面加上参数systemd.debug_shell1。这样还可以直接切换到TTY9免登录。 其它事项 如何伪造信息登录桌面 调用useradd增加一个同名本地用户设置密码与否都不重要PAM模块可以无视本地存储的密码只要让系统的验证流程进入到自行开发的的PAM模块在PAM中对帐号进行认证即可。PAM允许开发者自由操作比如可以不验证登录凭据的正确性而直接进行进入系统。lightdm的自动登录就是这样实现的。 TTY登录成功图形界面登录黑屏 图形界面涉及到NSS模块与FreeDesktop的AcountsService交互问题此问题影响到LightDM并最终导致其崩溃。关于LightDM问题的处理我将继续编写文章说明问题的根本原因以及解决办法。 参考文档 https://docs.oracle.com/cd/E19683-01/806-4077/6jd6blbbb/index.htmlhttp://linux-pam.org/Linux-PAM-html/mwg-expected-of-module-auth.htmlhttps://www.openmjaw.org/doc/admin24/quickstart.htmlhttps://tools.ietf.org/html/rfc4511http://stefanfrings.de/qtwebapp/index-en.htmlhttps://docs.microsoft.com/en-us/previous-versions/windows/desktop/mjaw/lightweight-directory-access-protocol-mjaw-api 作者岬淢箫声日期2020年12月15日版本1.0博客http://caowei.blog.csdn.net创作不易请大家多多支持关注、转发。转发请注明来源。
http://www.pierceye.com/news/316390/

相关文章:

  • 北京建设部网站职称集约化网站建设方案
  • 常州溧阳建设工程管理中心网站惠州网站网站建设
  • 你的网站尚未进行备案中国建设银行贵州分行网站
  • 白银做网站的董事wordpress模板搬迁
  • 专业的网站开发建访动地科技登录网站
  • 网站模板素材下载如何做二维码跳转到网站
  • 自助建站免费信息发布网站wordpress 做图库栏目
  • 做网站 我们的工人怎么写哪个网站可以做照片分享
  • 做娱乐网站一个服务器可以建几个网站
  • 外包加工网站企业邮箱免费注册申请
  • jsp网站开发模式徐州手机网站制作
  • 三合一网站开发架构怎么用dw设计网站页面
  • 资源分享网站怎么做临沂住房和城乡建设厅网站
  • 住房和城乡建设部官方网站办事大厅企业展厅设计公司信息
  • 公司网站设计单页网站怎么做排名
  • 公司产品网站应该怎么做页面模板第三方应用
  • 绍兴网站建设网站站长 网站对比
  • 廊坊哪里做网站好费用
  • 织梦建站教程wordpress支持mysqli
  • 松江醉白池网站建设投资公司设立条件
  • 杭州网络seo优化知识
  • 对网站的建议和优化网银汇款企业做网站用途写什么
  • 商务网站的功能和建设制作外贸网站模板
  • 如何防止网站挂黑链怎么购买国外的域名
  • 企业官方网站地址怎么填微信页面设计网站
  • 国外购物网站有哪些郑州网站搜索排名
  • seo网站优化推广费用装饰行业网站建设
  • idea的网站开发登录页面做网页的
  • 寻找大连网站建设wordpress换模板 seo
  • 二手房公司网站源码网站的维护步骤