用户权限以及组权限
这三个UID分别是RUID(Real UID,实际用户ID)、EUID(Effective UID,有效用户ID)、
SUID(Saved Set-user-ID,保存的设置用户ID)。
gid同样的有三个
可以没有SUID
鉴定权限的时候看的是effective uid
passwd的执行
一个文件有u+s权限的时候表示,当别的用户在调用这个可执行文件的时候,它的身份会切换到当前二进制文件的user的身份来执行。如果是g+s权限的话,意味着不管任何用户来调用这个可执行的二进制文件,就会切换到这个二进制文件的同组用户的身份来执行,
exec来鉴定权限,发现当前的passwd是一个u+s权限,所以到此为止,身份就不再是之前的r、e、s,一般情况下会变成r、0、0.鉴定权限的时候查看的是e,所以当我们在执行passwd的时候,是在以root权限在运行。
关键在于passwd这个文件是有u+s权限的(g+s差不多原理)
不用切换身份回去,结束这个passwd这个进程就会消亡了,所以不需要
那么shell的身份是从哪里来的?
当前机器环境中产生的第一个进程是init进程
,当init进程产生的时候是root权限
然后fork+exec产生一个进程叫做getey进程
getey进程产生以后,会告诉你,请输入login name
输入名字,然后在exec,getey进程就不存在了,就会变成一个叫做login进程
login进程阶段提示你,输入password,然后输入密码,在此之前所有进程的权限都是root
在root下,可以拿到passwd下的所有信息,然后就可以进行校验,成功以后就会fork+exec产生一个子进程
shell,这个时候shell的身份就是r、e、s
相关函数;
getuid();
geteuid();
#include <unistd.h>
#include <sys/types.h>
uid_t getuid(void);
uid_t geteuid(void);
DESCRIPTION
getuid() returns the real user ID of the calling process.
geteuid() returns the effective user ID of the calling process.
getgid();
getegid();
#include <unistd.h>
#include <sys/types.h>
gid_t getgid(void);
gid_t getegid(void);
DESCRIPTION
getgid() returns the real group ID of the calling process.
getegid() returns the effective group ID of the calling process.
setuid();
---------- setuid - set user identity
#include <sys/types.h>
#include <unistd.h>
int setuid(uid_t uid);
setgid();
------------------------- set group identity
#include <sys/types.h>
#include <unistd.h>
int setgid(gid_t gid);
setreuid();
setregid();//这两个函数是一个原子化的一个东西
---------setreuid, setregid - set real and/or effective user or group ID
#include <sys/types.h>
#include <unistd.h>
int setreuid(uid_t ruid, uid_t euid);
int setregid(gid_t rgid, gid_t egid);
seteuid();
setegid();
seteuid, setegid - set effective user or group ID
#include <sys/types.h>
#include <unistd.h>
int seteuid(uid_t euid);
int setegid(gid_t egid);
例子:以某个uid来执行一个命令
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
pid_t pid;
if(argc < 3)
{
fprintf(stderr,"Usage.......\n");
}
pid=fork();
if(pid<0)
{
perror("fork()");
exit(1);
}
if(pid==0)
{
setuid(atoi(argv[1]));
execvp(argv[2],argv+2);
perror("execvp");
exit(1);
}
wait(NULL);
exit(0);
}
在普通权限下是无法使用的,得换到root用户下
首先chown root mysu
然后chmod u+s mysu
最后运行./mysu 0 cat/etc/shadow
就可以看到文件内容
解释器文件
解释器文件就是脚本文件
最复杂的调用就是exec
脚本文件:
例子(t.sh(名字后缀可以随便取)):
#!/bin/bash
ls
whoami
cat /etc/shadow
ps
#!是脚本文件的标记,当shell看到这个标记的时候会把/bin/bash这个解释器装载进来
用这个解释器解释整个文件,由于脚本标识第一行开头是#号,当作注释,所以不解释
将上面的bash换成cat后,在运行整个脚本,有如下结果就相当于cat ./t.sh
7、system();//相当于fork+exec+wait的简单封装
------------------------ execute a shell command
#include <stdlib.h>
int system(const char *command);
小例子:
#include <stdio.h>
#include <stdlib.h>
int main()
{
system("date +%s > /tmp/out");
exit(0);
}
相当于下面的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
fflush(NULL);
pid=fork();
if(pid<0)
{
perror("fork()");
exit(1);
}
if(pid==0)
{
execl("/bin/sh","sh","-c","date +%s",NULL);
perror("execl()");
exit(1);
}
wait(NULL);
exit(0);
}
进程会计
相关函数:
acct();了解
#include <unistd.h>
int acct(const char filename);
参数是一个文件,这个文件的作用是:当有进程消亡的时候,就会把这个进程所相关的属性
填到这个文件中,但是这个函数不是一种标准
struct acct {
char ac_flag; / Accounting flags /
u_int16_t ac_uid; / Accounting user ID /
u_int16_t ac_gid; / Accounting group ID /
u_int16_t ac_tty; / Controlling terminal /
u_int32_t ac_btime; / Process creation time
(seconds since the Epoch) /
comp_t ac_utime; / User CPU time /
comp_t ac_stime; / System CPU time /
comp_t ac_etime; / Elapsed time /
comp_t ac_mem; / Average memory usage (kB) /
comp_t ac_io; / Characters transferred (unused) /
comp_t ac_rw; / Blocks read or written (unused) /
comp_t ac_minflt; / Minor page faults /
comp_t ac_majflt; / Major page faults /
comp_t ac_swaps; / Number of swaps (unused) /
u_int32_t ac_exitcode; / Process termination status
(see wait(2)) /
char ac_comm[ACCT_COMM+1];
/ Command name (basename of last
executed command; null-terminated) /
char ac_pad[X]; / padding bytes */
};
进程时间
times();
---------- get process times
#include <sys/times.h>
clock_t times(struct tms *buf);
struct tms {
clock_t tms_utime; /* user time /
clock_t tms_stime; / system time /
clock_t tms_cutime; / user time of children /
clock_t tms_cstime; / system time of children */
};
守护进程
也有叫做精灵进程
需要一直在运行的程序
有个进程一直在运行
守护进程脱离控制终端存在
一般是一个会话的leader
进程组的leader
服务器一直在跑
会话:session
前台进程组:只能有一个或是没有,能够接收
后台进程组:
前台进程组可以接收标准的输入,或者是可以使用标准的输出,但是后台进程组不可以
为什么区分前台后台?
如果有两个进程组作为前台进程组在运行,然后在键盘上输入的内容就不知道给的是哪一个。
如果我们要将一个标准输入的内容给到后台进程组的话,那么这个做法将会杀掉后台正在运行的进程
session标识:sid
终端:
相关函数:
setsid();
------------------------ creates a session and sets the process group ID
#include <unistd.h>
pid_t setsid(void);
setsid() creates a new session if the calling process is not a process group leader.The calling process also becomes the process group leader of a new process group in the session.
//如果当前调用它的那个进程不是一个进程组的leader,那么才会创建出一个会话
一个进程产生子进程,子进程天生就是和父进程同组的,而且父进程是leader
所以可以知道setsid这个函数不能是父进程来调用,只能是子进程调用
这个特点就是一个守护进程的特点:
守护进程脱离控制终端
父进程是init进程
并且pid pgid sid是一样的
getpgrp();
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid);
pid_t getpgid(pid_t pid);
pid_t getpgrp(void); /* POSIX.1 version */返回当前进程所在的进程组的id
pid_t getpgrp(pid_t pid); /* BSD version */查看指定进程的所在的进程组是哪一个?
setpgid();
getpgid();
守护进程:
初始代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FILENAME "/tmp/out"
static int deamonize(void)
{
int fd;
pid_t pid;
pid=fork();
if(pid<0)
{
perror("fork()");
return -1;
}
if(pid>0) //parent
{
exit(0);
}
fd=open("/dev/null",O_RDWR);
if(fd<0)
{
perror("open()");
return -1;
}
dup2(fd,0);
dup2(fd,1);
dup2(fd,2);
if(fd>2)
{
close(fd);
}
setsid();
chdir("/");
umask(0);
return 0;
}
int main()
{
if(deamonize())
exit(1);
int i;
FILE *fp;
fp=fopen(FILENAME,"w");
if(fp==NULL)
{
perror("fopen()");
exit(1);
}
for(i=0;;i++)
{
fprintf(fp,"%d\n",i);
fflush(fp);
sleep(1);
}
exit(0);
}
系统日志的书写
每一个应用程序都有必要写一个系统日志,
syslogd服务
所有要写系统日志的内容都要把自己要写的系统日志提交给syslogd这项服务
这项服务在去统一的来进行系统日志的写法,所以只需要按照一定的函数接口把要写的内容提交给syslogd,由这个服务去写就可以了
相关函数
openlog();syslog();closelog();
#include <syslog.h>
void openlog(const char *ident, int option, int facility);//相当于关联
第一个参数:给出的一个字段
第二个参数:有无特殊要求(比较多的使用LOG_PID)
第三个参数:来源,从man手册上选择
void syslog(int priority, const char *format, …);//提交内容
void closelog(void);
加上日志文件的守护进程代码:
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>
#define FILENAME "/tmp/out"
static int deamonize(void)
{
int fd;
pid_t pid;
pid=fork();
if(pid<0)
{
return -1;
}
if(pid>0) //parent
{
exit(0);
}
fd=open("/dev/null",O_RDWR);
if(fd<0)
{
return -1;
}
dup2(fd,0);
dup2(fd,1);
dup2(fd,2);
if(fd>2)
{
close(fd);
}
setsid();
chdir("/");
umask(0);
return 0;
}
int main()
{
openlog("mydeamon",LOG_PID,LOG_DAEMON);
if(deamonize())
{
syslog(LOG_ERR,"deamonize() failed!");
exit(1);
}
else
{
syslog(LOG_INFO,"deamonize() successded!");
}
int i;
FILE *fp;
fp=fopen(FILENAME,"w");
if(fp==NULL)
{
syslog(LOG_ERR,"fopen:%s",strerror(errno));
exit(1);
}
syslog(LOG_INFO,"%s was open",FILENAME);
for(i=0;;i++)
{
fprintf(fp,"%d\n",i);
fflush(fp);
syslog(LOG_DEBUG,"%d is printed",i);
sleep(1);
}
fclose(fp);
closelog();
exit(0);
}