Thanks to everyone who responded. I got several ideas but by far, the
consensus is to use a program called expect. I found expect-5.30 at
http://expect.nist.gov
Expect uses TCL/TK and uses a syntax something expect, send, expect,
send...
I haven't used it yet but it looks trivially easy.
Other people sent in nice ideas and scripts too. I'll include them
below.
***************from Tom Payerle:
#!/bin/sh
USER=$1
NEWPASS=$2
expect -c "spawn \"passwd\" \"${USER}\"" \
-c 'expect "word:"' -c "send \"${NEWPWD}\r\"" \
-c 'expect "gain:"' -c "send \"${NEWPWD}\r\"" -c "interact"
****************from Alan Davis
You might also take a look at the zuausr from the U of Alaska :
ftp://raven.alaska.edu/pub/randy/zuausr/
**************from Alan Angulo
#!/usr/local/bin/perl
# By Alan Angulo
# May 13, 1997
B
# Get passwd
srand;
while($pline = <STDIN>) {
($username,$password)=split(/:/,$pline);
chop ($password);
if (length($password) < 6) {
print "PASSWORD LESS THAN 6 CHARACTERS - TRY AGAIN.\n";
$epasswd="PASSWORD WAS LESS THAN 6 CHARACTERS";
next;
}
if (length($password) > 8) {
$password = substr($password,0,8);
}
$salt = pack("CC",valid_salt_char(),valid_salt_char());
$crypt_passwd = crypt($password,$salt);
print "$username:$password:$crypt_passwd\n";
}
# SUBROUTINES
#Returns a random character from the set [./0-9A-Za-z]
#Used to generate salt chahacters
sub valid_salt_char
{
$s1=int(rand(76) +46);
if ( (($s1 >= 58) && ($s1 <= 64)) || (($s1 >= 91) && ($s1 <= 96)) )
{
#Jump to a valid set instead of generating again
return ($s1 += 8);
}
return $s1;
}
#END-----------------------------------------------------------------
Save this code as makepasswd.
Create a text file all user/password information with the format:
login:password
use it as: ./makepasswd < user_password.txt > encrypted_password.txt
encrypted_password.txt will contain login:password:encrypted_password.
Once you have the this info, the rest is just... you know... stuff.
*******************from Lars Bro
>From lbr_at_nettest.dk Thu Sep 16 05:18:09 1999
Hi,
Some commands are intended to be 'interactive'. Such commands read and wr=
ite
'/dev/tty' instead of standard input and standard output. One of the
benefits
is that these commands can make their own tty settings just like the pass=
wd
command that disables echo when the user types the password. If the comma=
nd
were
polite, it might have asked if stdin were a tty and then run interactivel=
y,
otherwise in batch....... but
for the sake of those programs where we cannot just redirect something in=
to
standard input, we have the 'pseudo ttys'. A pseudo tty is a terminal dev=
ice
in /dev. It is not connected to a terminal but to a process. Look at the =
C
example
below:
This program: (mypasswd.c)
#include <fcntl.h>
main()
{
char buf[1024];
int fd;
int n;
fd =3D open("/dev/tty", O_RDWR);
for(;;) {
n=3Dread(fd, buf, sizeof(buf));
if (n <=3D0 )
break;
buf[n]=3D0;
write(fd, buf, n);
}
}
reads from /dev/tty and prints the same back to /dev/tty again. If you ru=
n
it, it will
work exactly as 'cat', it echoes everything back that you write. But no
matter how you
try to redirect or pipe input to it, it communicates with your terminal
only.
The next program makes a pseudo-tty (the terminal device I mentioned befo=
re)
and creates
a new process that runs the command "mypasswd".
main()
{
char buf[1024];
int n;
int master;
char name[64];
int st;
if (!forkpty(&master, name, (void*)0, (void*)0)) {
execl("./mypasswd", "mypasswd", "user", 0);
exit(1);
} else {
write(master, "Hello, World\n", 13);
n=3Dread(master, buf, sizeof(buf));
write(1,buf, n);
}
wait(&st);
}
This program calls forkpty() which - if returning 0 is the child process =
and
immediately
starts the program mypasswd above. The parent proces writes "Hello World"=
to
the pseudo
terminal which is seen by "mypasswd" and returned. So, now we can make
programs that talk
to other programs by means of pseudo terminals.
The program below (run as root) successfully changed my password to "lars=
.."
main()
{
char buf[1024];
int n;
int master;
char name[64];
int st;
if (!forkpty(&master, name, (void*)0, (void*)0)) {
execl("/usr/bin/passwd", "passwd", "lbr", 0);
exit(1);
} else {
n=3Dread(master, buf, sizeof(buf));
write(1,buf, n);
write(master, "lars..\n", 7);
n=3Dread(master, buf, sizeof(buf));
write(1,buf, n);
write(master, "lars..\n", 7);
n=3Dread(master, buf, sizeof(buf));
write(1,buf, n);
}
wait(&st);
}
This is fairly easy provided you can program C.
For those people that dont program C, there is something called "expect".=
It
is a
program that does exactly the above, only its documentation is a 500+ pag=
es
book and it
needs its own mail group and news group. Basically, you write 'expect'
scripts
that contain information like this:
run this program
when it says ...
you say ...
and when it says
you say ...
and so on.
It is very popular and very commonly used (=3Dreliable). I bet you get a =
lot
of references
to it. But you can also do with 22 lines of C.
**************from Rich Lafferty rich_at_alcor.concordia.ca
You need to fool passwd into thinking it's not on a tty. Something
like this (which originally changed unix and AppleShare passwords;
I've cut out the appleshare part.)
/*
* passwd.wrapper.c -- change Unix passwords, using passwd(1)
* for the latter (to avoid bypassing PAM)
*
* 1999/08/25 Rich Lafferty
* based on N. Dean Pentcheff's SMB-password changer
*
* This program is free software; you can redistribute it and/or
* modify it under the same terms as Perl (see
http://www.perl.com).
*
* To work, must be installed SUID-root.
* If called interactively (from a tty), is slightly verbose, and uses
* the standard getpass() routine to query for and confirm a password.
* If called noninteractively, expects the password (once) on stdin.
*/
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pwd.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
/* Path to unix passwd(1) program */
#define PASSWD "/usr/bin/passwd.real"
#define PROMPT1 "New password: "
#define PROMPT2 "Retype new password: "
#define STRLEN 1024
int main (int argc, char *argv[]) {
int fd;
int status;
struct passwd *pwentry;
char new[STRLEN];
char cmd[STRLEN];
char *cp;
FILE *cmdpipe;
FILE *mystderr;
uid_t origuid;
/* get username and home directory */
if (argc == 1) {
if ((pwentry = getpwuid(getuid())) == NULL) {
fprintf(stderr, "Failed getting pw entry for UID=%d, exiting...\n",
getuid());
exit(1);
}
} else {
if ((pwentry = getpwnam(argv[1])) == NULL) {
fprintf(stderr, "Failed getting pw entry for '%s', exiting...\n",
argv[1]);
exit(1);
}
/* Only root can change other people's passwords. */
if (getuid() != 0) {
fprintf(stderr, "Your magic is not strong enough to perform on other people's passwords.\n");
exit(1);
}
}
fprintf(stderr, "Changing password for %s...\n", pwentry->pw_name);
/* do we have the appropriate permissions? */
if (geteuid() != 0) {
fprintf(stderr, "This program cannot run unless it is SUID-root, "
"exiting...\n");
exit(1);
}
/* get a password and strip any trailing cr/lf stuff */
if (isatty(0)) { /* interactive, so use a no-echo prompt twice */
cp = getpass(PROMPT1);
strncpy(new, cp, STRLEN);
cp = getpass(PROMPT2);
if (strcmp(new, cp)) {
fprintf(stderr, "The two versions don't match, exiting...\n");
exit(1);
}
} else { /* noninteractive, so just get it from stdin */
if (read(0, new, STRLEN) <= 0) {
fprintf(stderr, "Failed to read a new password, exiting...\n");
exit(1);
}
}
for (cp=new; *cp!='\n' && *cp!='\r' && cp-new<STRLEN-1; ++cp)
;
*cp = '\0';
if (strlen(new) <= 0) {
fprintf(stderr, "No password entered, exiting...\n");
exit(1);
}
/* get a private stderr, then close stderr/stdout to silence pwd programs */
if ((fd = dup(2)) < 0) {
fprintf(stderr, "Couldn't dup error-output fd, exiting...\n");
exit(1);
}
if ((mystderr = fdopen(fd, "w")) == NULL) {
fprintf(stderr, "Couldn't fdopen new stderr fd, exiting...\n");
exit(1);
}
close(1);
close(2);
/* detach from controlling tty to convince passwd to read stdin for pw */
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
if (ioctl(fd, TIOCNOTTY) < 0) {
fprintf(mystderr, "Failed to detach from /dev/tty: %s, exiting...\n",
strerror(errno));
exit(1);
}
close(fd);
}
/* shuffle UIDs for permissions - we expect to be running SUID-root */
origuid = getuid();
if (setuid(geteuid()) != 0) {
fprintf(mystderr, "Failed to properly set UID, exiting...\n");
exit(1);
}
/* open a pipe to and then feed the standard Unix passwd program, slowly */
if (isatty(0)) {
fprintf(mystderr, "Changing Unix password...");
fflush(mystderr);
}
strcpy(cmd, PASSWD);
strcat(cmd, " ");
strcat(cmd, pwentry->pw_name);
if ((cmdpipe = popen(cmd, "w")) == NULL) {
fprintf(mystderr, "FAILED: Can't open pipe to '%s', exiting...\n", cmd);
exit(1);
}
sleep(3);
fprintf(cmdpipe, "%s\n", new); fflush(cmdpipe); sleep(2);
fprintf(cmdpipe, "%s\n", new); fflush(cmdpipe); sleep(2);
if ((status = pclose(cmdpipe)) != 0) {
fprintf(mystderr, "FAILED: '%s' returned error code %d, exiting...\n",
cmd, status);
exit(1);
}
if (isatty(0))
fprintf(mystderr, "Success.\n");
}
exit(0);
}
/* end of program */
********************from Leonardo Mosquera
#!/usr/local/bin/expect -f
spawn /bin/passwd [lindex $argv 0]
set password [lindex $argv 1]
puts $password
expect "password:"
send "$password\r"
expect "password:"
send "$password\r"
expect eof
This shell use expect, and is an easy one to run or call from your
script:
./putpass username password
**********************from Mark John Suter / <suter_at_its.uq.edu.au>
#!/bin/sh
# set_c2_passwd
# [CJT 22-July-1998]
# If given user does not have a C2 password field then set one.
# Value used for password field is "*", i.e. an impossible password.
edauth=/usr/tcb/bin/edauth
if [ $# != 1 ]
then
echo "Usage: $0 username" 1>&2
exit 2
fi
user=$1
$edauth -g $user || exit 3
if $edauth -g $user | grep -q ":u_pwd="
then
echo "User $user already has a password" 1>&2
else
echo "Setting password for user $user" 1>&2
$edauth -g $user | sed -e 's/:chkent:/:u_pwd=*:chkent:/' | $edauth -s
fi
--
Don H. Olive, Physics Department don_at_campbellsvil.edu
Campbellsville University http://www2.campbellsvil.edu/~don
UPO 1265, One University Drive +1.270.789.5243 voice/+1.270.789.5042 fax
Campbellsville KY, 42718 USA PGP: finger don_at_cygnus.campbellsvil.edu
Received on Fri Sep 17 1999 - 21:35:01 NZST