mysu的实现

命令解释器:http://blog.csdn.net/qq_35256722/article/details/53316066

ls的实现: http://blog.csdn.net/qq_35256722/article/details/53323238

pwd和clear 的实现:http://blog.csdn.net/qq_35256722/article/details/53322604

su,切换目录的,首先切换目录 ,通过切换uid来实现的,切换uid后,我们就得到了一个表面看起来是切换的名字,但是你的gid还没切换过来,所以你还没有全部是那个用户。切换过的用户,一定是新的用户完全替换old用户,那么exec又来了。

   1.  struct passwd *p = getpwnam(s);  根据用户名得到更多信息,例如:id

   2. struct spwd * sp = getspnam(s); //从shadow里面读出加密的密码

   3.int tcgetattr(int fd, struct termios *termios_p);    把当前终端的变量信息,写到termios_p这个结构体中。

   4.char *crypt(const char *key, const char *salt);加密函数:key加密的密钥是  salt,

函数分析完了,那么大体思路,

    先从根据用户名获得当前用户的详细信息,从shadow里面读取该用户的密文,和用相同的密钥加密用户输入的密码后,作比较,相同开辟子进程,否则退出。

       1.比较密码:

         那么从shadow里面读取密文要分割用$分割,分割前两个$,一个加密方式,一个是加密的密钥,第三个那$是密文,用户输入的密码,在crypt函数的作用下,利用从shadow里面读取的密钥和加密方式,对用户所输入的密码加密,屏和系统的作比较。

        2.设置密码不可见

        在我们每次输入密码时,系统的密码总是什么都没有,所以我们在这里对用户输入的密码加以处理,nts.c_lflag    宏nts.c_lflag &= ~(ECHO|ICANON),将nts 的设置成不回显隐藏起来。

        3.输入完成后,设置回显

         在输入完成后,提取密码时,记得回显,这样子才能把密码读到,后续 可以正常工作。

    代码实现:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<unistd.h>
#include<sys/stat.h>
#include<pwd.h>
#include<shadow.h>
#include<termios.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("username error");
		exit(0);
	}
    struct spwd * sp = getspnam(s); //从shadow里面读出加密的密码
	if(sp == NULL)
	{
		printf("sp is error\n");
		exit(0);
	}
	printf("input  passwd:");
	fflush(stdout);
    struct termios ts,nts;
	tcgetattr(0,&ts); //把当前终端端口变量的值,写入ts这个结构体中,如果这些值其后被修改,你可能通过调用函数tcsetattr 来重新配置终端接口 
	nts = ts;
	// tcflag_t c_iflag;      /* input modes */
	nts.c_lflag &= ~(ECHO|ICANON); 
	c_iflag 的宏
	 //  ECHO   输入字符串的本地回显功能
	 // ICANON  启用标准输入处理

    /*TCSANOW  立即对值进行修改。
    TCSADRAIN  等当前的输出完成后再对值进行后,修改
    TCSAFLUSH 等当前的输出完成后再对值进行修改,但丢弃还未从read调用返回的当前可用的任何输入。*/
	tcsetattr(0,TCSANOW,&nts);  //密码隐藏
	char buff[128] = {0};
	int j = 0;
	char ch;
	while((ch=getchar()) !='\n')
	{
		buff[j++] = ch;
	}
	//fgets(buff,128,stdin);
	//buff[strlen(buff)-1] = 0;
	char lt[128]= {0};
	int i = 0;
	int num = 0;
	tcsetattr(0,TCSANOW,&ts); //密码回显
	for(;i < strlen(sp->sp_pwdp);i ++)
	{
		if(sp->sp_pwdp[i] == '$')
		{
			num ++;
			if(num ==3)
			{
				break;
			}
		}
		lt[i] = sp->sp_pwdp[i];
	}
	char *fg = crypt(buff,lt);  //加密函数
	if(strcmp(fg,sp->sp_pwdp) != 0)  //采用相同的密钥来加密,最后来比较密文就可以了
	{
		printf("fg  error\n");
		exit(0);
	}
	printf("succes!\n");

	
	pid_t pid = fork();
	assert(pid != -1);
	if(pid == 0)
	{
		setuid(p->pw_uid);
		setgid(p->pw_gid);
		setenv("HOME",p->pw_dir,1);//加上u+s 无论谁调起来,调起来就变成来root
		execl(p->pw_shell,p->pw_shell,(char*)0);//启动当前的终端
		perror("exec error");
		exit(0);
	}
	wait(NULL);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值