> But how can I sync the passwords
> the other way? I mean, when a user changes his password on the
> linux-server, how can I sync this with samba?
Code appended. Have users use this instead of "passwd" (you may
prefer to move passwd to something else and install this instead --
note that you'll need to change the constant in this program to point
to the "real" Unix passwd program that you just renamed).
===== code begins (delete this line) =====
/*
* cpasswords.c
* Copyright N. Dean Pentcheff 1998
* University of South Carolina
* dean2@mail.biol.sc.edu
* This program may be redistributed either under the terms of the GNU Copyleft
* or the Perl Artistic License (http://www.perl.com).
*
* Change both the Unix and SMB passwords for a user.
*
* To work, must be installed SUID-root.
* Uses the current user's username, except that if the program is called
* by the root user, a username can be given as an argument.
* If called interactively (from a tty), is slightly verbose, and uses
* the standard getpass() routine to query for a password twice.
* If called noninteractively, expects the password (once) on stdin.
*
* Customize the locations of the standard Unix and SMB password programs
* in the "#defines" near the top (do NOT be tempted to add code to make
* these changeable from command-line arguments: these programs will
* be run as root!). If your paths are obscenely long, examine the
* size of STRLEN to make sure it will accomodate them.
* The only check on password quality is existence (len > 0) and for
* non-root callers a minimum length (MINPWLEN). This can be enhanced.
* The sleep()s in the actual pwd-changing routines appeared to be necessary
* in some early tests I did with the PAM-passwd program on Linux. I'm
* not convinced they're always necessary. Delays in a pwd-changing
* program aren't a bad idea anyway, so I've left them in.
*/
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pwd.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define PASSWD "/usr/bin/passwd"
#define SMBPASSWD "/usr/local/bin/smbpasswd"
#define PROMPT1 "Type a new password: "
#define PROMPT2 "Type the same password again: "
#define MINPWLEN 6
#define STRLEN 1024
int change(char *program, char *user, char *pwd, FILE *mystderr);
int main (
int argc,
char **argv)
{
int fd;
struct passwd *pwentry;
char name[STRLEN];
char newpw[STRLEN];
int reallyroot = 0;
char *cp;
FILE *mystderr;
/* do we have the appropriate permissions? */
if (geteuid() != 0) {
fprintf(stderr, "This program cannot run unless it is SUID-root, "
"exiting...\n");
exit(1);
}
if (getuid() == 0)
reallyroot = 1;
/* get the appropriate username */
if (argc > 1) {
if (reallyroot) {
/* if root, we can specify a username */
strncpy(name, *++argv, STRLEN);
} else {
fprintf(stderr, "Only the root user can specify a name, exiting...\n");
exit(1);
}
} else {
/* pick up the current user's username */
if ((pwentry = getpwuid(getuid())) == NULL) {
fprintf(stderr, "Failed getting name entry for UID=%d, exiting...\n",
getuid());
exit(1);
}
strncpy(name, pwentry->pw_name, STRLEN);
}
/* get a password and clean any cr/lf stuff */
if (isatty(0)) {
/* interactive, so use a no-echo prompt twice */
fprintf(stderr, "Changing password for user '%s'\n", name);
cp = getpass(PROMPT1);
strncpy(newpw, cp, STRLEN);
cp = getpass(PROMPT2);
if (strcmp(newpw, cp)) {
fprintf(stderr, "The two versions don't match, exiting...\n");
exit(1);
}
} else {
/* noninteractive, so just get it from stdin */
if (read(0, newpw, STRLEN) <= 0) {
fprintf(stderr, "Failed to read a new password, exiting...\n");
exit(1);
}
}
for (cp=newpw; *cp!='\n' && *cp!='\r' && cp-newpw= 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 know we are running SUID-root */
if (setuid(geteuid()) != 0) {
fprintf(stderr, "Failed to properly set UID, exiting...\n");
exit(1);
}
/* change the Unix password */
if (isatty(0))
fprintf(mystderr, "Changing Unix password...\n");
if ( ! change(PASSWD, name, newpw, mystderr))
exit(1);
if (isatty(0))
fprintf(mystderr, "\tSuccessfully changed Unix password.\n");
/* change the SMB password */
if (isatty(0))
fprintf(mystderr, "Changing SMB/Windows password...\n");
if ( ! change(SMBPASSWD, name, newpw, mystderr))
exit(1);
if (isatty(0))
fprintf(mystderr, "\tSuccessfully changed SMB/Windows password.\n");
exit(0);
}
int
change(char *program,
char *user,
char *pwd,
FILE *mystderr)
{
char cmd[STRLEN];
FILE *cmdpipe;
int status;
/* open a pipe to and then feed the password program, slowly */
strncpy(cmd, program, STRLEN);
strncat(cmd, " ", STRLEN - 1);
strncat(cmd, user, STRLEN - strlen(cmd));
if ((cmdpipe = popen(cmd, "w")) == NULL) {
fprintf(mystderr, "Failed to open pipe to '%s', exiting...\n", cmd);
return 0;
}
sleep(3);
fprintf(cmdpipe, "%s\n", pwd); fflush(cmdpipe); sleep(2);
fprintf(cmdpipe, "%s\n", pwd); fflush(cmdpipe); sleep(2);
if ((status = pclose(cmdpipe)) != 0) {
fprintf(mystderr, "Program '%s' returned error code %d, exiting...\n",
cmd, status);
return 0;
}
return 1;
}
============ code ends ==============