largely rewrote smbpasswd so that the code is understandable. This
authorAndrew Tridgell <tridge@samba.org>
Thu, 12 Nov 1998 06:12:19 +0000 (06:12 +0000)
committerAndrew Tridgell <tridge@samba.org>
Thu, 12 Nov 1998 06:12:19 +0000 (06:12 +0000)
should allow us to call a function in swat rather than piping to
smbpasswd.

while doing this I also fixed quite a few "const char *" versus "char *" issues
that cropped up while using const to track down bugs in the code. This
led to changes in several generic functions.

The smbpasswd changes should be correct but they have not been
extensively tested. At least if I have introduced bugs then we should
be able to fix them more easily than before.
(This used to be commit 713864dd0322ae2ae2d83e333d85be35a7eed4ec)

source3/include/proto.h
source3/include/smb.h
source3/lib/util.c
source3/lib/util_str.c
source3/lib/util_unistr.c
source3/libsmb/clientgen.c
source3/libsmb/namequery.c
source3/libsmb/nmblib.c
source3/libsmb/smbencrypt.c
source3/utils/smbpasswd.c

index 019e793aa6aefa96aa0822589761559bd701469c..888e2af33f3d1cc00089544431ba320350b03f33 100644 (file)
@@ -258,7 +258,7 @@ BOOL matchname(char *remotehost,struct in_addr  addr);
 void standard_sub_basic(char *str);
 void standard_sub(connection_struct *conn,char *str);
 BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask);
-struct hostent *Get_Hostbyname(char *name);
+struct hostent *Get_Hostbyname(const char *name);
 BOOL process_exists(int pid);
 char *uidtoname(uid_t uid);
 char *gidtoname(gid_t gid);
@@ -333,9 +333,9 @@ char *client_addr(int fd);
 void set_first_token(char *ptr);
 BOOL next_token(char **ptr,char *buff,char *sep, int bufsize);
 char **toktocliplist(int *ctok, char *sep);
-int StrCaseCmp(char *s, char *t);
+int StrCaseCmp(const char *s, const char *t);
 int StrnCaseCmp(char *s, char *t, int n);
-BOOL strequal(char *s1, char *s2);
+BOOL strequal(const char *s1, const char *s2);
 BOOL strnequal(char *s1,char *s2,int n);
 BOOL strcsequal(char *s1,char *s2);
 void strlower(char *s);
@@ -352,8 +352,8 @@ int count_chars(char *s,char c);
 char *safe_strcpy(char *dest,const char *src, int maxlength);
 char *safe_strcat(char *dest, char *src, int maxlength);
 char *StrCpy(char *dest,char *src);
-char *StrnCpy(char *dest,char *src,int n);
-char *strncpyn(char *dest, char *src,int n, char c);
+char *StrnCpy(char *dest,const char *src,int n);
+char *strncpyn(char *dest, const char *src,int n, char c);
 int strhex_to_str(char *p, int len, const char *strhex);
 BOOL in_list(char *s,char *list,BOOL casesensitive);
 BOOL string_init(char **dest,char *src);
@@ -372,7 +372,7 @@ char *unistr2_to_str(UNISTR2 *str);
 uint32 buffer2_to_uint32(BUFFER2 *str);
 char *buffer2_to_str(BUFFER2 *str);
 char *buffer2_to_multistr(BUFFER2 *str);
-int struni2(uint16 *p, char *buf);
+int struni2(uint16 *p, const char *buf);
 char *unistr(char *buf);
 int unistrcpy(char *dst, char *src);
 
@@ -435,12 +435,12 @@ BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
                   time_t *w_time, SMB_INO_T *ino);
 int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute, 
             void (*fn)(file_info *, const char *));
-BOOL cli_oem_change_password(struct cli_state *cli, char *user, char *new_password,
-                             char *old_password);
+BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
+                             const char *old_password);
 BOOL cli_negprot(struct cli_state *cli);
 BOOL cli_session_request(struct cli_state *cli,
                         struct nmb_name *calling, struct nmb_name *called);
-BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip);
+BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip);
 struct cli_state *cli_initialise(struct cli_state *cli);
 void cli_shutdown(struct cli_state *cli);
 int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num);
@@ -482,12 +482,12 @@ BOOL deal_with_creds(uchar sess_key[8],
 BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
                 struct in_addr to_ip,char *master,char *rname,
                 void (*fn)(struct packet_struct *));
-struct in_addr *name_query(int fd,char *name,int name_type, BOOL bcast,BOOL recurse,
+struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse,
          struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *));
 FILE *startlmhosts(char *fname);
 BOOL getlmhostsent( FILE *fp, char *name, int *name_type, struct in_addr *ipaddr);
 void endlmhosts(FILE *fp);
-BOOL resolve_name(char *name, struct in_addr *return_ip, int name_type);
+BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type);
 BOOL find_master_ip(char *group, struct in_addr *master_ip);
 
 /*The following definitions come from  libsmb/nmblib.c  */
@@ -497,7 +497,7 @@ char *namestr(struct nmb_name *n);
 struct packet_struct *copy_packet(struct packet_struct *packet);
 void free_packet(struct packet_struct *packet);
 struct packet_struct *read_packet(int fd,enum packet_type packet_type);
-void make_nmb_name( struct nmb_name *n, char *name, int type, char *this_scope );
+void make_nmb_name( struct nmb_name *n, const char *name, int type, const char *this_scope );
 BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2);
 BOOL send_packet(struct packet_struct *p);
 struct packet_struct *receive_packet(int fd,enum packet_type type,int t);
@@ -540,7 +540,7 @@ void nt_lm_owf_gen(char *pwd, uchar nt_p16[16], uchar p16[16]);
 void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24]);
 void NTLMSSPOWFencrypt(uchar passwd[8], uchar *ntlmchalresp, uchar p24[24]);
 void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24);
-BOOL make_oem_passwd_hash(char data[516], char *passwd, uchar old_pw_hash[16], BOOL unicode);
+BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[16], BOOL unicode);
 
 /*The following definitions come from  libsmb/smberr.c  */
 
index db7b251d65e4cec073da367a348d8d4aa9280a0e..47a8869a48fd24ab802e8917e3201955064eeb8d 100644 (file)
@@ -41,7 +41,7 @@
 #define IS_BITS_SET_SOME(var,bit) (((var)&(bit))!=0)
 #define IS_BITS_CLR_ALL(var,bit) (((var)&(~(bit)))==0)
 
-#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
+#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2)))
 
 typedef int BOOL;
 
index f1fae9155c8280d7cea93bbf18392cf9f0039085..2be1fcaf6fcf3a33dca3e575154753d185bd3285 100644 (file)
@@ -2386,7 +2386,7 @@ BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask)
 a wrapper for gethostbyname() that tries with all lower and all upper case 
 if the initial name fails
 ****************************************************************************/
