| |
The Unix Password-Changing Script
0 #!/usr/bin/perl -T
1
2 # preliminaries to satisfy taint checks
3 $ENV{PATH} = '/bin:/usr/bin';
4 $ENV{IFS} = '';
5
6 # Prevent buffering problems
7 $| = 1;
8
9 use CGI qw/:standard :html3/;
10
11 print header,
12 start_html(-title=>'Change Unix Password',
13 -bgcolor=>'white'),
14 h1('Change your Unix password');
15
16 import_names('Q');
17
18 TRY: {
19 last TRY unless $Q::user;
20 my ($rv,$msg) = check_consistency();
21 do_error($msg),last TRY unless $rv;
22
23 # Change the password, after temporarily turning off
24 # an annoying (and irrelevant) error message from su
25 open(SAVERR, ">&STDERR");
26 open(STDERR, ">/dev/null");
27 ($rv,$msg) = set_passwd($Q::user,$Q::old,$Q::new1);
28 open(STDERR, ">&SAVERR");
29 do_error($msg),last TRY unless $rv;
30
31 print $msg;
32 $OK++;
33 }
34
35 create_form() unless $OK;
36
37 print
38 p,
39 a({href=>"$Q::referer" || referer() },"[ EXIT SCRIPT ]");
40 hr,
41 a({href=>'/'},'Home page'),
42 end_html;
43
44 sub check_consistency {
45 return (undef,'Please fill in the user name field.') unless $Q::user;
46 return (undef,'Please fill in the old password field.') unless $Q::old;
47 return (undef,'Please fill in the new password fields.') unless $Q::new1 && $Q::new2;
48 return (undef,"New password fields don't match.") unless $Q::new1 eq $Q::new2;
49 return (undef,"Suspicious user name $Q::user.") unless $Q::user=~/^\w{3,8}$/;
50 return (undef,'Suspiciously long old password.') unless length($Q::old) <= 30;
51 return (undef,'Suspiciously long new password.') unless length($Q::new1) <= 30;
52 my $uid = (getpwnam($Q::user))[2];
53 return (undef,"Unknown user name $Q::user.") if $uid eq '';
54 return (undef,"Can't use this script to set root password.") if $uid == 0;
55 return 1;
56 }
57
58 sub set_passwd ($$$) {
59 require "chat2.pl";
60 my $TIMEOUT = 2;
61 my $PASSWD = "/usr/bin/passwd";
62 my $SU = '/bin/su';
63
64 my ($user,$old,$new) = @_;
65
66 my $h = chat::open_proc($SU,'-c',$PASSWD,$user)
67 || return (undef,"Couldn't open $SU -c $PASSWD: $!");
68
69 # wait for su to prompt for password
70 my $rv = chat::expect($h,$TIMEOUT,
71 'Password:' => "'ok'",
72 'user \w+ does not exist' => "'unknown user'"
73 );
74 $rv || return (undef,"Didn't get su password prompt.");
75 $rv eq 'unknown user' && return (undef,"User $user unknown.");
76 chat::print($h, "$old\n");
77
78 # wait for passwd to prompt for old password
79 $rv = chat::expect($h,$TIMEOUT,
80 'Enter old password:' => "'ok'",
81 'incorrect password' => "'not ok'");
82 $rv || return (undef, "Didn't get prompt for old password.");
83 $rv eq 'not ok' && return (undef,"Old password is incorrect.");
84
85 # print old password
86 chat::print($h, "$old\n");
87 $rv = chat::expect($h,$TIMEOUT,
88 'Enter new password: ' => "'ok'",
89 'Illegal' => "'not ok'");
90 $rv || return (undef,"Timed out without seeing prompt for new password.");
91 $rv eq 'not ok' && return (undef,"Old password is incorrect.");
92
93 # print new password
94 chat::print($h,"$new\n");
95 ($rv,$msg) = chat::expect($h,$TIMEOUT,
96 'Re-type new password: ' => "'ok'",
97 '([\s\S]+)Enter new password:' => "('rejected',\$1)"
98 );
99 $rv || return (undef,"Timed out without seeing 2d prompt for new password.");
100 $rv eq 'rejected' && return (undef,$msg);
101
102 # reconfirm password
103 chat::print($h, "$new\n");
104 $rv = chat::expect($h,$TIMEOUT,
105 'Password changed' => "'ok'");
106 $rv || return (undef,"Password program failed at very end.");
107 chat::close($h);
108
109 return (1,"Password changed successfully for $user.");
110 }
111
112 sub create_form {
113 print
114 start_form,
115 table(
116 TR({align=>RIGHT},
117 th('User name'),
118 td(textfield(-name=>'user')),
119 th('Old password'),
120 td(password_field(-name=>'old'))),
121 TR({align=>RIGHT},
122 th('New password'),
123 td(password_field(-name=>'new1')),
124 th('Confirm new password'),
125 td(password_field(-name=>'new2'))),
126 ),
127 hidden(-name=>'referer',-value=>referer()),
128 submit('Change Password'),
129 end_form;
130 }
131
132 sub do_error ($) {
133 print font({-color=>'red',-size=>'+1'},
134 b('Error:'),shift," Password not changed.");
135 }
|