1.口令文件
口令文件,即Unix系统用户数据库,存储在/etc/passwd中,是一个ASCII文件,包含的字段信息在<pwd.h>定义的passwd数据结构中。
pwd.h文件所在位置:/usr/include/pwd.h
struct passwd
{
char *pw_name;
char *pw_passwd;
uid_t uid;
gid_t gid;
char *pw_gecos;
char *pw_dir;
char *pw_shell;
};
分别根据用户ID和用户名获取口令文件函数:
struct passwd *getpwuid(uid_t uid); //根据用户ID
struct passwd *getpwnam(const char *name); //根据用户名
struct passwd *getpwuid(uid_t uid); //根据用户ID
struct passwd *getpwnam(const char *name); //根据用户名
查看整个口令文件并遍历:
struct passwd *getpwent(void); //返回口令文件中的下一个记录项
void setpwent(void); //反绕文件,从文件头开始
void endpwent(void); //关闭文件
void setpwent(void); //反绕文件,从文件头开始
void endpwent(void); //关闭文件
根据uid取得记录项、取下一记录项、遍历文件打印用户名;程序如下:
#include <stdio.h>
#include <pwd.h>
int main()
{
struct passwd *ppwd = NULL;
setpwent();
if ((ppwd = getpwuid(500)) != NULL)
{
printf("getpwuid() ok\n");
printf("name: %s ", ppwd->pw_name);
printf("passwd: %s ", ppwd->pw_passwd);
printf("uid: %d ", ppwd->pw_uid);
printf("gid: %d ", ppwd->pw_gid);
printf("gecos: %s ", ppwd->pw_name);
printf("director: %s ", ppwd->pw_dir);
printf("shell: %s \n", ppwd->pw_shell);
}
endpwent();
struct passwd *ppwd2 = NULL;
setpwent();
if ((ppwd2 = getpwent()) != NULL)
{
printf("getpwent() ok\n");
printf("name: %s ", ppwd2->pw_name);
printf("passwd: %s ", ppwd2->pw_passwd);
printf("uid: %d ", ppwd2->pw_uid);
printf("gid: %d ", ppwd2->pw_gid);
printf("gecos: %s ", ppwd->pw_name);
printf("director: %s ", ppwd->pw_dir);
printf("shell: %s \n", ppwd->pw_shell);
}
endpwent();
setpwent();
printf("\nprint all user's name:\n ");
while ((ppwd = getpwent()) != NULL)
{
printf("%s ", ppwd->pw_name);
}
printf("\n");
endpwent();
return 0;
}
结果:
应在开始位置调用setpwent(),结束后调用endpwent()关闭文件
2.阴影口令
/etc/passwd文件,任何用户都可以读,密码不安全,所以需要将密码单独放到阴影口令中。
只有超级用户(root)才能调用访问阴影文件的函数。阴影文件位于/etc/shadow文件中
#include <shadow.h>
struct spwd
{
char *sp_namp; /* 登录名 */
char *sp_pwdp; /* 加密口令 */
long sp_lstchg; /* 上次更改口令以来经过的时间 (measured in days since 1970-01-01 00:00:00 +0000 (UTC)) */
long sp_min; /* 经多少天以后允许更改*/
long sp_max; /* 要求更改尚余天数 */
long sp_warn; /* 超期警告天数 */
long sp_inact; /* 账户不活动之前尚余天数 */
long sp_expire; /* 账户超期天数 */
unsigned long sp_flag; /* 保留 */
};
struct spwd *getspnam(const char *name);
struct spwd *getspent(void);
void setspent(void);
void endspent(void);
#include <stdio.h>
#include <shadow.h>
int main()
{
struct spwd *pspwd = NULL;
setspent();
if ((pspwd = getspnam("zxin")) != NULL)
{
printf("getspnam() ok\n");
printf("name: %s ", pspwd->sp_namp);
printf("passwd: %s ", pspwd->sp_pwdp);
}
endspent();
setspent();
printf("\nprint all user's name:\n ");
while ((pspwd = getspent()) != NULL)
{
printf("%s ", pspwd->sp_namp);
}
printf("\n");
endspent();
return 0;
}
结果:
分析:root账户才能执行这些函数
3.组文件
/etc/group Unix组文件(组数据库) <grp.h>头文件 struct grp结构
#include <grp.h>
struct group
{
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /*指向各用户名指针的数组*/
};
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /*指向各用户名指针的数组*/
};
struct group *getgrnam(const char *name);
struct group *getgrgid(gid_t gid);
搜索整个文件组函数:
struct group *getgrent(void);
void setgrent(void);
void endgrent(void);
struct group *getgrgid(gid_t gid);
搜索整个文件组函数:
struct group *getgrent(void);
void setgrent(void);
void endgrent(void);
写个程序,输出组名和组id
#include <stdio.h>
#include <grp.h>
int main()
{
struct group *pgrp = NULL;
setgrent();
while ((pgrp = getgrent()) != NULL)
{
printf("group name: %s, group id: %d\n", pgrp->gr_name, pgrp->gr_gid);
}
endgrent();
return 0;
}
结果如下:
4.附属组
我们不仅可以属于口令文件记录项中组ID所对应的组,也可属于至多16个另外的组。文件访问权限检查相应的被修改为:不仅将进程的有效组ID与文件组ID相比较,而且也将所有附属组ID与文件的组ID进行比较。
优点:不必再显示经常更改组,一个用户会参与多个项目,因此,也就要同时属于多个组
获取和设置组ID:
#include <unistd.h>
#include <grp.h>
int getgroups(int gidsetsize, gid_t grouplist[]);//获取进程个附属组ID,到grouplist[]中,最多gidsetsize个
int setgroups(int ngroups, const gid_t grouplist[]);//由超级用户调用,为调用进程设置附属组ID表
int initgroups(const char *username, gid_t basegid);//调用setgroups,确定其组的成员关系,只有超级用户才能调用此函数
5.其他数据文件
其他数据文件 除了口令文件和组文件外,Linux也使用很多其他文件,一般情况下,这些文件都至少支持三个函数:
(1)get函数:读文件中的下一个记录项。
(2)set函数:将文件偏移量设置到文件起始处。
(3)end函数:关闭系统文件。
如果该文件支持关键字检索,例如口令文件支持基于用户名和用户ID的检索,因此实现了接口getpwnam和getpwuid函数,就会支持相应的函数。
(1)get函数:读文件中的下一个记录项。
(2)set函数:将文件偏移量设置到文件起始处。
(3)end函数:关闭系统文件。
如果该文件支持关键字检索,例如口令文件支持基于用户名和用户ID的检索,因此实现了接口getpwnam和getpwuid函数,就会支持相应的函数。
6.系统标识
#include <sys/utsname.h>
int uname(struct utsname *name);//返回与主机和操作系统有关的信息
返回值:成功,非负;失败,-1
struct utsname
{
char sysname[];/* name of the operating system */
char nodename[];/* name of this node */
char release[];/* current release of operating system */
char version[];/* current version of this release */
char machine[];/* name of hardware type */
};
程序,返回主机和系统信息:
#include <stdio.h>
#include <sys/utsname.h>
int main()
{
struct utsname puts;
if (uname(&puts) == -1)
{
printf("uname() error\n");
exit(-1);
}
printf("system name: %s\n", puts.sysname);
printf("system nodename: %s\n", puts.nodename);
printf("system release: %s\n", puts.release);
printf("system version: %s\n", puts.version);
printf("system machine: %s\n", puts.machine);
return 0;
}
结果:
7.时间相关
参考:
时间和日期,Unix内核提供的基本时间服务是计算自国际标准时间公元1970年1月1日00:00:00以来经过的秒数,基本数据类型是time_t,称为日历时间,包括时间和日期,将时间和日期作为一个量值进行保存。类型定义如下:
#ifndef __TIME_T
#define __TIME_T /* 避免重复定义 time_t */
typedef long time_t; /* 时间值time_t 为长整型的别名*/
#endif
#include <time.h>
time_t time(time_t *t); //返回当前时间及日期
#include <sys/time.h>
struct tm *localtime(const time_t *timep); //转换为本地时间
返回自1970.01.01经过的秒数、返回当前国际标准时间、返回本地时间,程序如下:
#include <stdio.h>
#include <time.h>
int main()
{
time_t now;
now = time(&now);
printf("seconds from 1970.01.01 is %ld\n", now);
struct tm *ptime;
ptime = gmtime(&now);
ptime->tm_year += 1900;
ptime->tm_mon += 1;
printf("global time is:\n%d-%d-%d %d: %d: %d\n", ptime->tm_year,
ptime->tm_mon, ptime->tm_mday, ptime->tm_hour, ptime->tm_min, ptime->tm_sec);
ptime = localtime(&now);
ptime->tm_year += 1900;
ptime->tm_mon += 1;
printf("local time is:\n%d-%d-%d %d: %d: %d\n", ptime->tm_year,
ptime->tm_mon, ptime->tm_mday, ptime->tm_hour, ptime->tm_min, ptime->tm_sec);
return 0;
}
结果:
时间相关的暂时只看了time、gmtime、localtime、struct tm、time_t;剩下的等用到了再回头看