1. 程式人生 > >linux命令:su的實現

linux命令:su的實現

使用su命令可以切換使用者,不加引數時預設切換到root使用者。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include <shadow.h>
#include <pwd.h>
#include <sys/types.h>
#include<termios.h>
#include<errno.h>


int main(int argc, char *argv[])
{
	char *user = "root";
	if(argv[1] != NULL)
	{
		user = argv[1];
	}

	printf("Password: ");
	fflush(stdout);
	
/////////////////////////////////
/////設定終端不回顯的程式碼
	struct termios oldflag, newflag;//儲存原有終端屬性和新設定的終端屬性

	tcgetattr(fileno(stdin), &oldflag);//獲得終端原有屬性並儲存在結構體oldflag
	newflag = oldflag;
	newflag.c_lflag &= ~ECHO;
	newflag.c_lflag |= ECHONL;
	if(tcsetattr(fileno(stdin), TCSANOW, &newflag) != 0)
	{
		perror("tcsetattr");
		return -1;
	}

	//////////////////////
	char passwd[128] = {0}; 
	fgets(passwd, 128, stdin);
	passwd[strlen(passwd) - 1] = 0;
	/////////////////////////////////
	if(tcsetattr(fileno(stdin), TCSANOW, &oldflag) != 0)
	{
		perror("tcsetattr");
		return -1;
	}
	////////////////////////////////
	//根據使用者名稱獲取系統儲存使用者的密碼資訊
	struct spwd *pwd = getspnam(user);
	assert(pwd != NULL);
//////////////////////////////////////
//根據使用者密碼資訊獲取加密演算法iD以及金鑰
	char *p = pwd->sp_pwdp;
	char salt[128] = {0};
	int count = 0, i = 0;
	while(1)
	{
		salt[i] = *p;
		if(salt[i] == '$')
		{
			count++;
		}

		if(count == 3)
		{
			break;
		}

		i++,p++;
	}
////////////////////////////

	//根據獲取的演算法ID和金鑰,對輸入的明文加密
    char *s = crypt(passwd, salt);

	if(strcmp(s, pwd->sp_pwdp) != 0)
	{
		printf("password is error\n");
		exit(0);
	}

	pid_t n = fork();
	assert(n != -1);

	if(n == 0)
	{
		struct passwd *pw = getpwnam(user);
		assert(pw != NULL);
	
		setenv("HOME", pw->pw_dir, 1); // 設定環境變數
		setuid(pw->pw_uid);     // 修改使用者
		execl(pw->pw_shell, pw->pw_shell, (char*)0);

		printf("su is fail\n");
		exit(0);
	}
	else
	{
		wait(NULL);
	}
}

 

系統中的su命令,在你輸入密碼時不會回顯,這樣更加安全,

下面是實現程式碼:

#include<termios.h>
#include<errno.h>


/////設定終端不回顯的程式碼
	struct termios oldflag, newflag;//儲存原有終端屬性和新設定的終端屬性

	tcgetattr(fileno(stdin), &oldflag);//獲得終端原有屬性並儲存在結構體oldflag
	newflag = oldflag;
	newflag.c_lflag &= ~ECHO;
	newflag.c_lflag |= ECHONL;
	if(tcsetattr(fileno(stdin), TCSANOW, &newflag) != 0)
	{
		perror("tcsetattr");
		return -1;
	}

	//////////////////////
	char passwd[128] = {0}; 
	fgets(passwd, 128, stdin);
	passwd[strlen(passwd) - 1] = 0;
	/////////////////////////////////
	if(tcsetattr(fileno(stdin), TCSANOW, &oldflag) != 0)
	{
		perror("tcsetattr");
		return -1;
	}
	////////////////////////////////

在該命令中,我們要判斷使用者輸入的密碼是否正確,在判斷密碼正確後,要重新設定環境變數,並且修改使用者,將終端切換到當前新使用者的預設終端下。這才真正完成了su命令。

執行結果如下: