Problems running smbclient noninteractively

Russell Kliese russell at eminence.com.au
Fri Feb 18 02:59:55 GMT 2005


Michael B Allen wrote:

>Russell Kliese said:
>  
>
>>Is there problems running smbpasswd noninteractivly?
>>    
>>
>
>A lot of programs behave differently depending on whether or not their
>connected to a terminal. You could try system() but the only sure-fire way
>to run an interactive program without a terminal is to do I/O with a pty
>[1] like an xterm would.
>  
>
Thanks for your help. I ended up using expect to interact with 
smbpasswd. I have included a test application I wrote because it might 
be helpful to others (particularly since the documentation for expect is 
quite sparse). I hope this isn't too off topic.

Russell

/*
 * Example of using expect with smbpasswd to add a user and set their 
password
 *
 * Perhaps not the most eloquent solution
 *
 * Compile with gcc -o smbpasswdTest -lexpect5.42 -lstdc++ smbpasswdTest.cpp
 */

#include <stdio.h>
#include <string>
#include <iostream>
#include <sstream>
#include <tcl8.4/expect.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>


/** Causes the stdout to be written to /dev/null
 * upon instantiation
 */
class StdoutObliviate {
public:
  StdoutObliviate() {
    int fdNull;
    if(-1 == (fdNull = open("/dev/null", O_WRONLY)))
      throw std::string("Couldn't open /dev/null");
    oldStdOut = dup(fileno(stdout));
    dup2(fdNull, fileno(stdout));
  }
   
  ~StdoutObliviate() {
    dup2(oldStdOut, fileno(stdout));
  }
private:
  int oldStdOut;
};

/** Adds a user and sets their password using smbpasswd
 *
 * @param userName The user name of the user to add
 * @param password The password to assign to the user
 * \raises std::string with a description of what caused the exception
 */
void createSMBUser(std::string userName, std::string password) {
  /*
   * Write everything on stdout to /dev/null
   */
  StdoutObliviate stdoutObliviate;
   
  int fd;
  exp_timeout = 2; // 2 seconds timeout. It shouldn't take longer than this.
   
  /*
   * turn off echo
   */
  exp_stty_init = "-echo";

  /*
   * fire up smbpasswd with the appropriate arguments
   */   
  if (-1 == (fd = exp_spawnl("/usr/bin/smbpasswd","smbpasswd", "-a", 
"-s", "russell", (char *)0))) {
    throw std::string(std::string("Couldn't spawn smbpasswd: ") + 
strerror(errno));
  }
   
  /*
   * send the password
   */
  std::string input = password + "\r" + password + "\r";
  if (-1 == write(fd,input.c_str(),input.length())) {
    throw std::string("Error sending password to smbpasswd");
  }
  /*
   * Wait for smbpasswd to finish (or timeout)
   */
  switch (exp_expectl(fd,exp_end)) {
  case EXP_TIMEOUT:
    throw std::string("smbpasswd timed out after sending password");
  case EXP_EOF:
    std::string expBuffer(exp_buffer);
    if(expBuffer.length())
      std::cerr << "smbpasswd chatter: " << exp_buffer << std::endl;
  }
   
  /*
   * See how smbpasswd finished
   */
  int status;
  wait(&status); // wait for smbpasswd to terminate
  if(WIFEXITED(status)) {
    int returnValue = WEXITSTATUS(status);
    if(returnValue != 0) {
      std::ostringstream os;
      os << "smbpasswd exited with exit value: " << returnValue;
      throw std::string(os.str());
    }
  } else {
    throw std::string("smbpasswd exited abnormally");
  }
}

int main(){
  try {
    createSMBUser("user", "test");
    std::cout << "User created successfully" << std::endl;
    return 0;
  } catch (std::string& exception) {
    std::cerr << "Problem adding user: " << exception << std::endl;
  }
  return 1;
}

-- 

<http://www.eminence.com.au/> Eminence Technology Pty Ltd
PO Box 118, Moorooka QLD 4105
Web: www.eminence.com.au <http://www.eminence.com.au/>
Ph: +61-7-3277-4100
Fax: +61-7-3277-4577



More information about the samba-technical mailing list