系统相关信息和文件基础(一)

原创 2018年02月01日 22:45:37

1. 基本概念

1.1 Password File And Shadow Passwords

Description struct passwd member
user name char *pw_name
encrypted password char *pw_passwd
numerical user ID uid_t pw_uid
numerical group ID gid_t pw_gid
comment field char *pw_gecos
initial working directory char *pw_dir
initial shell (user program) char *pw_shell

  在/etc/passwd中的条目如下所示:

root:x:0:0:root:/root:/bin/bash
squid:x:23:23::/var/spool/squid:/dev/null
nobody:x:65534:65534:Nobody:/home:/bin/sh
sar:x:205:105:Stephen Rago:/home/sar:/bin/bash

  对上述条目的解读遵循以下准则:

  • There is usually an entry with the user name root. This entry has a user ID of 0 (the superuser).
  • The encrypted password field contains a single character as a placeholder.
  • Some fields in a password file entry can be empty. If the encrypted password field is empty, it usually means that the user does not have a password. The entry for squid has one blank field: the comment field. An empty comment field has no effect.
  • The shell field contains the name of the executable program to be used as the login shell for the user. Note, however, that the entry for squid has /dev/null as the login shell. Obviously, this is a device and cannot be executed, so its use here is to prevent anyone from logging in to our system as user squid.
  • The nobody user name can be used to allow people to log in to a system, but with a user ID (65534) and group ID (65534) that provide no privileges. The only files that this user ID and group ID can access are those that are readable or writable by the world.
  • Some systems that provide the finger(1) command support additional
    information in the comment field. Each of these fields is separated by a comma:
    the user’s name, office location, office phone number, and home phone number.

  上述论述中comment field,分隔,可以附加用户名,办公室地址,办公室电话,家庭电话相关信息。并且这些信息够被finger指令直接使用。

#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
Both return: pointer if OK, NULL on error

struct passwd *getpwent(void);
Returns: pointer if OK, NULL on error or end of file
void setpwent(void);
void endpwent(void);

  getpwuid,getpwnamgetpwent都返回一个指向passwd结构体的指针,该结构体为静态变量,所以每次调用以上函数,其内容都会改变。getpwuid,getpwnam可以根据uid或者namepasswd文件中查找一个用户的相关信息,而getpwent,setpwent,endpwent三个函数可以用于遍历完整的passwd文件。
  getpwent每次返回passwd文件中的下一条记录,如果第一次调用该函数,则该函数自动打开它需要的文件,setpwent可以rewind其所打开的文件,也就是从头开始。endpwent关闭getpwent所打开的文件。特别的返回条目的顺序是不确定的:

There is no order implied when we use this function; the entries can be in any order, because some systems use a hashed version of the file /etc/passwd.

  为了防止获取原始密码(即使是加密后的),系统将加密后的密码存储在另外的文件,这个文件就是shadow password file

Description struct spwd member
user loginname char *sp_namp
encrypted password char *sp_pwdp
days since Epoch of last password change int sp_lstchg
days until change allowed int sp_min
days before change required int sp_max
days warning for expiration int sp_warn
days before account inactive int sp_inact
days since Epoch when account expires int sp_expire
reserved unsigned int sp_fla
  • The only two mandatory fields are the user’s login name and encrypted password. The other fields control how often the password is to change and how long an account is allowed to remain active.

  • The shadow password file should not be readable by the world.Only a few programs need to access encrypted passwords —login(1) and passwd(1), for example — and these programs are often set-user-ID root. With shadow passwords, the regular password file, /etc/passwd, can be left readable by the world.

  除了上面两点值得注意的,linux上访问该shadow password文件的API如下所示,其用法和上述无异:

#include <shadow.h>
struct spwd *getspnam(const char *name);
struct spwd *getspent(void);
Both return: pointer if OK, NULL on error
void setspent(void);
void endspent(void);

2. Group File And Supplementary Group IDs

Description struct group member
group name char *gr_name
encrypted password char *gr_passwd
numerical group ID int gr_gid
array of pointers to individual user names char **gr_mem
#include <grp.h>
struct group *getgrgid(gid_t gid);
struct group *getgrnam(const char *name);
Both return: pointer if OK, NULL on error
struct group *getgrent(void);
Returns: pointer if OK, NULL on error or end of file
void setgrent(void);
void endgrent(void);

  group结构体中gr_mem指向属于一个数组,该数组的成员是指向用户名的指针,该数组以null指针结尾。getgrgidgetgrnam可以根据其gid或者name/etc/group获得一个条目,其他的相关操作都和前面passwd相仿。
  我们不仅可以属于一个在passwd文件中指定的组,也可以属于至多16个别的组。文件访问权限检查的时候也会参考supplementary group IDs

