伪终端和交互式应用程序通信

【自动修改 Linux 用户密码】今天学习了一下如何使用伪终端和交互式应用程序通信
其实主要就是 openpty/forkpty/login_tty 三个函数。

以下内容为程序代码:
flw@debian:~/study$ ./tpasswd chinaunix perlchina
pty name: /dev/pts/1
Changing password for flw.
(当前)UNIX 口令:chinaunix
输入新的 UNIX 口令:perlchina
重新输入新的 UNIX 口令:perlchina
passwd:已成功更新密码
flw@debian:~/study$ ./tpasswd perlchina abcdef
pty name: /dev/pts/1
Changing password for flw.
(当前)UNIX 口令:perlchina
输入新的 UNIX 口令:abcdef
重新输入新的 UNIX 口令:abcdef
Bad: new password is too simple
输入新的 UNIX 口令:abcdef
重新输入新的 UNIX 口令:abcdef
Bad: new password is too simple
输入新的 UNIX 口令:abcdef
重新输入新的 UNIX 口令:abcdef
Bad: new password is too simple
passwd:鉴定令牌操作错误
passwd: password unchanged

[code]flw@debian:~/study$ cat tpasswd.c
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <sys/types.h>
# include <linux/limits.h>
# include <pty.h>
void do_passwd( int pty, const char *old_passwd, const char *new_passwd );
int main( int argc, char *argv[] )
{
int pty, slave;
char pty_name[PATH_MAX];
int ret;
pid_t child;
if ( argc < 3 ){
fprintf( stderr, "Usage: %s <old password> <new password>\n", argv[0] );
exit( EXIT_FAILURE );
}
ret = openpty( &pty, &slave, pty_name, NULL, NULL );
if ( ret == -1 ){
perror( "openpty" );
exit( EXIT_FAILURE );
}
child = fork();
if ( child == -1 ){
perror( "fork" );
exit( EXIT_FAILURE );
}
else if ( child == 0 ){
close( pty );
login_tty( slave );
execl( "/usr/bin/passwd", "passwd", NULL );
}
close( slave );
printf( "pty name: %s\n", pty_name );
do_passwd( pty, argv[1], argv[2] );
exit( EXIT_SUCCESS );
}
void do_passwd( int pty, const char *old_passwd, const char *new_passwd )
{
char buffer[80];
int ret;
fd_set reads;
int input_old_passwd = 0;
while(1){
FD_ZERO( &reads );
FD_SET( pty, &reads );
ret = select( pty+1, &reads, NULL, NULL, NULL );
if ( ret == -1 ){
perror( "select" );
break;
}
ret = read( pty, buffer, sizeof(buffer) );
if ( ret <= 0 ){
break;
}
write( fileno(stdout), buffer, ret );
fflush( stdout );
if ( buffer[ret-1] == '\n' ){
continue;
}
if ( !input_old_passwd ){
write( pty, old_passwd, strlen(old_passwd) );
write( pty, "\n", 1 );
write( fileno(stdout), old_passwd, strlen(old_passwd) );
input_old_passwd = 1;
}
else{
write( pty, new_passwd, strlen(new_passwd) );
write( pty, "\n", 1 );
write( fileno(stdout), new_passwd, strlen(new_passwd) );
}
}
return;
}
flw@debian:~/study$[/code]

2008-4-14 18:55LinuxKen

学习,代码写得好漂亮.:)

2008-4-14 18:58flw

因为 forkpty 实际上是 openpty/fork/login_tty 三个函数的组合,因此主函数也可以简写成这样:
[code]int main( int argc, char *argv[] )
{
int pty, slave;
char pty_name[PATH_MAX];
int ret;
pid_t child;
if ( argc < 3 ){
fprintf( stderr, "Usage: %s <old password> <new password>\n", argv[0] );
exit( EXIT_FAILURE );
}
child = forkpty( &pty, pty_name, NULL, NULL );
if ( child == -1 ){
perror( "fork" );
exit( EXIT_FAILURE );
}
else if ( child == 0 ){
execl( "/usr/bin/passwd", "passwd", NULL );
}
printf( "pty name: %s\n", pty_name );
do_passwd( pty, argv[1], argv[2] );
exit( EXIT_SUCCESS );
}[/code]

2008-4-14 19:03flw

如同标题所说,本程序旨在演示如何操纵伪终端和交互式应用程序通信,
因此对于 passwd 实用工具的输出解析并不多,只是做了一些简单的判断。
事实上,根据输入内容的不同,passwd 实用工具的输出信息多达十多种,PAM 的到来使得 passwd 的输出更加复杂,
因此如果希望能够自动控制 passwd,那么还是用 expect/perl 等工具较为方便。
另外需要说明的一点是,自动控制交互式应用程序运行时,尽量运行其英文版本,这样信息会规范一些从而有利于捕获并匹配。
中文或者其它语种的信息不仅要考虑到编码的问题,而且信息用语经常会有变化。
通过设定环境变量 LANG=C,可以使 passwd 实用工具的输出变成英文。
[ 本帖最后由 flw 于 2008-4-14 19:06 编辑 ]

2008-4-15 11:26Sorehead

很少用到这方面的东西,学习。

2008-4-15 11:28system888net

顶...

本篇文章来自于:百家学院 (http://www.9php.com),转载请保留此行

原文地址:https://www.cnblogs.com/cute/p/1984922.html