[Samba] Linux and Samba Code

Philippe Faure philippe at faure.ca
Mon Nov 25 03:08:01 GMT 2002


Here is an executable that would allow a user to change the linux and
SMB passwords simultaneously.

The website indicated in the comments had some problems in the code, but 
they are fixed in the cpasswd.c file which is below and also attached.

Hope that this helps others. The code is a fix, not a solution. it only 
works from the command prompt, but it helps with keeping linyx and Samba 
passwords the same.

Good Luck
/*
  * cpasswords.c
  * Copyright N. Dean Pentcheff  1998
  * University of South Carolina
  * dean2 at 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.
  * Program from http://www.linuxvoodoo.com/howto/all/00000074.html
  *
*/
#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_old"
#define  SMBPASSWD "/usr/bin/smbpasswd_old"
#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) {
//      fprintf(stderr, "No password entered, exiting...\n");
//      exit(1);
//      }
   if ( ! reallyroot) {
     if (strlen(newpw) < MINPWLEN) {
       fprintf(stderr, "Password must be at least %d characters long, " 
"exiting...\n", MINPWLEN);
       exit(1);
     }
   } /* get a private stderr, then close stderr/stdout to silence pwd 
programs */
   if ((fd=dup(2)) < 0) {
       fprintf(stderr, "Strange! Couldn't dup error-output fd, 
exiting...\n");
       exit(1);
   }
   if ((mystderr=fdopen(fd, "w"))== NULL) {
     fprintf(stderr, "Strange! Couldn't fdopen new stderr fd, 
exiting...\n");
     exit(1);
   }
   close(1);
   close(2); /* detach from controlling tty to get password programs to 
read stdin */
   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 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;
}


-------------- next part --------------
/*
 * cpasswords.c 
 * Copyright N. Dean Pentcheff  1998
 * University of South Carolina
 * dean2 at 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.
 * Program from http://www.linuxvoodoo.com/howto/all/00000074.html
 *
*/
#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_old"
#define  SMBPASSWD "/usr/bin/smbpasswd_old"
#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) {
//      fprintf(stderr, "No password entered, exiting...\n");
//      exit(1); 
//      }
  if ( ! reallyroot) {
    if (strlen(newpw) < MINPWLEN) {
      fprintf(stderr, "Password must be at least %d characters long, " "exiting...\n", MINPWLEN); 
      exit(1); 
    } 
  } /* get a private stderr, then close stderr/stdout to silence pwd programs */ 
  if ((fd=dup(2)) < 0) { 
      fprintf(stderr, "Strange! Couldn't dup error-output fd, exiting...\n"); 
      exit(1); 
  } 
  if ((mystderr=fdopen(fd, "w"))== NULL) { 
    fprintf(stderr, "Strange! Couldn't fdopen new stderr fd, exiting...\n"); 
    exit(1); 
  } 
  close(1); 
  close(2); /* detach from controlling tty to get password programs to read stdin */ 
  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 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; 
}


More information about the samba mailing list