进程三(用户权限以及组权限、解释器文件、进程会计、进程时间、守护进程、系统日志的书写)

用户权限以及组权限

这三个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);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值