#include <unistd.h>
int getgroups(int gidsetsize, gid_t grouplist[]);
Returns: number of supplementary group IDs if OK, −1 on error
#include <grp.h> /* on Linux */
int setgroups(int ngroups, const gid_t grouplist[]);
#include <grp.h> /* on Linux and Solaris */
int initgroups(const char *username, gid_t basegid);
Both return: 0 if OK, −1 on error

  getgroups函数使用supplementary group IDs填充gourplist所指向的数组,最多达到gidsetsize个,该函数返回实际存储的成员个数。如果该gidsetsize为0,则该函数只返回supplementary group IDs的个数。
  setgroups可以为当前进程设置其supplementary group IDs,此时调用该函数的进程必须具有管理员权限。initgroups其会读取整个group文件,寻找username所属的组,并调用setgroups函数,设置相应usernamesupplementary group IDs,需要注意以下引用:

initgroups includes basegid in the supplementary group ID list; basegid is the group ID from the password file for username.

1.3 Other Data Files And Login Accounting

  一般这些文件会具有以下函数来帮助操作,以下表格列举了一些常用系统数据文件和对应的函数:

  • A get function that reads the next record, opening the file if necessary.
  • A set function that opens the file, if not already open, and rewinds the file.
  • An end entry that closes the data file.
Description Data file Header Structure Additional keyed lookup
passwords /etc/passwd pwd.h passwd getpwnam, getpwuid
groups /etc/group grp.h group getgrnam, getgrgid
shadow /etc/shadow shadow.h spwd getspnam
hosts /etc/hosts netdb.h hostent getnameinfo, getaddrinfo
networks /etc/networks netdb.h netent getnetbyname, getnetbyaddr
protocols /etc/protocols netdb.h protoent getprotobyname, getprotobynumber
services /etc/services netdb.h servent getservbyname, getservbyport

  utmp记录当前登录的用户,wtmp记录所有的用户登录,注销信息:

struct utmp {
char ut_line[8]; /* tty line: "ttyh0", "ttyd0", "ttyp0", ... */
char ut_name[8]; /* login name */
long ut_time; /* seconds since Epoch * /
};

  记录该信息的细节如下:

On login, one of these structures was filled in and written to the utmp file by the login program, and the same structure was appended to the wtmp file. On logout, the entry in the utmp file was erased—filled with null bytes—by the init process, and a new entry was appended to the wtmp file. This logout entry in the wtmp file had the ut_name field zeroed out. Special entries were appended to the wtmp file to indicate when the system was rebooted and right before and after the system’s time and date was changed. Linux 3.2.0, the utmp(5) manual page gives the format of their versions ofthese login records. The pathnames of these two files are /var/run/utmp and/var/log/wtmp.

1.4 System Identification

#include <sys/utsname.h>
int uname(struct utsname *name);
Returns: non-negative value if OK, −1 on error
int gethostname(char *name, int namelen);
Returns: 0 if OK, −1 on error

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 * /
};

  utsname成员都是null字符结尾,uname命令使用的就是该结构体。gethostname函数在socket编程中使用的比较频繁,通过这个函数得到的主机名是fully qualified domain name,一般该主机位于TCP/IP网络上,但是注意uname在POSIX中规定如下:

POSIX.1 warns that the nodename element may not be adequate to reference the host on a communications network.

1.5 Time and Date Routines

#include <time.h>
time_t time(time_t *calptr);
Returns: value of time if OK, −1 on error
int clock_gettime(clockid_t clock_id, struct timespec *tsp);
Returns: 0 if OK, −1 on error
int clock_getres(clockid_t clock_id, struct timespec *tsp);
Returns: 0 if OK, −1 on error
int clock_settime(clockid_t clock_id, const struct timespec *tsp);
Returns: 0 if OK, −1 on error
#include <sys/time.h>
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
Returns: 0 always

struct tm { /* a broken-down time */
int tm_sec; /* seconds after the minute: [0 - 60] */
int tm_min; /* minutes after the hour: [0 - 59] */
int tm_hour; /* hours after midnight: [0 - 23] */
int tm_mday; /* day of the month: [1 - 31] */
int tm_mon; /* months since January: [0 - 11] */
int tm_year; /* years since 1900 */
int tm_wday; /* days since Sunday: [0 - 6] */
int tm_yday; /* days since January 1: [0 - 365] */
int tm_isdst; /* daylight saving time flag: <0, 0, >0 */
};
struct tm *gmtime(const time_t *calptr);
struct tm *localtime(const time_t *calptr);
Both return: pointer to broken-down time, NULL on error
time_t mktime(struct tm *tmptr);
Returns: calendar time if OK, −1 on error

  以下引用出自MAN PAGE:

time() returns the time as the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). If t is non-NULL, the return value is also stored in the memory pointed to by t.

Identifier Option Description
CLOCK_REALTIME real system time
CLOCK_MONOTONIC _POSIX_MONOTONIC_CLOCK real system time with no negative jumps
CLOCK_PROCESS_CPUTIME_ID _POSIX_CPUTIME CPU time for calling process
CLOCK_THREAD_CPUTIME_ID _POSIX_THREAD_CPUTIME CPU time for calling thread

  clock_gettime可以获得指定时钟的当前时间,并存储在tsp所指的变量中。当clock_idCLOCK_REALTIME,该函数作用与time相同。clock_getres将得到clock_id指定的时钟的精准度,并将该值存在tsp所指的结构体中。gettimeofday作用与time相似,但是其提供更高的精度,精确到ms

  localtimegmtime都是将calptr所指的时间转换为tm,但是前者将其转化为本地时间,后者还是UTC。mktimelocaltime作用恰好相反。

size_t strftime(char *restrict buf, size_t maxsize, const char *restrict format, const struct tm *restrict tmptr);
size_t strftime_l(char *restrict buf, size_t maxsize, const char *restrict format, const struct tm *restrict tmptr, locale_t locale);
Both return: number of characters stored in array if room, 0 otherwise
char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tmptr);
Returns: pointer to one character past last character parsed, NULL otherwise

  strftime函数将tmptr所指的tm所指的时间格式化输出到buf所指的数组中,如果maxsize的数组能够容下转换的结果,则返回实际存储的字节数,不含空字符。如果该数组的大小容乃不下,就返回0。format格式化输出参数,具体细节使用的时候再细究。strptimestrftime相似,两者格式转换符有区别,看看APUE中的一个例子:

int main(void)
{
    time_t t;
    struct tm * tmp;
    char buf1[16];
    char buf2[64];
    time(&t);
    tmp = localtime(&t);
    if (strftime(buf1, 16, "time and date: %r, %a %b %d, %Y", tmp) == 0)
        printf("buffer length 16 is too small\n");
    else
        printf("%s\n", buf1);
    if (strftime(buf2, 64, "time and date: %r, %a %b %d, %Y", tmp) == 0)
        printf("buffer length 64 is too small\n");
    else
        printf("%s\n", buf2);
    exit(0);
}

  结果如下:

$ ./a.out
buffer length 16 is too small
time and date: 11:12:35 PM, Thu Jan 19, 2012

  localtime, mktime, strftime三个函数受TZ环境变量影响,如果该变量被定义,则这三个函数将参照该环境变量进行输出,如果该变量为NULL,则默认使用UTC。以上函数的关系如下图所示:
这里写图片描述

2. 实验

Write a program to obtain the current time and print it using strftime, so that it looks like the default output from date(1). Set the TZ environment variable to different values and see what happens.

版权声明:本文为博主原创文章,未经博主允许不得转载。

SQL第九章数据查询基础上机题1-4

//查询学生相关基本信息 SELECT * FROM Student WHERE GradeId=1 SELECT StudentName,Phone FROM Student WHERE Gra...
  • qq_36074113
  • qq_36074113
  • 2016年11月22日 17:18
  • 411

互联网汽车信息娱乐系统基础框架

在互联网思维大潮下,汽车行业也随之变革加入了互联网元素,称之为互联网汽车。目前成熟且已经量产面市的互联网汽车主要体现在它的车载设备(中控部分的信息娱乐系统)。这种车载互联体现主要在几个方面:TSP(T...
  • AixChina
  • AixChina
  • 2016年10月08日 16:26
  • 737

系统基础信息模块

1、shell查看系统内存 [root@localhost psutil-2.0.0]# free -m |grep Mem |awk '{print $2}'          #物理内存tota...
  • duo__o
  • duo__o
  • 2015年07月22日 11:59
  • 129

有关如何获取操作系统已经安装了杀毒软件的研究

      WindowXP SP2开始,提供了安全中心Security Center功能。用于管理系统中的安全设备,像杀毒软件、防火墙等。要想获取操作系统中是不是安装了杀毒软件,以及病毒库是否过期等...
  • FROZEN_PEAK
  • FROZEN_PEAK
  • 2010年03月26日 13:08
  • 290

系统相关信息和文件之时区相关实验(二)

1. 题目 Write a program to obtain the current time and print it using strftime, so that it looks l...
  • LoveStackover
  • LoveStackover
  • 2018年02月02日 13:55
  • 213

安装emacs全过程

  • hongzhang184
  • hongzhang184
  • 2009年08月16日 13:03
  • 793

python 获取目录下的文件信息

获取某个目录下深度为1的目录和文件的大小和最近的修改时间: for item in os.listdir(request_path): full_path = os.path.join(reque...
  • u011085172
  • u011085172
  • 2018年01月12日 15:45
  • 32

关于使用WMI获取杀毒软件信息

使用WMI获取杀毒软件信息时需要区分不同的操作系统,不然 会获取不到杀毒软件的信息。以下范例是针对Vista之后版本的: //利用WMI获取杀毒软件信息 #include "stdafx.h" #i...
  • nui111
  • nui111
  • 2015年02月25日 16:48
  • 893

系统相关功能开发(一)-获取磁盘信息

1.获取驱动器卷标 void CDiskInfoDlg::OnButtonGetvol() // 获取驱动器卷标 { UpdateData(TRUE); // 从控件中更新数据,更新要获...
  • greless
  • greless
  • 2017年08月25日 11:49
  • 91

iOS蓝牙开发(一):蓝牙相关基础知识

蓝牙常见词汇 MFI :苹果认证的设备 BLE :bluetooth low energy 说明蓝牙4.0设备明显的特点是耗电低 Central :中心,发起连接的设备 Peripheral :外设,...
  • u010731949
  • u010731949
  • 2017年06月30日 17:56
  • 383
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:系统相关信息和文件基础(一)
举报原因:
原因补充:

(最多只允许输入30个字)