C语言实现su命令
来源:互联网 发布:固定资产管理 源码 编辑:程序博客网 时间:2024/06/08 10:07
su命令的功能为切换用户,首先看一下系统su命令的效果:
su命令为:su+用户名,没有输入参数时默认为root用户。由普通用户切换到root用户时,需要输入密码,由root用户切换到普通用户时不需要输入密码,而且密码输入时在屏幕上是不显示的。根据这些特点逐步实现速命令。
1、密码不显示设置
通过设置termios类型的数据结构中的值和使用一小组函数调用,就可以对终端接口进行控制。termios数据结构和相关的函数调用都定义在头文件termios.h中。
可以被调整来影响终端的值按照不同的模式被分成:
输入模式、输出模式、控制模式、本地模式和特殊控制字符。
最小的termios结构的定义如下,结构体成员的名称与上面列出的5种参数类型相对应:
#include<termios.h>struct termios{tcflag_t c_iflag;tcflag_t c_oflag;tcflag_t c_cflag;tcflag_t c_lflag;cc_t c_cc[NCCS];};函数tcgetattr初始化与一个终端对应的termios结构,把当前的终端接口变量的值写入p指向的结构:
int tcgetattr(int fd,struct termios *p);
函数tcsetattr来重新配置终端接口:int tcsetattr(int fd,int actions,const struct termios *p);
参数actions控制修改方式,共有3种修改方式:
TCSANOW:立刻对值进行修改;
TCSADRAIN:等当前的输出完成后再对值进行修改;
TCSAFLUSH:等当前的输出完成后再对值进行修改,但丢弃还未从read调用返回的当前可用的任何输入。
本地模式控制终端的各种特性,c_lflag成员中最重要的两个宏是ECHO和ICANON。ECHO 启用输入字符的本地回显功能,ICANON 启用标准输入处理。
struct termios old, new;tcgetattr(0, &old);new = old;new.c_lflag &= ~ECHO;//设置成不显示tcsetattr(0, TCSANOW, &new);fgets(passwd, 128, stdin);tcsetattr(0, TCSANOW, &old);//密码输入完成后要立即设回回显模式passwd[strlen(passwd) - 1] = 0;printf("\n");
这样我们就解决了密码不显示的问题。
那么,密码输入进去以后首先要判断密码是否正确,这里要用到crypt()函数。其原型为char *crypt(const char*key,const char*salt). key是我们传入的明文,salt是我们指定用来加密的密钥,返回值为加密后的密文。那这里关键是要知道salt,那就要用到getspnam函数。
getspnam()函数可以访问shadow口令,其原型为struct spwd *getspnam(const char*name),其返回值为spwd结构体指针。spwd结构部分如下:
struct spwd{ char *sp_namp;//用户登录名 char *sp_pwdp;//加密口令}要注意,这里只有root用户才可以调用该函数,所以要用chmod a+s su命令加上s权限,使得不管谁执行起来都具有所有者权限。
接下来就可以比较输入的密码是否正确,如果不正确直接退出,如果正确又会执行什么操作呢?先看一下系统是怎么做的。
通过上图可以发现,我们实现su命令就是如下过程:
整体代码如下:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <assert.h>#include <sys/types.h>#include <pwd.h>#include <shadow.h>#include <termios.h>int main(int argc, char *argv[]){char *user = "root";if(argv[1] != NULL){user = argv[1];}//input passwordprintf("Passwd: ");fflush(stdout);char passwd[128] = {0};struct termios old, new;tcgetattr(0, &old);new = old;new.c_lflag &= ~ECHO;tcsetattr(0, TCSANOW, &new);fgets(passwd, 128, stdin);tcsetattr(0, TCSANOW, &old);passwd[strlen(passwd) - 1] = 0;printf("\n");struct spwd *sp = getspnam(user);assert(sp != NULL);char salt[128] = {0};int i = 0, count = 0;for(; sp->sp_pwdp[i] != 0; ++i){salt[i] = sp->sp_pwdp[i];if(salt[i] == '$'){count++;if(count == 3){break;}}}char *p = crypt(passwd, salt);assert(p != NULL);if(strcmp(p, sp->sp_pwdp) != 0){printf("passwd error\n");exit(0);}pid_t pid = fork();assert(pid != -1);if(pid == 0){struct passwd *pw = getpwnam(user);assert(pw != NULL);setuid(pw->pw_uid);setenv("HOME", pw->pw_dir, 1);execl(pw->pw_shell, pw->pw_shell, (char*)0);printf("error\n");exit(0);}else{wait(NULL);}}
- C语言实现su命令
- C语言实现ls命令
- C语言实现ps命令
- C语言实现tree命令
- su -c命令与环境变量的困惑
- su,su-,sudo命令
- Linux下su命令的实现
- 模拟shell实现su命令(切换用户)
- su命令
- su 命令
- C语言实现ICMP协议Ping命令
- 命令ls的C语言实现
- Linux Shell命令的C语言实现
- linux 命令c语言代码实现
- C语言实现ICMP协议Ping命令
- linux c语言实现 执行shell命令
- 用C语言实现Ping命令
- C语言实现Linux cp命令
- HDPCD-Java-复习笔记(12)
- OpenCV 自学笔记30. 简单轮廓匹配的小例子
- 第五周 项目3
- C# SATO条码打印机(CT408i)
- 利用jquery.fly实现仿淘宝购物车飞入特效
- C语言实现su命令
- 【数学知识整理】
- 制作一个APP(持续更新)
- Ubuntu下的Notepad++——Notepadqq
- 名称:非递归遍历后序二叉树
- maven使用以及遇到的一些问题记录
- java文件传输基础:序列化和反序列化ObjectInputStream/ObjectOutputStream
- 以bat或.sh方式启动tomcat出现闪退
- Tunnel Warfare