-struct hostent *Get_Hostbyname(char *name)
+struct hostent *Get_Hostbyname(const char *name)
 {
   char *name2 = strdup(name);
   struct hostent *ret;
index 996273bf3adb3acfa83f38a2f2441f6acf69035b..02fa892d7b2d3734165ec500d651f57b43e8f091 100644 (file)
@@ -115,7 +115,7 @@ char **toktocliplist(int *ctok, char *sep)
 /*******************************************************************
   case insensitive string compararison
 ********************************************************************/
-int StrCaseCmp(char *s, char *t)
+int StrCaseCmp(const char *s, const char *t)
 {
   /* compare until we run out of string, either t or s, or find a difference */
   /* We *must* use toupper rather than tolower here due to the
@@ -272,7 +272,7 @@ int StrnCaseCmp(char *s, char *t, int n)
 /*******************************************************************
   compare 2 strings 
 ********************************************************************/
-BOOL strequal(char *s1, char *s2)
+BOOL strequal(const char *s1, const char *s2)
 {
   if (s1 == s2) return(True);
   if (!s1 || !s2) return(False);
@@ -819,7 +819,7 @@ char *StrCpy(char *dest,char *src)
 /****************************************************************************
 like strncpy but always null terminates. Make sure there is room!
 ****************************************************************************/
-char *StrnCpy(char *dest,char *src,int n)
+char *StrnCpy(char *dest,const char *src,int n)
 {
   char *d = dest;
   if (!dest) return(NULL);
@@ -837,7 +837,7 @@ char *StrnCpy(char *dest,char *src,int n)
 like strncpy but copies up to the character marker.  always null terminates.
 returns a pointer to the character marker in the source string (src).
 ****************************************************************************/
-char *strncpyn(char *dest, char *src,int n, char c)
+char *strncpyn(char *dest, const char *src,int n, char c)
 {
        char *p;
        int str_len;
index 49fb729267047b3c03cb88927872d1e22766a2f8..c58820cfeced603c8000191128ff94ad945e89b6 100644 (file)
@@ -189,7 +189,7 @@ return number of unicode chars copied, excluding the null character.
 only handles ascii strings
 ********************************************************************/
 #define MAXUNI 1024
-int struni2(uint16 *p, char *buf)
+int struni2(uint16 *p, const char *buf)
 {
        int len = 0;
 
index fc4c7f1d5db660c9fe58fe3378a64db8aed3bbf9..b4ca7a1d77713ad69128b55e9883084e85ff50d4 100644 (file)
@@ -2087,8 +2087,8 @@ int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
 Send a SamOEMChangePassword command
 ****************************************************************************/
 
-BOOL cli_oem_change_password(struct cli_state *cli, char *user, char *new_password,
-                             char *old_password)
+BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
+                             const char *old_password)
 {
   char param[16+sizeof(fstring)];
   char data[532];
@@ -2317,7 +2317,7 @@ retry:
 /****************************************************************************
 open the client sockets
 ****************************************************************************/
-BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip)
+BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
 {
        extern struct in_addr ipzero;
 
index 0e92e6b5dd815527b9b360a2b1557428da70ad7c..f06ecc94e4047678d49eace075dc9f6b020dffe9 100644 (file)
@@ -194,7 +194,7 @@ BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
   returns an array of IP addresses or NULL if none
   *count will be set to the number of addresses returned
   ****************************************************************************/
-struct in_addr *name_query(int fd,char *name,int name_type, BOOL bcast,BOOL recurse,
+struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse,
          struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *))
 {
   BOOL found=False;
@@ -440,7 +440,7 @@ void endlmhosts(FILE *fp)
 /********************************************************
 resolve via "bcast" method
 *********************************************************/
-static BOOL resolve_bcast(char *name, struct in_addr *return_ip, int name_type)
+static BOOL resolve_bcast(const char *name, struct in_addr *return_ip, int name_type)
 {
        int sock, i;
        
@@ -486,7 +486,7 @@ static BOOL resolve_bcast(char *name, struct in_addr *return_ip, int name_type)
 /********************************************************
 resolve via "wins" method
 *********************************************************/
-static BOOL resolve_wins(char *name, struct in_addr *return_ip, int name_type)
+static BOOL resolve_wins(const char *name, struct in_addr *return_ip, int name_type)
 {
       int sock;
       struct in_addr wins_ip;
@@ -536,7 +536,7 @@ static BOOL resolve_wins(char *name, struct in_addr *return_ip, int name_type)
 /********************************************************
 resolve via "lmhosts" method
 *********************************************************/
-static BOOL resolve_lmhosts(char *name, struct in_addr *return_ip, int name_type)
+static BOOL resolve_lmhosts(const char *name, struct in_addr *return_ip, int name_type)
 {
        /*
         * "lmhosts" means parse the local lmhosts file.
@@ -566,7 +566,7 @@ static BOOL resolve_lmhosts(char *name, struct in_addr *return_ip, int name_type
 /********************************************************
 resolve via "hosts" method
 *********************************************************/
-static BOOL resolve_hosts(char *name, struct in_addr *return_ip)
+static BOOL resolve_hosts(const char *name, struct in_addr *return_ip)
 {
        /*
         * "host" means do a localhost, or dns lookup.
@@ -589,7 +589,7 @@ static BOOL resolve_hosts(char *name, struct in_addr *return_ip)
  or NetBIOS name. This uses the name switch in the
  smb.conf to determine the order of name resolution.
 *********************************************************/
-BOOL resolve_name(char *name, struct in_addr *return_ip, int name_type)
+BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
 {
   int i;
   BOOL pure_address = True;
index 87f483e9fd86aca097094229033f94febde7be9e..6314a9076b66e70462a13119822b93263ad0c92a 100644 (file)
@@ -762,7 +762,7 @@ static int build_dgram(char *buf,struct packet_struct *p)
 /*******************************************************************
   build a nmb name
  *******************************************************************/
-void make_nmb_name( struct nmb_name *n, char *name, int type, char *this_scope )
+void make_nmb_name( struct nmb_name *n, const char *name, int type, const char *this_scope )
 {
   memset( (char *)n, '\0', sizeof(struct nmb_name) );
   StrnCpy( n->name, name, 15 );
index 5017b33c07dcb3869ab890ae6dca5869773b696a..9234088404e73baa976925406dd6d9b432b7a919 100644 (file)
@@ -190,7 +190,7 @@ void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24)
 #endif
 }
 
-BOOL make_oem_passwd_hash(char data[516], char *passwd, uchar old_pw_hash[16], BOOL unicode)
+BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[16], BOOL unicode)
 {
        int new_pw_len = strlen(passwd) * (unicode ? 2 : 1);
 
index e1904f9c967417d78d05387b8c652c6a4e12b1f8..09aa0be9d685ed34b72eaa31f23f0341006da94e 100644 (file)
@@ -23,697 +23,739 @@ extern pstring scope;
 extern pstring myhostname;
 extern pstring global_myname;
 extern fstring global_myworkgroup;
+extern int DEBUGLEVEL;
 
-static char *prog_name;
 
 /*********************************************************
- Print command usage on stderr and die.
+a strdup with exit
 **********************************************************/
+static char *xstrdup(char *s)
+{
+       s = strdup(s);
+       if (!s) {
+               fprintf(stderr,"out of memory\n");
+               exit(1);
+       }
+       return s;
+}
 
-static void usage(char *name, BOOL is_root)
+
+/*********************************************************
+ Print command usage on stderr and die.
+**********************************************************/
+static void usage(void)
 {
-       if(is_root)
-               fprintf(stderr, "Usage is : %s [-D DEBUGLEVEL] [-h] [-a] [-d] [-e] [-m] [-n] [-s] [username] [password]\n\
-%s: [-R <name resolve order>] [-D DEBUGLEVEL] [-j DOMAINNAME] [-r machine] [-U remote_username] [username] [password]\n%s: [-h]\n", name, name, name);
-       else
-               fprintf(stderr, "Usage is : %s [-h] [-s] [-D DEBUGLEVEL] [-r machine] [-U remote_username] [password]\n", name);
+       if (getuid() == 0) {
+               printf("smbpasswd [options] [username] [password]\n");
+       } else {
+               printf("smbpasswd [options] [password]\n");
+       }
+       printf("options:\n");
+       printf("  -s                   use stdin for password prompt\n");
+       printf("  -D LEVEL             debug level\n");
+       printf("  -U USER              remote username\n");
+       printf("  -r MACHINE           remote machine\n");
+
+       if (getuid() == 0) {
+               printf("  -R ORDER             name resolve order\n");
+               printf("  -j DOMAIN            join domain name\n");
+               printf("  -a                   add user\n");
+               printf("  -d                   delete user\n");
+               printf("  -e                   enable user\n");
+               printf("  -n                   set no password\n");
+               printf("  -m                   machine trust account\n");
+       }
        exit(1);
 }
 
 /*********************************************************
 Join a domain.
 **********************************************************/
+static int join_domain(char *domain, char *remote)
+{
+       pstring remote_machine;
+       fstring trust_passwd;
+       unsigned char orig_trust_passwd_hash[16];
+       BOOL ret;
+
+       pstrcpy(remote_machine, remote ? remote : "");
+       fstrcpy(trust_passwd, global_myname);
+       strlower(trust_passwd);
+       E_md4hash( (uchar *)trust_passwd, orig_trust_passwd_hash);
+
+       /* Ensure that we are not trying to join a
+          domain if we are locally set up as a domain
+          controller. */
+
+       if(strequal(remote, global_myname)) {
+               fprintf(stderr, "Cannot join domain %s as the domain controller name is our own. We cannot be a domain controller for a domain and also be a domain member.\n", domain);
+               return 1;
+       }
+
+       /*
+        * Create the machine account password file.
+        */
+       if(!trust_password_lock( domain, global_myname, True)) {
+               fprintf(stderr, "unable to open the machine account password file for \
+machine %s in domain %s.\n", global_myname, domain); 
+               return 1;
+       }
+
+       /*
+        * Write the old machine account password.
+        */
+       
+       if(!set_trust_account_password( orig_trust_passwd_hash)) {              
+               fprintf(stderr, "unable to write the machine account password for \
+machine %s in domain %s.\n", global_myname, domain);
+               trust_password_unlock();
+               return 1;
+       }
+       
+       /*
+        * If we are given a remote machine assume this is the PDC.
+        */
+       
+       if(remote == NULL) {
+               pstrcpy(remote_machine, lp_passwordserver());
+       }
+
+       if(!*remote_machine) {
+               fprintf(stderr, "No password server list given in smb.conf - \
+unable to join domain.\n");
+               trust_password_unlock();
+               return 1;
+       }
+
+       ret = change_trust_account_password( domain, remote_machine);
+       trust_password_unlock();
+       
+       if(!ret) {
+               trust_password_delete( domain, global_myname);
+               fprintf(stderr,"Unable to join domain %s.\n",domain);
+       } else {
+               printf("Joined domain %s.\n",domain);
+       }
+       
+       return (int)ret;
+}
+
 
-static int join_domain( char *domain, char *remote)
+static void set_line_buffering(FILE *f)
 {
-  pstring remote_machine;
-  fstring trust_passwd;
-  unsigned char orig_trust_passwd_hash[16];
-  BOOL ret;
-
-  pstrcpy(remote_machine, remote ? remote : "");
-  fstrcpy(trust_passwd, global_myname);
-  strlower(trust_passwd);
-  E_md4hash( (uchar *)trust_passwd, orig_trust_passwd_hash);
-
-  /* Ensure that we are not trying to join a
-     domain if we are locally set up as a domain
-     controller. */
-
-  if(strequal(remote, global_myname)) {
-    fprintf(stderr, "%s: Cannot join domain %s as the domain controller name is our own. \
-We cannot be a domain controller for a domain and also be a domain member.\n", prog_name, domain);
-    return 1;
-  }
-
-  /*
-   * Create the machine account password file.
-   */
-  if(!trust_password_lock( domain, global_myname, True)) {
-    fprintf(stderr, "%s: unable to open the machine account password file for \
-machine %s in domain %s.\n", prog_name, global_myname, domain); 
-    return 1;
-  }
-
-  /*
-   * Write the old machine account password.
-   */
-
-  if(!set_trust_account_password( orig_trust_passwd_hash)) {              
-    fprintf(stderr, "%s: unable to write the machine account password for \
-machine %s in domain %s.\n", prog_name, global_myname, domain);
-    trust_password_unlock();
-    return 1;
-  }
-
-  /*
-   * If we are given a remote machine assume this is the PDC.
-   */
-
-  if(remote == NULL)
-    pstrcpy(remote_machine, lp_passwordserver());
-
-  if(!*remote_machine) {
-    fprintf(stderr, "%s: No password server list given in smb.conf - \
-unable to join domain.\n", prog_name);
-    trust_password_unlock();
-    return 1;
-  }
-
-  ret = change_trust_account_password( domain, remote_machine);
-  trust_password_unlock();
-
-  if(!ret) {
-    trust_password_delete( domain, global_myname);
-    fprintf(stderr,"%s: Unable to join domain %s.\n", prog_name, domain);
-  } else {
-    printf("%s: Joined domain %s.\n", prog_name, domain);
-  }
-
-  return (int)ret;
+       setvbuf(f, NULL, _IOLBF, 0);
 }
 
 /*************************************************************
  Utility function to prompt for passwords from stdin. Each
  password entered must end with a newline.
 *************************************************************/
-
 static char *stdin_new_passwd(void)
 {
-  static fstring new_passwd;
-  size_t len;
-
-  memset( new_passwd, '\0', sizeof(new_passwd));
-
-  /*
-   * if no error is reported from fgets() and string at least contains
-   * the newline that ends the password, then replace the newline with
-   * a null terminator.
-   */
-  if ( fgets(new_passwd, sizeof(new_passwd), stdin) != NULL) {
-    if ((len = strlen(new_passwd)) > 0) {
-      if(new_passwd[len-1] == '\n')
-        new_passwd[len - 1] = 0; 
-    }
-  }
-  return(new_passwd);
+       static fstring new_passwd;
+       size_t len;
+
+       ZERO_STRUCT(new_passwd);
+
+       /*
+        * if no error is reported from fgets() and string at least contains
+        * the newline that ends the password, then replace the newline with
+        * a null terminator.
+        */
+       if ( fgets(new_passwd, sizeof(new_passwd), stdin) != NULL) {
+               if ((len = strlen(new_passwd)) > 0) {
+                       if(new_passwd[len-1] == '\n')
+                               new_passwd[len - 1] = 0; 
+               }
+       }
+       return(new_passwd);
 }
 
+
 /*************************************************************
  Utility function to get passwords via tty or stdin
  Used if the '-s' option is set to silently get passwords
  to enable scripting.
 *************************************************************/
-
 static char *get_pass( char *prompt, BOOL stdin_get)
 {
-  if (stdin_get)
-    return( stdin_new_passwd());
-  else
-    return( getpass( prompt));
+       char *p;
+       if (stdin_get) {
+               p = stdin_new_passwd();
+       } else {
+               p = getpass(prompt);
+       }
+       return xstrdup(p);
 }
 
 /*************************************************************
  Utility function to prompt for new password.
 *************************************************************/
-
-static void prompt_for_new_password(char *new_passwd, BOOL stdin_get)
+static char *prompt_for_new_password(BOOL stdin_get)
 {
-  char *p;
+       char *p;
+       fstring new_passwd;
 
-  new_passwd[0] = '\0';
+       ZERO_STRUCT(new_passwd);
  
-  p = get_pass("New SMB password:", stdin_get);
+       p = get_pass("New SMB password:", stdin_get);
 
-  strncpy(new_passwd, p, sizeof(fstring));
-  new_passwd[sizeof(fstring)-1] = '\0';
+       fstrcpy(new_passwd, p);
 
-  p = get_pass("Retype new SMB password:", stdin_get);
+       p = get_pass("Retype new SMB password:", stdin_get);
 
-  if (strncmp(p, new_passwd, sizeof(fstring)-1))
-  {
-    fprintf(stderr, "%s: Mismatch - password unchanged.\n", prog_name);
-    exit(1);
-  }
+       if (strcmp(p, new_passwd)) {
+               fprintf(stderr, "Mismatch - password unchanged.\n");
+               return NULL;
+       }
 
-  if (new_passwd[0] == '\0') {
-    printf("Password not set\n");
-    exit(0);
-  }
+       return xstrdup(p);
 }
 
-/*********************************************************
- Start here.
-**********************************************************/
 
-int main(int argc, char **argv)
-{
-  extern char *optarg;
-  extern int optind;
-  extern int DEBUGLEVEL;
-  uid_t             real_uid;
-  uid_t             eff_uid;
-  struct passwd  *pwd = NULL;
-  fstring         old_passwd;
-  fstring         new_passwd;
-  uchar           new_p16[16];
-  uchar           new_nt_p16[16];
-  char           *p;
-  struct smb_passwd *smb_pwent;
-  FILE           *fp;
-  int             ch;
-  int             err;
-  BOOL is_root = False;
-  pstring  user_name;
-  BOOL remote_user_name = False;
-  char *remote_machine = NULL;
-  BOOL add_user = False;
-  BOOL got_new_pass = False;
-  BOOL trust_account = False;
-  BOOL disable_user = False;
-  BOOL enable_user = False;
-  BOOL set_no_password = False;
-  BOOL joining_domain = False;
-  BOOL stdin_passwd_get = False;
-  char *new_domain = NULL;
-  pstring servicesf = CONFIGFILE;
-  void           *vp;
-  struct nmb_name calling, called;
-  
-
-  new_passwd[0] = '\0';
-  user_name[0] = '\0';
-
-  memset(old_passwd, '\0', sizeof(old_passwd));
-  memset(new_passwd, '\0', sizeof(new_passwd));
 
-  prog_name = argv[0];
 
-  TimeInit();
-
-  setup_logging(prog_name,True);
-  
-  charset_initialise();
-
-  if(!initialize_password_db()) {
-    fprintf(stderr, "%s: Can't setup password database vectors.\n", prog_name);
-    exit(1);
-  }
-
-  if (!lp_load(servicesf,True,False,False)) {
-    fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n", prog_name, servicesf);
-    exit(1);
-  }
-
-  if(!get_myname(myhostname,NULL)) {
-    fprintf(stderr, "%s: unable to get my hostname.\n", prog_name );
-    exit(1);
-  }
-
-  /*
-   * Set the machine NETBIOS name if not already
-   * set from the config file. 
-   */ 
-    
-  if (!*global_myname)
-  {   
-    fstrcpy( global_myname, myhostname );
-    p = strchr( global_myname, '.' );
-    if (p) 
-      *p = 0;
-  }           
-  strupper( global_myname );
-
-  codepage_initialise(lp_client_code_page());
-
-  /* Get the real and effective uids */
-  real_uid = getuid();
-  eff_uid = geteuid();
-  /* Check the effective uid */
-  if ((eff_uid == (uid_t)0) && (real_uid != (uid_t)0)) {
-    fprintf(stderr, "%s: Must *NOT* be setuid root.\n", prog_name);
-    exit(1);
-  }
-
-  is_root = (eff_uid == (uid_t)0);
-
-  while ((ch = getopt(argc, argv, "adehmnj:r:sR:D:U:")) != EOF) {
-    switch(ch) {
-    case 'a':
-      if(is_root)
-        add_user = True;
-      else
-        usage(prog_name, is_root);
-      break;
-    case 'd':
-      if(is_root) {
-        disable_user = True;
-        got_new_pass = True;
-        fstrcpy(new_passwd, "XXXXXX");
-      } else
-        usage(prog_name, is_root);
-      break;
-    case 'e':
-      if(is_root) {
-        enable_user = True;
-        got_new_pass = True;
-        fstrcpy(new_passwd, "XXXXXX");
-      } else
-        usage(prog_name, is_root);
-      break;
-    case 'D':
-      DEBUGLEVEL = atoi(optarg);
-      break;
-    case 'n':
-      if(is_root) {
-        set_no_password = True;
-        got_new_pass = True;
-        fstrcpy(new_passwd, "NO PASSWORD");
-      } else
-        usage(prog_name, is_root);
-    case 'r':
-      remote_machine = optarg;
-      break;
-    case 's':
-      /*
-       * Ensure stdin/stdout are line buffered.
-       */
-      if (setvbuf( stdin, NULL, _IOLBF, 0) != 0) {
-        fprintf(stderr, "%s: setvbuf error on stdin. Error was %s\n", prog_name, strerror(errno));
-        exit(1);
-      }
-
-      if (setvbuf( stdout, NULL, _IOLBF, 0) != 0) {
-        fprintf(stderr, "%s: setvbuf error on stdout. Error was %s\n", prog_name, strerror(errno));
-        exit(1);
-      }
-
-      if (setvbuf( stderr, NULL, _IOLBF, 0) != 0) {
-        fprintf(stderr, "%s: setvbuf error on stderr. Error was %s\n", prog_name, strerror(errno));
-        perror("setvbuf error on stdout");
-        exit(1);
-      }
-
-      stdin_passwd_get = True;
-      break;
-    case 'R':
-      if(is_root) {
-        lp_set_name_resolve_order(optarg);
-        break;
-      } else
-        usage(prog_name, is_root);
-    case 'm':
-      if(is_root) {
-        trust_account = True;
-      } else
-        usage(prog_name, is_root);
-      break;
-    case 'j':
-      if(is_root) {
-        new_domain = optarg;
-        strupper(new_domain);
-        joining_domain = True;
-      } else
-        usage(prog_name, is_root);  
-      break;
-    case 'U':
-      remote_user_name = True;
-      pstrcpy(user_name, optarg);
-      break;
-    case 'h':
-    default:
-      usage(prog_name, is_root);
-    }
-  }
-
-  argc -= optind;
-  argv += optind;
-
-  if (!is_root && remote_user_name && !remote_machine) {
-    fprintf(stderr, "%s: You can only use -U with -r.\n", prog_name);
-    usage(prog_name, False);
-  }
-
-  /*
-   * Ensure add_user and either remote machine or join domain are
-   * not both set.
-   */
-
-  if(add_user && ((remote_machine != NULL) || joining_domain))
-    usage(prog_name, True);
-
-  /*
-   * Deal with joining a domain.
-   */
-  if(joining_domain && argc != 0)
-    usage(prog_name, True);
-
-  if(joining_domain) {
-    return join_domain( new_domain, remote_machine);
-  }
-
-  if(is_root) {
-
-    /*
-     * Deal with root - can add a user, but only locally.
-     */
-
-    switch(argc) {
-      case 0:
-        break;
-      case 1:
-        /* If we are root we can change another's password. */
-        pstrcpy(user_name, argv[0]);
-        break;
-      case 2:
-        pstrcpy(user_name, argv[0]);
-        fstrcpy(new_passwd, argv[1]);
-        got_new_pass = True;
-        break;
-      default:
-        usage(prog_name, True);
-    }
-
-    if(*user_name) {
-
-      if(trust_account) {
-        int username_len = strlen(user_name);
-        if(username_len >= sizeof(pstring) - 1) {
-          fprintf(stderr, "%s: machine account name too long.\n", user_name);
-          exit(1);
-        }
-
-        if(user_name[username_len-1] != '$') {
-          user_name[username_len] = '$';
-          user_name[username_len+1] = '\0';
-        }
-      }
-
-      if(!remote_machine && ((pwd = Get_Pwnam(user_name, True)) == NULL)) {
-        fprintf(stderr, "%s: User \"%s\" was not found in system password file.\n", 
-                    prog_name, user_name);
-        exit(1);
-      }
-    } else {
-      if((pwd = getpwuid(eff_uid)) != NULL)
-        pstrcpy( user_name, pwd->pw_name);
-    }
-
-  } else {
-
-    if(add_user) {
-      fprintf(stderr, "%s: Only root can add a user.\n", prog_name);
-      usage(prog_name, False);
-    }
-
-    if(disable_user) {
-      fprintf(stderr, "%s: Only root can disable a user.\n", prog_name);
-      usage(prog_name, False);
-    }
-
-    if(enable_user) {
-      fprintf(stderr, "%s: Only root can enable a user.\n", prog_name);
-      usage(prog_name, False);
-    }
-
-    if(argc > 1)
-      usage(prog_name, False);
-
-    if(argc == 1) {
-      fstrcpy(new_passwd, argv[0]);
-      got_new_pass = True;
-    }
-
-    if(!remote_user_name && ((pwd = getpwuid(eff_uid)) != NULL))
-      pstrcpy( user_name, pwd->pw_name);
-
-    /*
-     * A non-root user is always setting a password
-     * via a remote machine (even if that machine is
-     * localhost).
-     */
-
-    if(remote_machine == NULL)
-      remote_machine = "127.0.0.1";
-  }
-    
-  if (*user_name == '\0') {
-    fprintf(stderr, "%s: Unable to get a user name for password change.\n", prog_name);
-    exit(1);
-  }
-
-  /*
-   * If we are adding a machine account then pretend
-   * we already have the new password, we will be using
-   * the machinename as the password.
-   */
-
-  if(add_user && trust_account) {
-    got_new_pass = True;
-    strncpy(new_passwd, user_name, sizeof(fstring));
-    new_passwd[sizeof(fstring)-1] = '\0';
-    strlower(new_passwd);
-    if(new_passwd[strlen(new_passwd)-1] == '$')
-      new_passwd[strlen(new_passwd)-1] = '\0';
-  }
-
-  /* 
-   * If we are root we don't ask for the old password (unless it's on a
-   * remote machine.
-   */
-
-  if (remote_machine != NULL) {
-    p = get_pass("Old SMB password:",stdin_passwd_get);
-    fstrcpy(old_passwd, p);
-  }
-
-  if (!got_new_pass)
-    prompt_for_new_password(new_passwd,stdin_passwd_get);
-  
-  if (new_passwd[0] == '\0') {
-    printf("Password not set\n");
-    exit(0);
-  }
-  /* 
-   * Now do things differently depending on if we're changing the
-   * password on a remote machine. Remember - a normal user is
-   * always using this code, looping back to the local smbd.
-   */
-
-  if(remote_machine != NULL) {
-    struct cli_state cli;
-    struct in_addr ip;
-
-    if(!resolve_name( remote_machine, &ip, 0x20)) {
-      fprintf(stderr, "%s: unable to find an IP address for machine %s.\n",
-              prog_name, remote_machine );
-      exit(1);
-    }
+/*************************************************************
+change a password on a remote machine using IPC calls
+*************************************************************/
+static BOOL remote_password_change(const char *remote_machine, const char *user_name, 
+                                  const char *old_passwd, const char *new_passwd)
+{
+       struct nmb_name calling, called;
+       struct cli_state cli;
+       struct in_addr ip;
+
+       if(!resolve_name( remote_machine, &ip, 0x20)) {
+               fprintf(stderr, "unable to find an IP address for machine %s.\n",
+                       remote_machine );
+               return False;
+       }
  
-    ZERO_STRUCT(cli);
+       ZERO_STRUCT(cli);
  
-    if (!cli_initialise(&cli) || !cli_connect(&cli, remote_machine, &ip)) {
-      fprintf(stderr, "%s: unable to connect to SMB server on machine %s. Error was : %s.\n",
-              prog_name, remote_machine, cli_errstr(&cli) );
-      exit(1);
-    }
+       if (!cli_initialise(&cli) || !cli_connect(&cli, remote_machine, &ip)) {
+               fprintf(stderr, "unable to connect to SMB server on machine %s. Error was : %s.\n",
+                       remote_machine, cli_errstr(&cli) );
+               return False;
+       }
   
        make_nmb_name(&calling, global_myname , 0x0 , scope);
        make_nmb_name(&called , remote_machine, 0x20, scope);
-
-       if (!cli_session_request(&cli, &calling, &called))
-       {
-      fprintf(stderr, "%s: machine %s rejected the session setup. Error was : %s.\n",
-              prog_name, remote_machine, cli_errstr(&cli) );
-      cli_shutdown(&cli);
-      exit(1);
-    }
+       
+       if (!cli_session_request(&cli, &calling, &called)) {
+               fprintf(stderr, "machine %s rejected the session setup. Error was : %s.\n",
+                       remote_machine, cli_errstr(&cli) );
+               cli_shutdown(&cli);
+               return False;
+       }
   
-    cli.protocol = PROTOCOL_NT1;
-
-    if (!cli_negprot(&cli)) {
-      fprintf(stderr, "%s: machine %s rejected the negotiate protocol. Error was : %s.\n",        
-              prog_name, remote_machine, cli_errstr(&cli) );
-      cli_shutdown(&cli);
-      exit(1);
-    }
+       cli.protocol = PROTOCOL_NT1;
+
+       if (!cli_negprot(&cli)) {
+               fprintf(stderr, "machine %s rejected the negotiate protocol. Error was : %s.\n",        
+                       remote_machine, cli_errstr(&cli) );
+               cli_shutdown(&cli);
+               return False;
+       }
   
-    /*
-     * We should connect as the anonymous user here, in case
-     * the server has "must change password" checked...
-     * Thanks to <Nicholas.S.Jenkins@cdc.com> for this fix.
-     */
-
-    if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
-      fprintf(stderr, "%s: machine %s rejected the session setup. Error was : %s.\n",        
-              prog_name, remote_machine, cli_errstr(&cli) );
-      cli_shutdown(&cli);
-      exit(1);
-    }               
-
-    if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
-      fprintf(stderr, "%s: machine %s rejected the tconX on the IPC$ share. Error was : %s.\n",
-              prog_name, remote_machine, cli_errstr(&cli) );
-      cli_shutdown(&cli);
-      exit(1);
-    }
-
-    if(!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) {
-      fprintf(stderr, "%s: machine %s rejected the password change: Error was : %s.\n",
-              prog_name, remote_machine, cli_errstr(&cli) );
-      cli_shutdown(&cli);
-      exit(1);
-    }
-
-    cli_shutdown(&cli);
-    exit(0);
-  }
-
-  /*
-   * Check for a machine account.
-   */
-
-  if(trust_account && !pwd) {
-    fprintf(stderr, "%s: User %s does not exist in system password file \
-(usually /etc/passwd). Cannot add machine account without a valid system user.\n",
-           prog_name, user_name);
-    exit(1);
-  }
-
-  /* Calculate the MD4 hash (NT compatible) of the new password. */
-  
-  nt_lm_owf_gen( new_passwd, new_nt_p16, new_p16);
-
-  /*
-   * Open the smbpaswd file.
-   */
-  vp = startsmbpwent(True);
-  if (!vp && errno == ENOENT) {
-      fprintf(stderr,"%s: smbpasswd file did not exist - attempting to create it.\n", prog_name);
-         fp = fopen(lp_smb_passwd_file(), "w");
-         if (fp) {
-                 fprintf(fp, "# Samba SMB password file\n");
-                 fclose(fp);
-                 vp = startsmbpwent(True);
-         }
-  }
-  if (!vp) {
-         err = errno;
-         fprintf(stderr, "%s: Failed to open password file %s.\n",
-                 prog_name, lp_smb_passwd_file());
-         errno = err;
-         perror(prog_name);
-         exit(err);
-  }
+       /*
+        * We should connect as the anonymous user here, in case
+        * the server has "must change password" checked...
+        * Thanks to <Nicholas.S.Jenkins@cdc.com> for this fix.
+        */
+
+       if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
+               fprintf(stderr, "machine %s rejected the session setup. Error was : %s.\n",        
+                       remote_machine, cli_errstr(&cli) );
+               cli_shutdown(&cli);
+               return False;
+       }               
+
+       if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
+               fprintf(stderr, "machine %s rejected the tconX on the IPC$ share. Error was : %s.\n",
+                       remote_machine, cli_errstr(&cli) );
+               cli_shutdown(&cli);
+               return False;
+       }
+
+       if(!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) {
+               fprintf(stderr, "machine %s rejected the password change: Error was : %s.\n",
+                       remote_machine, cli_errstr(&cli) );
+               cli_shutdown(&cli);
+               return False;
+       }
+       
+       cli_shutdown(&cli);
+       return True;
+}
+
+
+/*************************************************************
+add a new user to the local smbpasswd file
+*************************************************************/
+static BOOL add_new_user(char *user_name, uid_t uid, BOOL trust_account, 
+                        BOOL disable_user, BOOL set_no_password,
+                        char *new_p16, char *new_nt_p16)
+{
+       struct smb_passwd new_smb_pwent;
+
+       /* Create a new smb passwd entry and set it to the given password. */
+       new_smb_pwent.smb_userid = uid;
+       new_smb_pwent.smb_name = user_name; 
+       new_smb_pwent.smb_passwd = NULL;
+       new_smb_pwent.smb_nt_passwd = NULL;
+       new_smb_pwent.acct_ctrl = (trust_account ? ACB_WSTRUST : ACB_NORMAL);
+       
+       if(disable_user) {
+               new_smb_pwent.acct_ctrl |= ACB_DISABLED;
+       } else if (set_no_password) {
+               new_smb_pwent.acct_ctrl |= ACB_PWNOTREQ;
+       } else {
+               new_smb_pwent.smb_passwd = new_p16;
+               new_smb_pwent.smb_nt_passwd = new_nt_p16;
+       }
+       
+       return add_smbpwd_entry(&new_smb_pwent);
+}
+
+
+/*************************************************************
+change a password entry in the local smbpasswd file
+*************************************************************/
+static BOOL local_password_change(char *user_name, BOOL trust_account, BOOL add_user,
+                                BOOL enable_user, BOOL disable_user, BOOL set_no_password,
+                                char *new_passwd)
+{
+       struct passwd  *pwd;
+       void *vp;
+       struct smb_passwd *smb_pwent;
+       uchar           new_p16[16];
+       uchar           new_nt_p16[16];
+
+       pwd = getpwnam(user_name);
+       
+       /*
+        * Check for a machine account.
+        */
+       
+       if(trust_account && !pwd) {
+               fprintf(stderr, "User %s does not exist in system password file (usually /etc/passwd). Cannot add machine account without a valid system user.\n",
+                       user_name);
+               return False;
+       }
+
+       /* Calculate the MD4 hash (NT compatible) of the new password. */
+       nt_lm_owf_gen(new_passwd, new_nt_p16, new_p16);
+
+       /*
+        * Open the smbpaswd file.
+        */
+       vp = startsmbpwent(True);
+       if (!vp && errno == ENOENT) {
+               FILE *fp;
+               fprintf(stderr,"smbpasswd file did not exist - attempting to create it.\n");
+               fp = fopen(lp_smb_passwd_file(), "w");
+               if (fp) {
+                       fprintf(fp, "# Samba SMB password file\n");
+                       fclose(fp);
+                       vp = startsmbpwent(True);
+               }
+       }
+
+       if (!vp) {
+               perror(lp_smb_passwd_file());
+               return False;
+       }
   
-  /* Get the smb passwd entry for this user */
-  smb_pwent = getsmbpwnam(user_name);
-  if (smb_pwent == NULL) {
-    if(add_user == False) {
-      fprintf(stderr, "%s: Failed to find entry for user %s.\n",
-             prog_name, pwd->pw_name);
-      endsmbpwent(vp);
-      exit(1);
-    }
-
-    /* Create a new smb passwd entry and set it to the given password. */
-    {
-      struct smb_passwd new_smb_pwent;
-
-      new_smb_pwent.smb_userid = pwd->pw_uid;
-      new_smb_pwent.smb_name = pwd->pw_name; 
-      new_smb_pwent.smb_passwd = NULL;
-      new_smb_pwent.smb_nt_passwd = NULL;
-      new_smb_pwent.acct_ctrl = (trust_account ? ACB_WSTRUST : ACB_NORMAL);
-
-      if(disable_user) {
-        new_smb_pwent.acct_ctrl |= ACB_DISABLED;
-      } else if (set_no_password) {
-        new_smb_pwent.acct_ctrl |= ACB_PWNOTREQ;
-      } else {
-        new_smb_pwent.smb_passwd = new_p16;
-        new_smb_pwent.smb_nt_passwd = new_nt_p16;
-      }
-
-      if(add_smbpwd_entry(&new_smb_pwent) == False) {
-        fprintf(stderr, "%s: Failed to add entry for user %s.\n", 
-                prog_name, pwd->pw_name);
-        endsmbpwent(vp);
-        exit(1);
-      }
-      
-      endsmbpwent(vp);
-      printf("%s: Added user %s.\n", prog_name, user_name);
-      exit(0);
-    }
-  } else {
-         /* the entry already existed */
-         add_user = False;
-  }
-
-  /*
-   * We are root - just write the new password
-   * and the valid last change time.
-   */
-
-  if(disable_user)
-    smb_pwent->acct_ctrl |= ACB_DISABLED;
-  else if (enable_user) {
-    if(smb_pwent->smb_passwd == NULL) {
-      prompt_for_new_password(new_passwd,stdin_passwd_get);
-      nt_lm_owf_gen( new_passwd, new_nt_p16, new_p16);
-      smb_pwent->smb_passwd = new_p16;
-      smb_pwent->smb_nt_passwd = new_nt_p16;
-    }
-    smb_pwent->acct_ctrl &= ~ACB_DISABLED;
-  } else if (set_no_password) {
-    smb_pwent->acct_ctrl |= ACB_PWNOTREQ;
-    /* This is needed to preserve ACB_PWNOTREQ in mod_smbfilepwd_entry */
-    smb_pwent->smb_passwd = NULL;
-    smb_pwent->smb_nt_passwd = NULL;
-  } else {
-    smb_pwent->acct_ctrl &= ~ACB_PWNOTREQ;
-    smb_pwent->smb_passwd = new_p16;
-    smb_pwent->smb_nt_passwd = new_nt_p16;
-  }
-
-  if(mod_smbpwd_entry(smb_pwent,True) == False) {
-    fprintf(stderr, "%s: Failed to modify entry for user %s.\n",
-            prog_name, pwd->pw_name);
-    endsmbpwent(vp);
-    exit(1);
-  }
-
-  endsmbpwent(vp);
-  if(disable_user)
-    printf("User %s disabled.\n", user_name);
-  else if(enable_user)
-    printf("User %s enabled.\n", user_name);
-  else if (set_no_password)
-    printf("User %s - set to no password.\n", user_name);
-  else
-    printf("Password changed for user %s.\n", user_name);
-  return 0;
+       /* Get the smb passwd entry for this user */
+       smb_pwent = getsmbpwnam(user_name);
+       if (smb_pwent == NULL) {
+               if(add_user == False) {
+                       fprintf(stderr, "Failed to find entry for user %s.\n",
+                               pwd->pw_name);
+                       endsmbpwent(vp);
+                       return False;
+               }
+
+               if (add_new_user(user_name, pwd->pw_uid, trust_account, disable_user,
+                                set_no_password, new_p16, new_nt_p16)) {
+                       printf("Added user %s.\n", user_name);
+                       endsmbpwent(vp);
+                       return True;
+               } else {
+                       fprintf(stderr, "Failed to add entry for user %s.\n", user_name);
+                       endsmbpwent(vp);
+                       return False;
+               }
+       } else {
+               /* the entry already existed */
+               add_user = False;
+       }
+
+       /*
+        * We are root - just write the new password
+        * and the valid last change time.
+        */
+
+       if(disable_user) {
+               smb_pwent->acct_ctrl |= ACB_DISABLED;
+       } else if (enable_user) {
+               if(smb_pwent->smb_passwd == NULL) {
+                       smb_pwent->smb_passwd = new_p16;
+                       smb_pwent->smb_nt_passwd = new_nt_p16;
+               }
+               smb_pwent->acct_ctrl &= ~ACB_DISABLED;
+       } else if (set_no_password) {
+               smb_pwent->acct_ctrl |= ACB_PWNOTREQ;
+               /* This is needed to preserve ACB_PWNOTREQ in mod_smbfilepwd_entry */
+               smb_pwent->smb_passwd = NULL;
+               smb_pwent->smb_nt_passwd = NULL;
+       } else {
+               smb_pwent->acct_ctrl &= ~ACB_PWNOTREQ;
+               smb_pwent->smb_passwd = new_p16;
+               smb_pwent->smb_nt_passwd = new_nt_p16;
+       }
+       
+       if(mod_smbpwd_entry(smb_pwent,True) == False) {
+               fprintf(stderr, "Failed to modify entry for user %s.\n",
+                       pwd->pw_name);
+               endsmbpwent(vp);
+               return False;
+       }
+
+       endsmbpwent(vp);
+
+       return True;
+}
+
+
+/*************************************************************
+change a password either locally or remotely
+*************************************************************/
+static BOOL password_change(const char *remote_machine, char *user_name, 
+                           char *old_passwd, char *new_passwd, 
+                           BOOL add_user, BOOL enable_user, 
+                           BOOL disable_user, BOOL set_no_password,
+                           BOOL trust_account)
+{
+       if (remote_machine != NULL) {
+               if (add_user || enable_user || disable_user || set_no_password || trust_account) {
+                       /* these things can't be done remotely yet */
+                       return False;
+               }
+               return remote_password_change(remote_machine, user_name, old_passwd, new_passwd);
+       }
+       
+       return local_password_change(user_name, trust_account, add_user, enable_user, 
+                                    disable_user, set_no_password, new_passwd);
+}
+
+
+/*************************************************************
+handle password changing for root
+*************************************************************/
+static int process_root(int argc, char *argv[])
+{
+       struct passwd  *pwd;
+       int ch;
+       BOOL joining_domain = False;
+       BOOL trust_account = False;
+       BOOL add_user = False;
+       BOOL disable_user = False;
+       BOOL enable_user = False;
+       BOOL set_no_password = False;
+       BOOL stdin_passwd_get = False;
+       char *user_name = NULL;
+       char *new_domain = NULL;
+       char *new_passwd = NULL;
+       char *old_passwd = NULL;
+       char *remote_machine = NULL;
+
+       while ((ch = getopt(argc, argv, "adehmnj:r:sR:D:U:")) != EOF) {
+               switch(ch) {
+               case 'a':
+                       add_user = True;
+                       break;
+               case 'd':
+                       disable_user = True;
+                       new_passwd = "XXXXXX";
+                       break;
+               case 'e':
+                       enable_user = True;
+                       break;
+               case 'D':
+                       DEBUGLEVEL = atoi(optarg);
+                       break;
+               case 'n':
+                       set_no_password = True;
+                       new_passwd = "NO PASSWORD";
+               case 'r':
+                       remote_machine = optarg;
+                       break;
+               case 's':
+                       set_line_buffering(stdin);
+                       set_line_buffering(stdout);
+                       set_line_buffering(stderr);
+                       stdin_passwd_get = True;
+                       break;
+               case 'R':
+                       lp_set_name_resolve_order(optarg);
+                       break;
+               case 'm':
+                       trust_account = True;
+                       break;
+               case 'j':
+                       new_domain = optarg;
+                       strupper(new_domain);
+                       joining_domain = True;
+                       break;
+               case 'U':
+                       user_name = optarg;
+                       break;
+               default:
+                       usage();
+               }
+       }
+       
+       argc -= optind;
+       argv += optind;
+
+
+       /*
+        * Ensure add_user and either remote machine or join domain are
+        * not both set.
+        */     
+       if(add_user && ((remote_machine != NULL) || joining_domain)) {
+               usage();
+       }
+       
+       if(joining_domain) {
+               if (argc != 0) usage();
+               return join_domain(new_domain, remote_machine);
+       }
+
+       /*
+        * Deal with root - can add a user, but only locally.
+        */
+
+       switch(argc) {
+       case 0:
+               break;
+       case 1:
+               user_name = argv[0];
+               break;
+       case 2:
+               user_name = argv[0];
+               new_passwd = argv[1];
+               break;
+       default:
+               usage();
+       }
+
+       if (!user_name && (pwd = getpwuid(0))) {
+               user_name = xstrdup(pwd->pw_name);
+       } 
+
+       if (!user_name) {
+               fprintf(stderr,"You must specify a username\n");
+               exit(1);
+       }
+
+       if (!remote_machine && !Get_Pwnam(user_name, True)) {
+               fprintf(stderr, "User \"%s\" was not found in system password file.\n", 
+                       user_name);
+               exit(1);
+       }
+
+       if (user_name[strlen(user_name)-1] == '$') {
+               user_name[strlen(user_name)-1] = 0;
+       }
+
+       if (trust_account) {
+               /* add the $ automatically */
+               static fstring buf;
+
+               if (add_user) {
+                       new_passwd = xstrdup(user_name);
+                       strlower(new_passwd);
+               }
+
+               slprintf(buf, sizeof(buf)-1, "%s$", user_name);
+               user_name = buf;
+       }
+
+       if (remote_machine != NULL) {
+               old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
+       }
+       
+       if (!new_passwd) {
+               new_passwd = prompt_for_new_password(stdin_passwd_get);
+       }
+       
+       if (!password_change(remote_machine, user_name, old_passwd, new_passwd,
+                            add_user, enable_user, disable_user, set_no_password,
+                            trust_account)) {
+               fprintf(stderr,"Failed to change password entry for %s\n", user_name);
+               return 1;
+       } 
+
+       if(disable_user) {
+               printf("User %s disabled.\n", user_name);
+       } else if(enable_user) {
+               printf("User %s enabled.\n", user_name);
+       } else if (set_no_password) {
+               printf("User %s - set to no password.\n", user_name);
+       } else {
+               printf("Password changed for user %s\n", user_name);
+       }
+       return 0;
+}
+
+
+/*************************************************************
+handle password changing for non-root
+*************************************************************/
+static int process_nonroot(int argc, char *argv[])
+{
+       struct passwd  *pwd = NULL;
+       int ch;
+       BOOL stdin_passwd_get = False;
+       char *old_passwd = NULL;
+       char *remote_machine = NULL;
+       char *user_name = NULL;
+       char *new_passwd = NULL;
+
+       while ((ch = getopt(argc, argv, "hD:r:sU:")) != EOF) {
+               switch(ch) {
+               case 'D':
+                       DEBUGLEVEL = atoi(optarg);
+                       break;
+               case 'r':
+                       remote_machine = optarg;
+                       break;
+               case 's':
+                       set_line_buffering(stdin);
+                       set_line_buffering(stdout);
+                       set_line_buffering(stderr);
+                       stdin_passwd_get = True;
+                       break;
+               case 'U':
+                       user_name = optarg;
+                       break;
+               default:
+                       usage();
+               }
+       }
+       
+       argc -= optind;
+       argv += optind;
+
+       if(argc > 1) {
+               usage();
+       }
+       
+       if (argc == 1) {
+               new_passwd = argv[0];
+       }
+       
+       if (!user_name) {
+               pwd = getpwuid(getuid());
+               if (pwd) {
+                       user_name = xstrdup(pwd->pw_name);
+               } else {
+                       fprintf(stderr,"you don't exist - go away\n");
+                       exit(1);
+               }
+       }
+       
+       /*
+        * A non-root user is always setting a password
+        * via a remote machine (even if that machine is
+        * localhost).
+        */     
+       if (remote_machine == NULL) {
+               remote_machine = "127.0.0.1";
+       }
+
+
+       if (remote_machine != NULL) {
+               old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
+       }
+       
+       if (!new_passwd) {
+               new_passwd = prompt_for_new_password(stdin_passwd_get);
+       }
+       
+       if (!new_passwd) {
+               printf("unable to get new password\n");
+               exit(0);
+       }
+
+       if (!password_change(remote_machine, user_name, old_passwd, new_passwd,
+                            False, False, False, False, False)) {
+               fprintf(stderr,"Failed to change password for %s\n", user_name);
+               return 1;
+       }
+
+       printf("Password changed for user %s\n", user_name);
+       return 0;
+}
+
+
+
+/*********************************************************
+ Start here.
+**********************************************************/
+int main(int argc, char **argv)
+{      
+       static pstring servicesf = CONFIGFILE;
+
+       TimeInit();
+       
+       setup_logging("smbpasswd", True);
+       
+       charset_initialise();
+       
+       if(!initialize_password_db()) {
+               fprintf(stderr, "Can't setup password database vectors.\n");
+               exit(1);
+       }
+
+       if (!lp_load(servicesf,True,False,False)) {
+               fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
+                       servicesf);
+               exit(1);
+       }
+
+       if(!get_myname(myhostname,NULL)) {
+               fprintf(stderr, "unable to get my hostname.\n");
+               exit(1);
+       }
+
+       /*
+        * Set the machine NETBIOS name if not already
+        * set from the config file. 
+        */ 
+    
+       if (!*global_myname) {   
+               char *p;
+               fstrcpy(global_myname, myhostname);
+               p = strchr(global_myname, '.' );
+               if (p) *p = 0;
+       }           
+       strupper(global_myname);
+
+       codepage_initialise(lp_client_code_page());
+
+       /* Check the effective uid - make sure we are not setuid */
+       if ((geteuid() == (uid_t)0) && (getuid() != (uid_t)0)) {
+               fprintf(stderr, "smbpasswd must *NOT* be setuid root.\n");
+               exit(1);
+       }
+
+       if (getuid() == 0) {
+               return process_root(argc, argv);
+       } 
+
+       return process_nonroot(argc, argv);
 }