addprinter and adddriver are working now :-)
authorGerald Carter <jerry@samba.org>
Thu, 15 Mar 2001 22:06:53 +0000 (22:06 +0000)
committerGerald Carter <jerry@samba.org>
Thu, 15 Mar 2001 22:06:53 +0000 (22:06 +0000)
source/libsmb/cli_spoolss.c
source/rpcclient/cmd_samr.c
source/rpcclient/cmd_spoolss.c
source/rpcclient/rpcclient.c

index 55eb4dc4b257faea2ab49672d993215bcc74d129..356ee8f03d7d20bf8a43a933471edf214cb23d86 100644 (file)
@@ -26,6 +26,8 @@
 
 #include "includes.h"
 
+extern pstring global_myname;
+
 /* Opens a SMB connection to the SPOOLSS pipe */
 struct cli_state *cli_spoolss_initialise(struct cli_state *cli, 
                                         char *system_name,
@@ -828,4 +830,108 @@ uint32 cli_spoolss_getprinterdriverdir (
        return result;  
 }
 
+/**********************************************************************
+ * Install a printer driver
+ */
+uint32 cli_spoolss_addprinterdriver (
+       struct cli_state        *cli, 
+       uint32                  level,
+       PRINTER_DRIVER_CTR      *ctr
+)
+{
+       prs_struct                      qbuf, rbuf;
+       SPOOL_Q_ADDPRINTERDRIVER        q;
+        SPOOL_R_ADDPRINTERDRIVER       r;
+       uint32                          result;
+       fstring                         server;
+
+       ZERO_STRUCT(q);
+       ZERO_STRUCT(r);
+
+        slprintf (server, sizeof(fstring), "\\\\%s", cli->desthost);
+        strupper (server);
+
+       /* Initialise input parameters */
+       prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+       prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+
+       /* write the request */
+       make_spoolss_q_addprinterdriver (&q, server, level, ctr);
+
+       /* Marshall data and send request */
+       if (!spoolss_io_q_addprinterdriver ("", &q, &qbuf, 0) ||
+           !rpc_api_pipe_req (cli, SPOOLSS_ADDPRINTERDRIVER, &qbuf, &rbuf)) 
+       {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+               
+       /* Unmarshall response */
+       if (!spoolss_io_r_addprinterdriver ("", &r, &rbuf, 0))
+       {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+               
+       /* Return output parameters */
+       result = r.status;
+
+       return result;  
+}
+
+/**********************************************************************
+ * Install a printer 
+ */
+uint32 cli_spoolss_addprinterex (
+       struct cli_state        *cli, 
+       uint32                  level,
+       PRINTER_INFO_CTR        *ctr
+)
+{
+       prs_struct                      qbuf, rbuf;
+       SPOOL_Q_ADDPRINTEREX            q;
+        SPOOL_R_ADDPRINTEREX           r;
+       uint32                          result;
+       fstring                         server,
+                                       client,
+                                       user;
+
+       ZERO_STRUCT(q);
+       ZERO_STRUCT(r);
+
+        slprintf (client, sizeof(fstring), "\\\\%s", cli->desthost);
+        strupper (client);
+        slprintf (server, sizeof(fstring), "\\\\%s", cli->desthost);
+        strupper (server);
+       fstrcpy  (user, cli->user_name);
+       
+
+       /* Initialise input parameters */
+       prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+       prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+
+       /* write the request */
+       make_spoolss_q_addprinterex (&q, server, client, user, level, ctr);
+
+       /* Marshall data and send request */
+       if (!spoolss_io_q_addprinterex ("", &q, &qbuf, 0) ||
+           !rpc_api_pipe_req (cli, SPOOLSS_ADDPRINTEREX, &qbuf, &rbuf)) 
+       {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+               
+       /* Unmarshall response */
+       if (!spoolss_io_r_addprinterex ("", &r, &rbuf, 0))
+       {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+               
+       /* Return output parameters */
+       result = r.status;
+
+       return result;  
+}
+
 
index 3772714cda3e5f886168905afff5e75e793e6dc5..908245f5dcee90b3ccec46eaf6bc323945514479 100644 (file)
@@ -25,7 +25,6 @@
 
 #include "includes.h"
 
-extern pstring server;
 extern DOM_SID domain_sid;
 
 /****************************************************************************
@@ -108,6 +107,7 @@ static uint32 cmd_samr_query_user(struct cli_state *cli, int argc, char **argv)
                got_user_pol = False;
        SAM_USERINFO_CTR user_ctr;
        SAM_USER_INFO_21 info_21;
+       fstring                 server;
        
        if (argc != 1) {
                printf("Usage: %s\n", argv[0]);
@@ -120,6 +120,9 @@ static uint32 cmd_samr_query_user(struct cli_state *cli, int argc, char **argv)
                return NT_STATUS_UNSUCCESSFUL;
        }
        
+       slprintf (server, sizeof(fstring), "\\\\%s", cli->desthost);
+       strupper (server);
+       
        if ((result = cli_samr_connect(cli, server, MAXIMUM_ALLOWED_ACCESS,
                                       &connect_pol)) !=
            NT_STATUS_NOPROBLEMO) {
@@ -223,6 +226,7 @@ static uint32 cmd_samr_query_group(struct cli_state *cli, int argc, char **argv)
        BOOL got_connect_pol = False, got_domain_pol = False,
                got_group_pol = False;
        GROUP_INFO_CTR group_ctr;
+       fstring                 server; 
        
        if (argc != 1) {
                printf("Usage: %s\n", argv[0]);
@@ -235,6 +239,9 @@ static uint32 cmd_samr_query_group(struct cli_state *cli, int argc, char **argv)
                return NT_STATUS_UNSUCCESSFUL;
        }
        
+       slprintf (server, sizeof(fstring), "\\\\%s", cli->desthost);
+       strupper (server);
+
        if ((result = cli_samr_connect(cli, server, MAXIMUM_ALLOWED_ACCESS,
                                       &connect_pol)) !=
            NT_STATUS_NOPROBLEMO) {
@@ -286,13 +293,18 @@ done:
 
 static uint32 cmd_samr_query_usergroups(struct cli_state *cli, int argc, char **argv) 
 {
-       POLICY_HND connect_pol, domain_pol, user_pol;
-       uint32 result = NT_STATUS_UNSUCCESSFUL;
-       BOOL got_connect_pol = False, got_domain_pol = False,
-               got_user_pol = False;
-       uint32 num_groups, user_rid;
-       DOM_GID *user_gids;
-       int i;
+       POLICY_HND              connect_pol, 
+                               domain_pol, 
+                               user_pol;
+       uint32                  result = NT_STATUS_UNSUCCESSFUL;
+       BOOL                    got_connect_pol = False, 
+                               got_domain_pol = False,
+                               got_user_pol = False;
+       uint32                  num_groups, 
+                               user_rid;
+       DOM_GID                 *user_gids;
+       int                     i;
+       fstring                 server;
        
        if (argc != 2) {
                printf("Usage: %s rid/name\n", argv[0]);
@@ -306,7 +318,10 @@ static uint32 cmd_samr_query_usergroups(struct cli_state *cli, int argc, char **
                fprintf (stderr, "Could not initialize samr pipe!\n");
                return NT_STATUS_UNSUCCESSFUL;
        }
-       
+
+       slprintf (server, sizeof(fstring), "\\\\%s", cli->desthost);
+       strupper (server);
+               
        if ((result = cli_samr_connect(cli, server, MAXIMUM_ALLOWED_ACCESS,
                                       &connect_pol)) !=
            NT_STATUS_NOPROBLEMO) {
@@ -366,6 +381,7 @@ static uint32 cmd_samr_query_groupmem(struct cli_state *cli, int argc, char **ar
                got_group_pol = False;
        uint32 num_members, *group_rids, *group_attrs, group_rid;
        int i;
+       fstring                 server;
        
        if (argc != 2) {
                printf("Usage: %s rid/name\n", argv[0]);
@@ -380,6 +396,9 @@ static uint32 cmd_samr_query_groupmem(struct cli_state *cli, int argc, char **ar
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       slprintf (server, sizeof(fstring), "\\\\%s", cli->desthost);
+       strupper (server);
+
        if ((result = cli_samr_connect(cli, server, MAXIMUM_ALLOWED_ACCESS,
                                       &connect_pol)) !=
            NT_STATUS_NOPROBLEMO) {
index b1160f182243ae7569143f18e53e387ad2ddf772..99a51eb338e9b91fa9d2a0b9efe2e1c5ca16057e 100644 (file)
@@ -32,21 +32,50 @@ extern pstring global_myname;
 extern pstring username, password;
 extern pstring workgroup;
 
-struct table {
-       char *long_archi;
-       char *short_archi;
+struct table_node {
+       char    *long_archi;
+       char    *short_archi;
+       int     version;
 };
  
-struct table archi_table[]= {
-
-       {"Windows 4.0",          "WIN40"    },
-       {"Windows NT x86",       "W32X86"   },
-       {"Windows NT R4000",     "W32MIPS"  },
-       {"Windows NT Alpha_AXP", "W32ALPHA" },
-       {"Windows NT PowerPC",   "W32PPC"   },
-       {NULL,                   ""         }
+struct table_node archi_table[]= {
+
+       {"Windows 4.0",          "WIN40",       0 },
+       {"Windows NT x86",       "W32X86",      2 },
+       {"Windows NT R4000",     "W32MIPS",     2 },
+       {"Windows NT Alpha_AXP", "W32ALPHA",    2 },
+       {"Windows NT PowerPC",   "W32PPC",      2 },
+       {NULL,                   "",            -1 }
 };
 
+/****************************************************************************
+function to do the mapping between the long architecture name and
+the short one.
+****************************************************************************/
+BOOL get_short_archi(char *short_archi, char *long_archi)
+{
+        int i=-1;
+
+        DEBUG(107,("Getting architecture dependant directory\n"));
+        do {
+                i++;
+        } while ( (archi_table[i].long_archi!=NULL ) &&
+                  StrCaseCmp(long_archi, archi_table[i].long_archi) );
+
+        if (archi_table[i].long_archi==NULL) {
+                DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
+                return FALSE;
+        }
+
+        StrnCpy (short_archi, archi_table[i].short_archi, strlen(archi_table[i].short_archi));
+
+        DEBUGADD(108,("index: [%d]\n", i));
+        DEBUGADD(108,("long architecture: [%s]\n", long_archi));
+        DEBUGADD(108,("short architecture: [%s]\n", short_archi));
+
+        return True;
+}
+
 
 /**********************************************************************
  * dummy function  -- placeholder
@@ -164,11 +193,11 @@ printer info level 0 display function
 ****************************************************************************/
 static void display_print_info_0(PRINTER_INFO_0 *i1)
 {
-       fstring name;
-       fstring the_server;
+       fstring         name;
+       fstring         the_server;
 
        unistr_to_ascii(name, i1->printername.buffer, sizeof(name) - 1);
-       unistr_to_ascii(server, i1->servername.buffer, sizeof(the_server) - 1);
+       unistr_to_ascii(the_server, i1->servername.buffer, sizeof(the_server) - 1);
 
        printf("\tprintername:[%s]\n", name);
        printf("\tservername:[%s]\n", the_server);
@@ -455,7 +484,8 @@ static uint32 cmd_spoolss_getprinter(struct cli_state *cli, int argc, char **arg
        BOOL            opened_hnd = False;
        PRINTER_INFO_CTR ctr;
        fstring         printername, 
-                       servername;
+                       servername,
+                       username;
 
        if (argc == 1 || argc > 3) {
                printf("Usage: %s printername [level]\n", argv[0]);
@@ -473,9 +503,10 @@ static uint32 cmd_spoolss_getprinter(struct cli_state *cli, int argc, char **arg
                info_level = atoi(argv[2]);
        }
 
-       slprintf (printername, sizeof(fstring), "\\\\%s\\%s", server, argv[1]);
        slprintf (servername, sizeof(fstring), "\\\\%s", cli->desthost);
        strupper (servername);
+       slprintf (printername, sizeof(fstring), "\\\\%s\\%s", servername, argv[1]);
+       fstrcpy  (username, cli->user_name);
        
        /* get a printer handle */
        if ((result = cli_spoolss_open_printer_ex(
@@ -483,7 +514,7 @@ static uint32 cmd_spoolss_getprinter(struct cli_state *cli, int argc, char **arg
                username, &pol)) != NT_STATUS_NOPROBLEMO) {
                goto done;
        }
-
        opened_hnd = True;
 
        /* Get printer info */
@@ -833,7 +864,7 @@ static void display_printdriverdir_1(DRIVER_DIRECTORY_1 *i1)
 }
 
 /***********************************************************************
- * Get printer information
+ * Get printer driver directory information
  */
 static uint32 cmd_spoolss_getdriverdir(struct cli_state *cli, int argc, char **argv)
 {
@@ -877,13 +908,254 @@ static uint32 cmd_spoolss_getdriverdir(struct cli_state *cli, int argc, char **a
                
 }
 
+/*******************************************************************************
+ set the version and environment fields of a DRIVER_INFO_3 struct
+ ******************************************************************************/
+void set_drv_info_3_env (DRIVER_INFO_3 *info, const char *arch)
+{
+
+       int i;
+       
+       for (i=0; archi_table[i].long_archi != NULL; i++) 
+       {
+               if (strcmp(arch, archi_table[i].short_archi) == 0)
+               {
+                       info->version = archi_table[i].version;
+                       init_unistr (&info->architecture, archi_table[i].long_archi);
+                       break;
+               }
+       }
+       
+       if (archi_table[i].long_archi == NULL)
+       {
+               DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
+       }
+       
+       return;
+}
+
+
+/**************************************************************************
+ wrapper for strtok to get the next parameter from a delimited list.
+ Needed to handle the empty parameter string denoted by "NULL"
+ *************************************************************************/
+static char* get_driver_3_param (char* str, char* delim, UNISTR* dest)
+{
+       char    *ptr;
+
+       /* get the next token */
+       ptr = strtok(str, delim);
+
+       /* a string of 'NULL' is used to represent an empty
+          parameter because two consecutive delimiters
+          will not return an empty string.  See man strtok(3)
+          for details */
+       if (StrCaseCmp(ptr, "NULL") == 0)
+               ptr = NULL;
+
+       if (dest != NULL)
+               init_unistr(dest, ptr); 
+
+       return ptr;
+}
+
+/********************************************************************************
+ fill in the members of a DRIVER_INFO_3 struct using a character 
+ string in the form of
+        <Long Printer Name>:<Driver File Name>:<Data File Name>:\
+            <Config File Name>:<Help File Name>:<Language Monitor Name>:\
+            <Default Data Type>:<Comma Separated list of Files> 
+ *******************************************************************************/
+static BOOL init_drv_info_3_members (DRIVER_INFO_3 *info, char *args)
+{
+       char    *str, *str2;
+       uint32  len, i;
+       
+       /* fill in the UNISTR fields */
+       str = get_driver_3_param (args, ":", &info->name);
+       str = get_driver_3_param (NULL, ":", &info->driverpath);
+       str = get_driver_3_param (NULL, ":", &info->datafile);
+       str = get_driver_3_param (NULL, ":", &info->configfile);
+       str = get_driver_3_param (NULL, ":", &info->helpfile);
+       str = get_driver_3_param (NULL, ":", &info->monitorname);
+       str = get_driver_3_param (NULL, ":", &info->defaultdatatype);
+
+       /* <Comma Separated List of Dependent Files> */
+       str2 = get_driver_3_param (NULL, ":", NULL); /* save the beginning of the string */
+       str = str2;                     
+
+       /* begin to strip out each filename */
+       str = strtok(str, ",");         
+       len = 0;
+       while (str != NULL)
+       {
+               /* keep a cumlative count of the str lengths */
+               len += strlen(str)+1;
+               str = strtok(NULL, ",");
+       }
+
+       /* allocate the space; add one extra slot for a terminating NULL.
+          Each filename is NULL terminated and the end contains a double
+          NULL */
+       if ((info->dependentfiles=(uint16*)malloc((len+1)*sizeof(uint16))) == NULL)
+       {
+               DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n"));
+               return False;
+       }
+       for (i=0; i<len; i++)
+       {
+               info->dependentfiles[i] = (uint16)str2[i];
+       }
+       info->dependentfiles[len] = '\0';
+
+       return True;
+}
+
+
+static uint32 cmd_spoolss_addprinterdriver (struct cli_state *cli, int argc, char **argv)
+{
+       uint32                  result,
+                               level = 3;
+       PRINTER_DRIVER_CTR      ctr;
+       DRIVER_INFO_3           info3;
+       fstring                 arch;
+       fstring                 driver_name;
+
+       /* parse the command arguements */
+       if (argc != 3)
+       {
+               printf ("Usage: %s <Environment>\\\n", argv[0]);
+               printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
+               printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
+               printf ("\t<Default Data Type>:<Comma Separated list of Files>\n");
+
+               return NT_STATUS_NOPROBLEMO;
+        }
+
+       /* Initialise RPC connection */
+       if (!cli_nt_session_open (cli, PIPE_SPOOLSS)) 
+       {
+               fprintf (stderr, "Could not initialize spoolss pipe!\n");
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+               
+       /* Fill in the DRIVER_INFO_3 struct */
+       ZERO_STRUCT(info3);
+       if (!get_short_archi(arch, argv[1]))
+       {
+               printf ("Error Unknown architechture [%s]\n", argv[1]);
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+       else
+               set_drv_info_3_env(&info3, arch);
+
+       if (!init_drv_info_3_members(&info3, argv[2]))
+       {
+               printf ("Error Invalid parameter list - %s.\n", argv[2]);
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+
+       /* Get the directory.  Only use Info level 1 */
+       ctr.info3 = &info3;
+       if ((result = cli_spoolss_addprinterdriver (cli, level, &ctr)) 
+            != NT_STATUS_NO_PROBLEMO)
+       {
+               return result;
+       }
+
+       unistr_to_ascii (driver_name, info3.name.buffer, sizeof(driver_name)-1);
+       printf ("Printer Driver %s successfully installed.\n", driver_name);
+
+       /* cleanup */
+       cli_nt_session_close (cli);
+       
+       return result;
+               
+}
+
+
+static uint32 cmd_spoolss_addprinterex (struct cli_state *cli, int argc, char **argv)
+{
+       uint32                  result,
+                               level = 2;
+       PRINTER_INFO_CTR        ctr;
+       PRINTER_INFO_2          info2;
+       fstring                 server;
+       
+       /* parse the command arguements */
+       if (argc != 5)
+       {
+               printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
+               return NT_STATUS_NOPROBLEMO;
+        }
+
+        slprintf (server, sizeof(fstring), "\\\\%s", cli->desthost);
+        strupper (server);
+
+       /* Initialise RPC connection */
+       if (!cli_nt_session_open (cli, PIPE_SPOOLSS)) 
+       {
+               fprintf (stderr, "Could not initialize spoolss pipe!\n");
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+               
+       /* Fill in the DRIVER_INFO_3 struct */
+       ZERO_STRUCT(info2);
+#if 0  /* JERRY */
+       init_unistr( &info2.servername,         server);
+#endif
+       init_unistr( &info2.printername,        argv[1]);
+       init_unistr( &info2.sharename,          argv[2]);
+       init_unistr( &info2.drivername,         argv[3]);
+       init_unistr( &info2.portname,           argv[4]);
+       init_unistr( &info2.comment,            "Created by rpcclient");
+       init_unistr( &info2.printprocessor,     "winprint");
+       init_unistr( &info2.datatype,           "RAW");
+       info2.devmode =         NULL;
+       info2.secdesc =         NULL;
+       info2.attributes        = PRINTER_ATTRIBUTE_SHARED;
+       info2.priority          = 0;
+       info2.defaultpriority   = 0;
+       info2.starttime         = 0;
+       info2.untiltime         = 0;
+       
+       /* These three fields must not be used by AddPrinter() 
+          as defined in the MS Platform SDK documentation..  
+          --jerry
+       info2.status            = 0;
+       info2.cjobs             = 0;
+       info2.averageppm        = 0;
+       */
+
+
+
+       /* Get the directory.  Only use Info level 1 */
+       ctr.printers_2 = &info2;
+       if ((result = cli_spoolss_addprinterex (cli, level, &ctr)) 
+            != NT_STATUS_NO_PROBLEMO)
+       {
+               return result;
+       }
+
+       printf ("Printer %s successfully installed.\n", argv[1]);
+
+       /* cleanup */
+       cli_nt_session_close (cli);
+       
+       return result;
+               
+}
+
 
 /* List of commands exported by this module */
 struct cmd_set spoolss_commands[] = {
 
        { "SPOOLSS",            NULL,                           "" },
-       { "adddriver",          cmd_spoolss_not_implemented,    "Add a print driver (*)" },
-       { "addprinter",         cmd_spoolss_not_implemented,    "Add a printer (*)" },
+       { "adddriver",          cmd_spoolss_addprinterdriver,   "Add a print driver" },
+       { "addprinter",         cmd_spoolss_addprinterex,       "Add a printer" },
        { "enumdata",           cmd_spoolss_not_implemented,    "Enumerate printer data (*)" },
        { "enumjobs",           cmd_spoolss_not_implemented,    "Enumerate print jobs (*)" },
        { "enumports",          cmd_spoolss_enum_ports,         "Enumerate printer ports" },
index 1b434dd696d4beb8243775e945e1fe0d72b9eb02..42d9d4e486254d78090a953eb311ef9eada77b6b 100644 (file)
@@ -30,14 +30,105 @@ extern struct cmd_set lsarpc_commands[];
 extern struct cmd_set samr_commands[];
 extern struct cmd_set spoolss_commands[];
 
-pstring password;
-pstring username;
-pstring workgroup;
-pstring server;
-
 
 DOM_SID domain_sid;
+/***********************************************************************
+ * read in username/password credentials from a file
+ */
+static void read_authfile (
+       char *filename, 
+       char* username, 
+       char* password, 
+       char* domain
+)
+{
+       FILE *auth;
+        fstring buf;
+        uint16 len = 0;
+       char *ptr, *val, *param;
+                               
+       if ((auth=sys_fopen(filename, "r")) == NULL)
+       {
+               printf ("ERROR: Unable to open credentials file!\n");
+               return;
+       }
+                                
+       while (!feof(auth))
+       {  
+               /* get a line from the file */
+               if (!fgets (buf, sizeof(buf), auth))
+                       continue;
+               
+               len = strlen(buf);
+               
+               /* skip empty lines */                  
+               if ((len) && (buf[len-1]=='\n'))
+               {
+                       buf[len-1] = '\0';
+                       len--;
+               }       
+               if (len == 0)
+                       continue;
+                                       
+               /* break up the line into parameter & value.
+                  will need to eat a little whitespace possibly */
+               param = buf;
+               if (!(ptr = strchr (buf, '=')))
+                       continue;
+               val = ptr+1;
+               *ptr = '\0';
+                                       
+               /* eat leading white space */
+               while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
+                       val++;
+                                       
+               if (strwicmp("password", param) == 0)
+                       fstrcpy (password, val);
+               else if (strwicmp("username", param) == 0)
+                       fstrcpy (username, val);
+               else if (strwicmp("domain", param) == 0)
+                       fstrcpy (domain, val);
+                                               
+               memset(buf, 0, sizeof(buf));
+       }
+       fclose(auth);
+       
+       return;
+}
+
+static char* next_command (
+       char**  cmdstr
+)
+{
+       static pstring          command;
+       char                    *p;
+       
+       if (!cmdstr || !(*cmdstr))
+               return NULL;
+       
+       p = strchr(*cmdstr, ';');
+       if (p)
+               *p = '\0';
+       pstrcpy(command, *cmdstr);
+       *cmdstr = p;
+       
+       return command;
+}
 
+static void get_username (char *username)
+{
+        if (getenv("USER"))
+                pstrcpy(username,getenv("USER"));
+        if (*username == 0 && getenv("LOGNAME"))
+                pstrcpy(username,getenv("LOGNAME"));
+        if (*username == 0) {
+                pstrcpy(username,"GUEST");
+        }
+
+       return;
+}
 
 /* Fetch the SID for this domain */
 void fetch_domain_sid(struct cli_state *cli)
@@ -75,7 +166,7 @@ void fetch_domain_sid(struct cli_state *cli)
        return;
 
  error:
-       fprintf(stderr, "could not obtain sid for domain %s\n", workgroup);
+       fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain);
 
        if (result != NT_STATUS_NOPROBLEMO) {
                fprintf(stderr, "error: %s\n", get_nt_error_msg(result));
@@ -87,7 +178,7 @@ void fetch_domain_sid(struct cli_state *cli)
 /* Initialise client credentials for authenticated pipe access */
 
 void init_rpcclient_creds(struct ntuser_creds *creds, char* username,
-                         char* workgroup, char* password)
+                         char* domain, char* password)
 {
        ZERO_STRUCTP(creds);
        
@@ -98,7 +189,7 @@ void init_rpcclient_creds(struct ntuser_creds *creds, char* username,
        }
 
        fstrcpy(creds->user_name, username);
-       fstrcpy(creds->domain, workgroup);
+       fstrcpy(creds->domain, domain);
 }
 
 /* List to hold groups of commands */
@@ -327,6 +418,7 @@ static void usage(char *pname)
 {
        printf("Usage: %s server [options]\n", pname);
 
+       printf("\t-A authfile           file containing user credentials\n");
        printf("\t-c \"command string\"   execute semicolon separated cmds\n");
        printf("\t-d debuglevel         set the debuglevel\n");
        printf("\t-l logfile            name of logfile to use as opposed to stdout\n");
@@ -334,7 +426,7 @@ static void usage(char *pname)
        printf("\t-N                    don't ask for a password\n");
        printf("\t-s configfile         specify an alternative config file\n");
        printf("\t-U username           set the network username\n");
-       printf("\t-W workgroup          set the workgroup name\n");
+       printf("\t-W domain             set the domain name for user account\n");
        printf("\n");
 }
 
@@ -342,19 +434,25 @@ static void usage(char *pname)
 
  int main(int argc, char *argv[])
 {
-       extern char *optarg;
-       extern int optind;
-       struct in_addr dest_ip;
-       extern pstring global_myname;
-       BOOL got_pass = False;
-       BOOL interactive = True;
-       BOOL have_ip = False;
-       int opt;
-       int olddebug;
-       pstring cmdstr = "", servicesf = CONFIGFILE;
+       extern char             *optarg;
+       extern int              optind;
+       struct in_addr          dest_ip;
+       extern pstring          global_myname;
+       BOOL                    got_pass = False;
+       BOOL                    interactive = True;
+       BOOL                    have_ip = False;
+       int                     opt;
+       int                     olddebug;
+       pstring                 cmdstr = "", 
+                               servicesf = CONFIGFILE;
        struct ntuser_creds     creds;
        struct cli_state        cli;
+       fstring                 password,
+                               username,
+                               domain,
+                               server;
 
+       charset_initialise();
        setlinebuf(stdout);
 
 #ifdef HAVE_LIBREADLINE
@@ -375,11 +473,17 @@ static void usage(char *pname)
        argv++;
        argc--;
 
-       while ((opt = getopt(argc, argv, "s:Nd:I:U:W:c:l:")) != EOF) {
+       while ((opt = getopt(argc, argv, "A:s:Nd:I:U:W:c:l:")) != EOF) {
                switch (opt) {
+               case 'A':
+                       /* only get the username, password, and domain from the file */
+                       read_authfile (optarg, username, password, domain);
+                       if (strlen (password))
+                               got_pass = True;
+                       break;
+
                case 'c':
                        pstrcpy(cmdstr, optarg);
-                       got_pass = True;
                        break;
 
                case 'd':
@@ -417,7 +521,7 @@ static void usage(char *pname)
                }
                
                case 'W':
-                       pstrcpy(workgroup, optarg);
+                       pstrcpy(domain, optarg);
                        break;
                        
                case 'h':
@@ -432,13 +536,10 @@ static void usage(char *pname)
        setup_logging (argv[0], interactive);
        if (!interactive) 
                reopen_logs();
-
-       charset_initialise();
        
+       /* Load smb.conf file */
        /* FIXME!  How to get this DEBUGLEVEL to last over lp_load()? */
        olddebug = DEBUGLEVEL;
-
-       /* Load smb.conf file */
        if (!lp_load(servicesf,True,False,False)) {
                fprintf(stderr, "Can't load %s\n", servicesf);
        }
@@ -456,12 +557,15 @@ static void usage(char *pname)
         * initialize the credentials struct.  Get password
         * from stdin if necessary
         */
+       if (!strlen(username))
+               get_username (username);
+               
        if (!got_pass) {
-               init_rpcclient_creds (&creds, username, workgroup, "");
+               init_rpcclient_creds (&creds, username, domain, "");
                pwd_read(&creds.pwd, "Enter Password: ", lp_encrypted_passwords());
        }
        else {
-               init_rpcclient_creds (&creds, username, workgroup, password);
+               init_rpcclient_creds (&creds, username, domain, password);
        }
        memset(password,'X',strlen(password));
 
@@ -478,21 +582,24 @@ static void usage(char *pname)
        /* Load command lists */
        add_command_set(rpcclient_commands);
        add_command_set(separator_command);
+
        add_command_set(spoolss_commands);
        add_command_set(separator_command);
+
        add_command_set(lsarpc_commands);
        add_command_set(separator_command);
+
        add_command_set(samr_commands);
        add_command_set(separator_command);
 
 
        /* Do anything specified with -c */
        if (cmdstr[0]) {
-               pstring cmd;
-               char *p = cmdstr;
-               uint32 result;
+               char    *cmd;
+               char    *p = cmdstr;
+               uint32  result;
 
-               while(next_token(&p, cmd, ";", sizeof(pstring))) {
+               while((cmd=next_command(&p)) != NULL) {
                        result = process_cmd(&cli, cmd);
                }