【自动修改 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
# include
# include
# include
# include
# include
# include
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 \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 );//把slave复制到0,1,2,并且关闭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
\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]
如同标题所说,本程序旨在演示如何操纵伪终端和交互式应用程序通信,
因此对于 passwd 实用工具的输出解析并不多,只是做了一些简单的判断。
事实上,根据输入内容的不同,passwd 实用工具的输出信息多达十多种,PAM 的到来使得 passwd 的输出更加复杂,
因此如果希望能够自动控制 passwd,那么还是用 expect/perl 等工具较为方便。
另外需要说明的一点是,自动控制交互式应用程序运行时,尽量运行其英文版本,这样信息会规范一些从而有利于捕获并匹配。
中文或者其它语种的信息不仅要考虑到编码的问题,而且信息用语经常会有变化。
通过设定环境变量 LANG=C,可以使 passwd 实用工具的输出变成英文。
阅读(2579) | 评论(0) | 转发(0) |