Linux 用户和组编程
来源:互联网 发布:光纤传输网络 编辑:程序博客网 时间:2024/06/14 07:35
在Linux中,每个用户都有一个唯一的用户名和用户id。而用户又可以隶属于一个或多个组,每个组也有一个唯一的组名和组id。
1. 密码文件/etc/passwd
首先来看密码文件,对系统中的每个用户账户,密码文件/etc/passwd都会专门有一行对其进行描述,每一行都包含7个字段,用冒号分割,例如:
经过加密的密码:该字段是经过加密处理的密码,这里用的字母'x'来显示。
用户id:用户id,对于root用户,用户id为0。
组id:组id。
注释:存放关于用户的描述性文字。
主目录:用户工作主目录,可以查看HOME环境变量。
登录shell:登录的shell,例如/bin/bash。
对于密码文件的访问,可以通过getpwnam、getpwuid来操作,原型如下:
2. 组文件/etc/group
系统中每个组在/etc/group中都有一条记录,每个记录包含4个字段,用冒号分割,例如:
经过加密的组密码:组密码属于非强制性的。
组id:组id号。
用户列表,属于该组的用户列表,之间用逗号分割。
对于root组后面没有用户列表,但是root用户确实属于root组,因为它的组id为0。
对于组文件的访问也有两个函数,原型如下:
root组的members成员为空的。
既然这里提到了组的概念,那么我们怎么查看用户属于哪个组呢,linux提供了一个命令,那就是groups命令。groups命令会将用户所属组给列举出来,如果没有指定用户名,那么显示的就是当前登录的用户。
3. 密码文件/etc/shadow
经过加密处理的密码实际上是存储在/etc/shadow文件中的,所以在/etc/passwd文件中看到的用户密码使用字符'x'来表示的。另外/etc/shadow文件是需要具有root用户权限才能访问的,普通用户是没有权限访问的。
对于/etc/shadow文件的访问可以通过getspnam函数,原型如下:
得到的struct spwd结构指针类型定义如下:
接下来我们用一个实例来看如何通过用户名和密码的方式来认证。
由于安全方面的原因,Linux系统采用的单向加密算法对密码进行加密,也就是说通过加密密码是无法还原出原始密码的。因此,认证的方式只有通过原始密码,然后采用同一加密算法进行加密,并将得到的加密密码与/etc/shadow中的密码进行匹配,完全相同,才表示认证成功。加密算法使用crypt函数,原型如下:
1. 密码文件/etc/passwd
首先来看密码文件,对系统中的每个用户账户,密码文件/etc/passwd都会专门有一行对其进行描述,每一行都包含7个字段,用冒号分割,例如:
root:x:0:0:root:/root:/bin/bash登录名:第一个字段是登录名或者说是用户名。
经过加密的密码:该字段是经过加密处理的密码,这里用的字母'x'来显示。
用户id:用户id,对于root用户,用户id为0。
组id:组id。
注释:存放关于用户的描述性文字。
主目录:用户工作主目录,可以查看HOME环境变量。
登录shell:登录的shell,例如/bin/bash。
对于密码文件的访问,可以通过getpwnam、getpwuid来操作,原型如下:
#include <sys/types.h>#include <pwd.h>struct passwd *getpwnam(const char *name);struct passwd *getpwuid(uid_t uid);
而passwd结构定义如下:
struct passwd { char *pw_name; /* username */ char *pw_passwd; /* user password */ uid_t pw_uid; /* user ID */ gid_t pw_gid; /* group ID */ char *pw_gecos; /* user information */ char *pw_dir; /* home directory */ char *pw_shell; /* shell program */};其中每个成员对应/etc/passwd中的一个字段,getpwnam和getpwuid返回值都是一样的,只是传递参数不一样,一个是用户名,而另一个是用户id。代码示例如下:
#include <stdio.h>#include <pwd.h>int main(int argc, char *argv[]){ struct passwd *pwd = NULL; pwd = getpwnam(argv[1]); if (pwd == NULL) { perror("getpwnam"); return -1; } printf( "name \t\t%s\n" "passwd \t\t%s\n" "uid \t\t%d\n" "gid \t\t%d\n" "information \t%s\n" "directory \t%s\n" "shell \t\t%s\n", pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid, pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell); return 0;}得到root用户信息如下:
name rootpasswd xuid 0gid 0information rootdirectory /rootshell /bin/bash
2. 组文件/etc/group
系统中每个组在/etc/group中都有一条记录,每个记录包含4个字段,用冒号分割,例如:
root:x:0:组名:组名,与用户登录名类似。
经过加密的组密码:组密码属于非强制性的。
组id:组id号。
用户列表,属于该组的用户列表,之间用逗号分割。
对于root组后面没有用户列表,但是root用户确实属于root组,因为它的组id为0。
对于组文件的访问也有两个函数,原型如下:
#include <sys/types.h>#include <grp.h>struct group *getgrnam(const char *name);struct group *getgrgid(gid_t gid);返回值为struct group类型指针,struct group定义如下:
struct group { char *gr_name; /* group name */ char *gr_passwd; /* group password */ gid_t gr_gid; /* group ID */ char **gr_mem; /* group members */};代码示例如下:
#include <stdio.h>#include <grp.h>int main(int argc, char *argv[]){ struct group *grp = NULL; int i; grp = getgrnam(argv[1]); if (grp == NULL) { perror("getgrnam"); return -1; } printf( "name \t\t%s\n" "passwd \t\t%s\n" "gid \t\t%d\n", grp->gr_name, grp->gr_passwd, grp->gr_gid); printf("members \t"); for (i = 0; grp->gr_mem[i] != NULL; i++) { printf("%s ", grp->gr_mem[i]); } printf("\n"); return 0;}root组信息如下:
name rootpasswd xgid 0members
root组的members成员为空的。
既然这里提到了组的概念,那么我们怎么查看用户属于哪个组呢,linux提供了一个命令,那就是groups命令。groups命令会将用户所属组给列举出来,如果没有指定用户名,那么显示的就是当前登录的用户。
3. 密码文件/etc/shadow
经过加密处理的密码实际上是存储在/etc/shadow文件中的,所以在/etc/passwd文件中看到的用户密码使用字符'x'来表示的。另外/etc/shadow文件是需要具有root用户权限才能访问的,普通用户是没有权限访问的。
对于/etc/shadow文件的访问可以通过getspnam函数,原型如下:
#include <shadow.h>struct spwd *getspnam(const char *name);注意:需要root权限。
得到的struct spwd结构指针类型定义如下:
struct spwd { char *sp_namp; /* Login name */ char *sp_pwdp; /* Encrypted password */ long sp_lstchg; /* Date of last change (measured in days since 1970-01-01 00:00:00 +0000 (UTC)) */ long sp_min; /* Min # of days between changes */ long sp_max; /* Max # of days between changes */ long sp_warn; /* # of days before password expires to warn user to change it */ long sp_inact; /* # of days after password expires until account is disabled */ long sp_expire; /* Date when account expires (measured in days since 1970-01-01 00:00:00 +0000 (UTC)) */ unsigned long sp_flag; /* Reserved */};注意:得到的密码也是经过加密处理的密码。
接下来我们用一个实例来看如何通过用户名和密码的方式来认证。
由于安全方面的原因,Linux系统采用的单向加密算法对密码进行加密,也就是说通过加密密码是无法还原出原始密码的。因此,认证的方式只有通过原始密码,然后采用同一加密算法进行加密,并将得到的加密密码与/etc/shadow中的密码进行匹配,完全相同,才表示认证成功。加密算法使用crypt函数,原型如下:
#define _XOPEN_SOURCE /* See feature_test_macros(7) */#include <unistd.h>char *crypt(const char *key, const char *salt);代码示例如下:
#define _XOPEN_SOURCE#include <stdio.h>#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <pwd.h>#include <shadow.h>int main(void){char *username, *password, *encrypted, *p;struct passwd *pwd;struct spwd *spwd;size_t len;int authok;long lnmax;lnmax = sysconf(_SC_LOGIN_NAME_MAX);if (lnmax < 0)/* If limit is indeterminate */lnmax = 256;/* make a guess */username = malloc(lnmax);if (username == NULL)exit(EXIT_FAILURE);printf("Username: ");fflush(stdout);if (fgets(username, lnmax, stdin) == NULL)exit(EXIT_FAILURE);/* Exit on EOF */len = strlen(username);if (username[len - 1] == '\n')username[len - 1] = '\0';/* Remove trailing '\n' */pwd = getpwnam(username);if (pwd == NULL) {printf("couldn't get password record\n");exit(EXIT_FAILURE);}spwd = getspnam(username);if (spwd == NULL && errno == EACCES) {printf("no permission to read shadow password file\n");exit(EXIT_FAILURE);}if (spwd != NULL)/* If there is a shadow password record */pwd->pw_passwd = spwd->sp_pwdp;/* Use the shadow password */password = getpass("Password: ");/* Encrypt password and erase cleartext version immediately */encrypted = crypt(password, pwd->pw_passwd);for (p = password; *p != '\0'; )*p++ = '\0';if (encrypted == NULL)exit(EXIT_FAILURE);authok = strcmp(encrypted, pwd->pw_passwd) == 0;if (!authok) {printf("Incorrect password\n");exit(EXIT_FAILURE);}printf("Successfully authenticated: UID=%ld\n", (long) pwd->pw_uid);/* Now do authenticated work... */exit(EXIT_SUCCESS);}
注意使用crypt函数时需要连接crypt库,所以在练级时需要加上-lcrypt,编译上面代码命令如下:
gcc -Wall -o test check.c -lcrypt
参考教程:The Linux Programming Interface - A Linux and UNIX System Programming Handbook.pdf
0 0
- Linux 用户和组编程
- linux编程手册第8章用户和组
- Linux编程用户和用户组的概念
- Linux编程用户和用户组进阶命令
- Linux编程用户和用户组其他命令
- Linux 用户和组
- linux用户和组
- Linux 用户和组
- linux 用户和组
- linux用户和组
- linux用户和组
- linux 组和用户
- linux用户和组
- Linux 用户和组
- Linux用户和组
- linux 用户和组
- linux创建组和用户,切换用户
- Unix/Linux环境C编程入门教程(33) 命令和鼠标管理用户和组
- hdu 5360 Hiking (优先队列+贪心)
- Linux网络编程(3)——多进程、多线程
- Android基础篇之Intent(二)-Intent使用
- 畅通工程
- Controller正反向传值
- Linux 用户和组编程
- ACdream 1073 雷霆战机
- RoadFlow项目架构分析
- Ubuntu搭建Android开发环境
- android学习笔记NO.2
- FORM 更新多表视图
- json数据解析
- 我花的钱都是父母挣的
- iOS最简单方法判断网络类型——通过状态栏显示