Linux编程入门-用户管理与安全 用户和组 getpwnam/getpwuid 从passwd文件中获取记录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <pwd.h> struct passwd { char *pw_name; char *pw_passwd; __uid_t pw_uid; __gid_t pw_gid; char *pw_gecos; char *pw_dir; char *pw_shell; }; struct passwd *getpwnam ( const char *__name ); struct passwd *getpwuid ( __uid_t __uid );
使用例子:
1 2 3 4 5 6 7 8 9 10 struct passwd * pwd;errno=0 ; pwd=getpwnnam (name); if (pwd==NULL ) if (errno==0 ){ } else { };
getgrnam/getgrgid 从group文件中获取记录:
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <grp.h> struct group { char *gr_name; char *gr_passwd; __gid_t gr_gid; char **gr_mem; }; struct group *getgrnam ( const char *__name ); struct group *getgrgid ( __gid_t __gid );
getpwent/setpwent/endpwent 按顺序扫描密码文件记录。getpwent
从passwd文件中逐条返回记录,无记录或出错时返回NULL,最后用endpwent
关闭密码文件。用setpwent
重返文件起始处。
1 2 3 struct passwd *getpwent (void );void setpwent (void ) ;void endpwent (void ) ;
例子:
1 2 3 4 struct passwd * pwd;while ((pwd=getpwent ())!=NULL ) printf ("%-8s %5ld\n" ,pwd->pw_name,(long )pw->pw_uid); endpwent ();
getspnam/getspent/setspent/endspent 从shadow文件中获取个别记录或扫描所有记录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <shadow.h> struct spwd { char *sp_namp; char *sp_pwdp; long int sp_lstchg; long int sp_min; long int sp_max; long int sp_warn; long int sp_inact; long int sp_expire; unsigned long int sp_flag; }; struct spwd *getspnam ( const char *__name ); struct spwd *getspent (void );void setspent (void ) ;void endspent (void ) ;
用户认证 crypt 使用用户名/密码认证的加密算法,即DES。crypt
返回的经加密的密码中,前两个字符是salf值。使用该函数时编译选项要加“-lcrypt”参数。
1 2 3 4 5 6 #define _XOPEN_SOURCE #include <unistd.h> char *crypt ( const char *__key, const char *__salt ) ;
getpass 读取用户密码。该函数先屏蔽回显功能,并停止对终端特殊字符字符的处理,如Ctrl+C等中断字符。然后打印prompt字符串,读取一行输入,返回静态分配的输入字符串。最后将终端设置还原。用sysconf
的_SC_LOGIN_NAME_MAX获取用户名字符串最大长度。
1 2 3 4 5 #define _BSD_SOURCE #include <unistd.h> char *getpass ( const char *__prompt ) ;
示例 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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #if ! defined(__sun) #define _BSD_SOURCE #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE #endif #endif #include <unistd.h> #include <limits.h> #include <pwd.h> #include <shadow.h> #include <crypt.h> int main (int argc, char * argv[]) { char * username, * password, * encrypted, * p; struct passwd * pwd; struct spwd * spwd; Boolean authOk; size_t len; long lnmax; lnmax = sysconf (_SC_LOGIN_NAME_MAX); if (lnmax == -1 ) lnmax = 256 ; username = malloc (lnmax); if (username == NULL ) errExit ("malloc" ); printf ("Username: " ); fflush (stdout); if (fgets (username, lnmax, stdin) == NULL ) exit (EXIT_FAILURE); len = strlen (username); if (username[len - 1 ] == '\n' ) username[len - 1 ] = '\0' ; pwd = getpwnam (username); if (pwd == NULL ) fatal ("couldn't get password record" ); spwd = getspnam (username); if (spwd == NULL && errno == EACCES) fatal ("no permission to read shadow password file" ); if (spwd != NULL ) pwd->pw_passwd = spwd->sp_pwdp; password = getpass ("Password: " ); encrypted = crypt (password, pwd->pw_passwd); for (p = password; *p != '\0' ; ) *p++ = '\0' ; if (encrypted == NULL ) errExit ("crypt" ); 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); exit (EXIT_SUCCESS); };
进程凭证 每个进程有一套用数字表示的用户ID和组ID,有时这些ID称为进程凭证。进程凭证具体包括实际用户ID和实际组ID、有效用户ID和有效组ID、保存用户ID和保存用户组ID、文件系统用户ID和文件系统组ID、辅助组ID。
实际用户ID和实际组ID确定进程所属的用户和组。登录shell从passwd文件中读取相应用户密码记录的第三、四字段,置为实际用户ID和实际组ID。创建新进程时,从父进程中继承这些ID。
有效用户ID为0的进程拥有超级用户的所有权限,称为特权级进程。通常有效用户ID和组ID与相应的实际ID相等,但当使用系统调用时,或执行set-user-ID和set-group-ID程序时,二者可能不同。set-user-ID程序将进程有效用户ID置为可执行文件用户ID,组ID类似,获得常规情况下不具有的权限。该权限位对shell脚本无效。有效用户ID为0的程序称为set-user-ID-root程序。
保存用户ID和保存用户组ID的值由对应的有效ID和有效组ID复制而来,允许进程的有效用户ID在实际用户ID和保存用户ID直接切换。
文件系统用户ID和组ID决定如打开文件、改变文件属主、修改文件权限等文件系统操作的操作权限。一般文件系统用户ID和组ID的值等于有效用户ID和组ID,发生变化时也跟随变化,除非用特定系统调用更改。
辅助组ID用于表示进程所属若干附加的组。新进程从其父进程处集成这些ID,登录shell从系统组文件获取辅助组ID。
getuid/getgid/setuid/setgid getuid
和getgid
分别获取调用进程的实际用户ID和组ID。setuid
和setgid
修改有效ID,可能实际ID和保存ID也随之修改。非特权用户执行set-user-ID程序时setuid
才起作用。当特权用户以非0参数调用setuid
后,实际用户ID、有效用户ID和保存用户ID三者都改为uid参数的值,所有特权将丢失且不能再用setuid
重置为0。
1 2 3 4 5 6 7 8 9 #include <unistd.h> __uid_t getuid (void ) ;__gid_t getgid (void ) ;int setuid ( __uid_t __uid ) ; int setgid ( __gid_t __gid ) ;
geteuid/getegid/seteuid/setegid geteuid
和getegid
返回有效ID,用seteduid
和setegid
修改有效ID。特权级进程能将其有效ID改为任意值。非特权级进程仅能将其有效ID改为相应的实际ID或保存ID。
1 2 3 4 5 6 7 8 __uid_t geteuid (void ) ; __gid_t getegid (void ) ; int seteuid ( __uid_t __uid ) ;int setegid ( __gid_t __gid ) ;
setreuid/setregid setreuid
和setregid
允许调用进程修改器实际和有效ID,当某个参数不用时置为-1。特权级用户可将其实际ID和有效ID设为任意值。非特权级进程只能将其实际ID设为有效ID值,且只能将有效ID设为当前实际ID或保存ID。当对有效ID设置的值不同余系统调用前的实际ID,无论进程是否拥有特权,都可将保存ID设为新的有效ID。
1 2 3 4 5 6 7 8 int setreuid ( __uid_t __ruid, __uid_t __euid ) ;int setregid ( __gid_t __rgid, __gid_t __egid ) ;
getresuid/getresgid/setresuid/setresgid getresuid
和getresgid
可获取调用进程当前实际ID、有效ID和保存ID,setresuid
和setresgid
可修改这些ID,无需修改的参数置-1。非特权进程能将实际ID、有效ID和保存ID中任一ID设为实际ID、有效ID或保存ID中任一当前值。特权级进程能对其实际ID、有效ID和保护ID任意设置。文件系统ID总与有效ID相同。setresuid
和setresgid
具有0/1效应,即对ID的修改请求要么全成功,要么全失败。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int getresuid ( __uid_t *__ruid, __uid_t *__euid, __uid_t *__suid ) ;int getresgid ( __gid_t *__rgid, __gid_t *__egid, __gid_t *__sgid ) ;int setresuid ( __uid_t __ruid, __uid_t __euid, __uid_t __suid ) ;int setresgid ( __gid_t __rgid, __gid_t __egid, __gid_t __sgid ) ;
setfsuid/setfsgid 修改文件系统ID。非特权进程能将文件系统ID设为实际ID、有效ID或保存ID的当前值。特权级进程能将为你教案系统ID设为任意值。
1 2 3 4 5 6 7 #include <sys/fsuid.h> int setfsuid ( __uid_t __uid ) ;int setfsgid ( __gid_t __gid ) ;
getgroups/setgroups/initgroups getgroups
将当前进程的辅助组ID的集合返回至list参数中。size参数建议设为NGROUPS_MAX+1,其中该常量在limits.h中定义,也可用sysconf
的_SC_NGROUPS_MAX获取,还可通过/proc/sys/kernel/ngroups_max文件读取。特权级进程可用setgroups
和initgroups
修改辅助组ID集合。setgroups
用groups参数数组替换调用进程的辅助组ID。initgroups
扫描group文件,为user参数创建属组列表,初始化调用进程的辅助组ID。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int getgroups ( int __size, __gid_t __list[] ) ; #define _BSD_SOURCE #include <grp.h> int setgroups ( size_t __n, const __gid_t *__groups ) ; int initgroups ( const char *__user, __gid_t __group ) ;
示例 获取进程所有用户ID和组ID:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 #define _GNU_SOURCE #include <unistd.h> #include <sys/fsuid.h> #include <limits.h> #include <pwd.h> #include <stdlib.h> #include <grp.h> #include <stdio.h> #define SG_SIZE (NGROUPS_MAX + 1) char * userNameFromId (uid_t uid) { struct passwd * pwd; pwd = getpwuid (uid); return (pwd == NULL ) ? NULL : pwd->pw_name; }; uid_t userIdFromName (const char * name) { struct passwd * pwd; uid_t u; char * endptr; if (name == NULL || *name == '\0' ) return -1 ; u = strtol (name, &endptr, 10 ); if (*endptr == '\0' ) return u; pwd = getpwnam (name); if (pwd == NULL ) return -1 ; return pwd->pw_uid; }; char * groupNameFromId (gid_t gid) { struct group * grp; grp = getgrgid (gid); return (grp == NULL ) ? NULL : grp->gr_name; }; gid_t groupIdFromName (const char * name) { struct group * grp; gid_t g; char * endptr; if (name == NULL || *name == '\0' ) return -1 ; g = strtol (name, &endptr, 10 ); if (*endptr == '\0' ) return g; grp = getgrnam (name); if (grp == NULL ) return -1 ; return grp->gr_gid; }; int main (int argc, char * argv[]) { uid_t ruid, euid, suid, fsuid; gid_t rgid, egid, sgid, fsgid; gid_t suppGroups[SG_SIZE]; int numGroups, j; char * p; if (getresuid (&ruid, &euid, &suid) == -1 ) errExit ("getresuid" ); if (getresgid (&rgid, &egid, &sgid) == -1 ) errExit ("getresgid" ); fsuid = setfsuid (0 ); fsgid = setfsgid (0 ); printf ("UID: " ); p = userNameFromId (ruid); printf ("real=%s (%ld); " , (p == NULL ) ? "???" : p, (long )ruid); p = userNameFromId (euid); printf ("eff=%s (%ld); " , (p == NULL ) ? "???" : p, (long )euid); p = userNameFromId (suid); printf ("saved=%s (%ld); " , (p == NULL ) ? "???" : p, (long )suid); p = userNameFromId (fsuid); printf ("fs=%s (%ld); " , (p == NULL ) ? "???" : p, (long )fsuid); printf ("\n" ); printf ("GID: " ); p = groupNameFromId (rgid); printf ("real=%s (%ld); " , (p == NULL ) ? "???" : p, (long )rgid); p = groupNameFromId (egid); printf ("eff=%s (%ld); " , (p == NULL ) ? "???" : p, (long )egid); p = groupNameFromId (sgid); printf ("saved=%s (%ld); " , (p == NULL ) ? "???" : p, (long )sgid); p = groupNameFromId (fsgid); printf ("fs=%s (%ld); " , (p == NULL ) ? "???" : p, (long )fsgid); printf ("\n" ); numGroups = getgroups (SG_SIZE, suppGroups); if (numGroups == -1 ) errExit ("getgroups" ); printf ("Supplementary groups (%d): " , numGroups); for (j = 0 ; j < numGroups; j++) { p = groupNameFromId (suppGroups[j]); printf ("%s (%ld) " , (p == NULL ) ? "???" : p, (long )suppGroups[j]); }; printf ("\n" ); exit (EXIT_SUCCESS); };