模拟shell实现su命令(切换用户)

来源:互联网 发布:db2 sql获取当前时间 编辑:程序博客网 时间:2024/06/06 02:51

在这里给大家推荐一本书《Linux程序设计 第4版》 里面有需要下面用到的几个函数

本篇博文和上篇博文实现mybash所用的到的函数一样


1、uid_t getuid(void)函数取得执行目前进程有效的用户识别码。有效的用户识别码用来决定进程执行的权限,改变此值,进程可以获得额外的权限。

2、struct passwd *getpwuid(uid_t uid)函数通过用户的uid查找用户的passwd数据。如果出错时,它们都返回一个空指针并设置errno的值,用户可以根据perror函数查看出错的信息。

3、struct passwd *getpwnam(const char *name)函数获取用户登录相关信息,其中name是当前登录的用户名。若成功,返回指针;若出错或者达到文件尾端,返回NULL。

4、int hostname(struct utsname *name)函数把主机信息写入name参数指向的结构体中。

5、char *getcwd(char *buf, size_t size)函数把当前目录的绝对地址保存到 buff中,buff 的大小为 size。如果 size太小无法保存该地址,返回 NULL 并设置 errno 为 ERANGE。可以采取令 buff 为 NULL并使 size 为负值来使 getcwd 调用 malloc 动态给 buff 分配,但是这种情况要特别注意使用后释放缓冲以防止内存泄漏。 


需注意的是:

1、使用函数uname()得到的主机名“.”之后的部分是多余的,需要进行额外的处理。

2、getcwd()函数得到的是函数的绝对路径,在显示的信息中只需要当前目录的名字,需要进行处理。


代码实现:

#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <unistd.h>#include <pwd.h>#include <shadow.h>#include <termios.h>#include <string.h>int main(int argc,char *argv[]){char *s = "root";if(argc == 2){s = argv[1];}struct passwd *p = getpwnam(s);if( p == NULL){perror("su error:");exit(0);}struct spwd *sp = getspnam(s); //通过/etc/shadow获取密码if(sp == NULL){perror("su spnam error");}//printf("mima:%s\n",sp->sp_pwdp);char sl[256] = {0};//存储加密方法和密钥int i = 0;int num = 0;char *sps = sp->sp_pwdp;//$$$1加密方法 2密钥 3密码对应的密文while(sps != "\0"){if(*sps == '$'){num++;if(num == 3){break;}}sl[i++] = *sps;sps++;}//printf("\nsl=%s\n",sl);printf("passwd:");fflush(stdout);struct termios ts,newts;//终端属性tcgetattr(0,&ts);//获取终端属性newts = ts;newts.c_lflag &= ~(ECHO | ICANON); //本地属性回显 和 标准模式tcsetattr(0,TCSANOW,&newts);//设置新属性char buff[128] = {0};//fgets(buff,128,stdin);//buff[strlen(buff)-1] = 0;int ch = 0;i = 0;while((ch = getchar()) != '\n'){buff[i++] = ch;printf("*");fflush(stdout);}tcsetattr(0,TCSANOW,&ts);//还原终端属性char *newsp = crypt(buff,sl);//对输入的明文密码加钥if(strcmp(newsp,sp->sp_pwdp) != 0)//比较密码是否正确{printf("mima error\n");exit(0);}printf("\n");//printf("success\n");pid_t pid = fork();//产生子进程并替换长该用户的默认shellassert(pid != -1);if(pid == 0){setgid(p->pw_gid);setuid(p->pw_uid);setenv("HOME",p->pw_dir,1);execl(p->pw_shell,p->pw_shell,(char *)0);perror("execl error");exit(0);}wait(NULL);exit(0);}













原创粉丝点击