Kill off the old varient of 'check_plaintext_password' (new version just
[ira/wip.git] / source3 / smbd / lanman.c
index fe2cc3ae7d4b81e27865bfd362570d50eaab0c0d..1a5777e1d4bb49d5a8d9dbf1e0f61b348d7414e9 100644 (file)
@@ -1,4 +1,3 @@
-#define OLD_NTDOMAIN 1
 /* 
    Unix SMB/Netbios implementation.
    Version 1.9.
@@ -34,9 +33,8 @@
 #endif
 #define CHECK_TYPES 0
 
-extern int DEBUGLEVEL;
-
 extern fstring local_machine;
+extern pstring global_myname;
 extern fstring global_myworkgroup;
 
 #define NERR_Success 0
@@ -75,8 +73,7 @@ static int CopyExpanded(connection_struct *conn,
        StrnCpy(buf,src,sizeof(buf)/2);
        pstring_sub(buf,"%S",lp_servicename(snum));
        standard_sub_conn(conn,buf);
-       StrnCpy(*dst,buf,*n);
-       l = strlen(*dst) + 1;
+       l = push_ascii(*dst,buf,*n-1, STR_TERMINATE);
        (*dst) += l;
        (*n) -= l;
        return l;
@@ -86,8 +83,7 @@ static int CopyAndAdvance(char** dst, char* src, int* n)
 {
   int l;
   if (!src || !dst || !n || !(*dst)) return(0);
-  StrnCpy(*dst,src,*n-1);
-  l = strlen(*dst) + 1;
+  l = push_ascii(*dst,src,*n-1, STR_TERMINATE);
   (*dst) += l;
   (*n) -= l;
   return l;
@@ -200,7 +196,17 @@ static BOOL init_package(struct pack_desc* p, int count, int subcount)
   if (i > n) {
     p->neededlen = i;
     i = n = 0;
+#if 0
+    /*
+     * This is the old error code we used. Aparently
+     * WinNT/2k systems return ERRbuftoosmall (2123) and
+     * OS/2 needs this. I'm leaving this here so we can revert
+     * if needed. JRA.
+     */
     p->errcode = ERRmoredata;
+#else
+       p->errcode = ERRbuftoosmall;
+#endif
   }
   else
     p->errcode = NERR_Success;
@@ -211,27 +217,15 @@ static BOOL init_package(struct pack_desc* p, int count, int subcount)
   return(p->errcode == NERR_Success);
 }
 
-#ifdef HAVE_STDARG_H
 static int package(struct pack_desc* p, ...)
 {
-#else
-static int package(va_alist)
-va_dcl
-{
-  struct pack_desc* p;
-#endif
   va_list args;
   int needed=0, stringneeded;
   char* str=NULL;
   int is_string=0, stringused;
   int32 temp;
 
-#ifdef HAVE_STDARG_H
   va_start(args,p);
-#else
-  va_start(args);
-  p = va_arg(args,struct pack_desc *);
-#endif
 
   if (!*p->curpos) {
     if (!p->subcount)
@@ -358,7 +352,7 @@ static void PackDriverData(struct pack_desc* desc)
   SIVAL(drivdata,0,sizeof drivdata); /* cb */
   SIVAL(drivdata,4,1000);      /* lVersion */
   memset(drivdata+8,0,32);     /* szDeviceName */
-  pstrcpy(drivdata+8,"NULL");
+  push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
   PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
 }
 
@@ -402,14 +396,14 @@ static int check_printq_info(struct pack_desc* desc,
 }
 
 
-#define JOB_STATUS_QUEUED 0
-#define JOB_STATUS_PAUSED 1
-#define JOB_STATUS_SPOOLING 2
-#define JOB_STATUS_PRINTING 3
-#define JOB_STATUS_PRINTED 4
+#define RAP_JOB_STATUS_QUEUED 0
+#define RAP_JOB_STATUS_PAUSED 1
+#define RAP_JOB_STATUS_SPOOLING 2
+#define RAP_JOB_STATUS_PRINTING 3
+#define RAP_JOB_STATUS_PRINTED 4
 
-#define QUEUE_STATUS_PAUSED 1
-#define QUEUE_STATUS_ERROR 2
+#define RAP_QUEUE_STATUS_PAUSED 1
+#define RAP_QUEUE_STATUS_ERROR 2
 
 /* turn a print job status into a on the wire status 
 */
@@ -417,13 +411,13 @@ static int printj_status(int v)
 {
        switch (v) {
        case LPQ_QUEUED:
-               return JOB_STATUS_QUEUED;
+               return RAP_JOB_STATUS_QUEUED;
        case LPQ_PAUSED:
-               return JOB_STATUS_PAUSED;
+               return RAP_JOB_STATUS_PAUSED;
        case LPQ_SPOOLING:
-               return JOB_STATUS_SPOOLING;
+               return RAP_JOB_STATUS_SPOOLING;
        case LPQ_PRINTING:
-               return JOB_STATUS_PRINTING;
+               return RAP_JOB_STATUS_PRINTING;
        }
        return 0;
 }
@@ -436,9 +430,9 @@ static int printq_status(int v)
        case LPQ_QUEUED:
                return 0;
        case LPQ_PAUSED:
-               return QUEUE_STATUS_PAUSED;
+               return RAP_QUEUE_STATUS_PAUSED;
        }
-       return QUEUE_STATUS_ERROR;
+       return RAP_QUEUE_STATUS_ERROR;
 }
 
 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
@@ -464,7 +458,7 @@ static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
     PACKI(desc,"D",queue->size); /* ulSize */
     PACKS(desc,"z",queue->file); /* pszComment */
   }
-  if (uLevel == 2 || uLevel == 3) {
+  if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
     PACKI(desc,"W",queue->priority);           /* uPriority */
     PACKS(desc,"z",queue->user); /* pszUserName */
     PACKI(desc,"W",n+1);               /* uPosition */
@@ -484,104 +478,203 @@ static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
       PACKS(desc,"z","NULL"); /* pszDriverName */
       PackDriverData(desc);    /* pDriverData */
       PACKS(desc,"z","");      /* pszPrinterName */
+    } else if (uLevel == 4) {   /* OS2 */
+      PACKS(desc,"z","");       /* pszSpoolFileName  */
+       PACKS(desc,"z","");       /* pszPortName       */
+       PACKS(desc,"z","");       /* pszStatus         */
+       PACKI(desc,"D",0);        /* ulPagesSpooled    */
+       PACKI(desc,"D",0);        /* ulPagesSent       */
+       PACKI(desc,"D",0);        /* ulPagesPrinted    */
+       PACKI(desc,"D",0);        /* ulTimePrinted     */
+       PACKI(desc,"D",0);        /* ulExtendJobStatus */
+       PACKI(desc,"D",0);        /* ulStartPage       */
+       PACKI(desc,"D",0);        /* ulEndPage         */
     }
   }
 }
 
+/********************************************************************
+ Return a driver name given an snum.
+ Looks in a tdb first. Returns True if from tdb, False otherwise.
+ ********************************************************************/
 
+static BOOL get_driver_name(int snum, pstring drivername)
+{
+       NT_PRINTER_INFO_LEVEL *info = NULL;
+       BOOL in_tdb = False;
+
+       get_a_printer (&info, 2, lp_servicename(snum));
+       if (info != NULL) {
+               pstrcpy( drivername, info->info_2->drivername);
+               in_tdb = True;
+               free_a_printer(&info, 2);
+       } else {
+               pstrcpy( drivername, lp_printerdriver(snum));
+       }
+
+       return in_tdb;
+}
+
+/********************************************************************
+ Respond to the DosPrintQInfo command with a level of 52
+ This is used to get printer driver information for Win9x clients
+ ********************************************************************/
 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
                                struct pack_desc* desc,
                                int count, print_queue_struct* queue,
                                print_status_struct* status)
 {
-       int i,ok=0;
+       int i;
+       BOOL ok = False;
        pstring tok,driver,datafile,langmon,helpfile,datatype;
        char *p;
-       char **lines, *line;
-       
-       lines = file_lines_load(lp_driverfile(),NULL);
-       if (!lines) {
-               DEBUG(3,("fill_printq_info: Can't open %s - %s\n",
-                        lp_driverfile(),strerror(errno)));
-               desc->errcode=NERR_notsupported;
-               return;
-       }
-       
-       /* lookup the long printer driver name in the file
-          description */
-       for (i=0;lines[i] && !ok;i++) {
-               p = lines[i];
-               if (next_token(&p,tok,":",sizeof(tok)) &&
-                   (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
-                   (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
-                       ok=1;
-       }
-       line = strdup(p);
-       p = line;
-       file_lines_free(lines);
-       
-       /* driver file name */
-       if (ok && !next_token(&p,driver,":",sizeof(driver))) ok = 0;
-       /* data file name */
-       if (ok && !next_token(&p,datafile,":",sizeof(datafile))) ok = 0;
+       char **lines = NULL;
+       pstring gen_line;
+       BOOL in_tdb = False;
+       fstring location;
+       pstring drivername;
+
        /*
-        * for the next tokens - which may be empty - I have
-        * to check for empty tokens first because the
-        * next_token function will skip all empty token
-        * fields */
-       if (ok) {
+        * Check in the tdb *first* before checking the legacy
+        * files. This allows an NT upload to take precedence over
+        * the existing fileset. JRA.
+        * 
+        * we need to lookup the driver name prior to making the call
+        * to get_a_printer_driver_9x_compatible() and not rely on the
+        * 'print driver' parameter --jerry
+        */
+
+
+       if ((get_driver_name(snum,drivername)) && 
+           ((ok = get_a_printer_driver_9x_compatible(gen_line, drivername)) == True))
+       {
+               in_tdb = True;
+               p = gen_line;
+               DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
+       } 
+       else 
+       {
+               /* didn't find driver in tdb */
+
+               DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
+                          snum, drivername, lp_driverfile(snum)));
+
+               lines = file_lines_load(lp_driverfile(snum),NULL);
+               if (!lines) 
+               {
+                       DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
+                                 strerror(errno)));
+                       desc->errcode=NERR_notsupported;
+                       goto done;
+               } 
+
+               /* lookup the long printer driver name in the file description */
+               for (i=0;lines[i] && !ok;i++) 
+               {
+                       p = lines[i];
+                       if (next_token(&p,tok,":",sizeof(tok)) &&
+                          (strlen(drivername) == strlen(tok)) &&
+                          (!strncmp(tok,drivername,strlen(drivername))))
+                       {
+                               ok = True;
+                       }
+               }
+       }
+
+       if (ok)
+       {
+               /* driver file name */
+               if (!next_token(&p,driver,":",sizeof(driver)))
+                       goto err;
+
+               /* data file name */
+               if (!next_token(&p,datafile,":",sizeof(datafile)))
+                       goto err;
+
+               /*
+                * for the next tokens - which may be empty - I have
+                * to check for empty tokens first because the
+                * next_token function will skip all empty token
+                * fields */
+
                /* help file */
-               if (*p == ':') {
+               if (*p == ':') 
+               {
                        *helpfile = '\0';
                        p++;
-               } else if (!next_token(&p,helpfile,":",sizeof(helpfile))) ok = 0;
-       }
+               } 
+               else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
+                       goto err;
        
-       if (ok) {
                /* language monitor */
-               if (*p == ':') {
+               if (*p == ':') 
+               {
                        *langmon = '\0';
                        p++;
-               } else if (!next_token(&p,langmon,":",sizeof(langmon)))
-                       ok = 0;
-       }
+               } 
+               else if (!next_token(&p,langmon,":",sizeof(langmon)))
+                       goto err;
        
-       /* default data type */
-       if (ok && !next_token(&p,datatype,":",sizeof(datatype))) 
-               ok = 0;
+               /* default data type */
+               if (!next_token(&p,datatype,":",sizeof(datatype))) 
+                       goto err;
        
-       if (ok) {
                PACKI(desc,"W",0x0400);               /* don't know */
-               PACKS(desc,"z",lp_printerdriver(snum));    /* long printer name */
+               PACKS(desc,"z",drivername);    /* long printer name */
                PACKS(desc,"z",driver);                    /* Driverfile Name */
                PACKS(desc,"z",datafile);                  /* Datafile name */
                PACKS(desc,"z",langmon);                         /* language monitor */
-               PACKS(desc,"z",lp_driverlocation(snum));   /* share to retrieve files */
+               if (in_tdb)
+               {
+                       fstrcpy(location, "\\\\");
+                       fstrcat(location, global_myname);
+                       fstrcat(location, "\\print$\\WIN40\\0");
+                       PACKS(desc,"z",location);   /* share to retrieve files */
+               }
+               else
+               {
+                       PACKS(desc,"z",lp_driverlocation(snum));   /* share to retrieve files */
+               }
                PACKS(desc,"z",datatype);                        /* default data type */
                PACKS(desc,"z",helpfile);                  /* helpfile name */
                PACKS(desc,"z",driver);                    /* driver name */
+
+               DEBUG(3,("printerdriver:%s:\n",drivername));
                DEBUG(3,("Driver:%s:\n",driver));
                DEBUG(3,("Data File:%s:\n",datafile));
                DEBUG(3,("Language Monitor:%s:\n",langmon));
+               if (in_tdb)
+                       DEBUG(3,("lp_driverlocation:%s:\n",location));
+               else
+                       DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
                DEBUG(3,("Data Type:%s:\n",datatype));
                DEBUG(3,("Help File:%s:\n",helpfile));
                PACKI(desc,"N",count);                     /* number of files to copy */
-               for (i=0;i<count;i++) {
-                               /* no need to check return value here
-                                * - it was already tested in
-                                * get_printerdrivernumber */
+
+               for (i=0;i<count;i++) 
+               {
+                       /* no need to check return value here
+                        * - it was already tested in
+                        * get_printerdrivernumber */
                        next_token(&p,tok,",",sizeof(tok));
                        PACKS(desc,"z",tok);         /* driver files to copy */
                        DEBUG(3,("file:%s:\n",tok));
                }
                
                DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
-                        SERVICE(snum),count));
-       } else {
-               DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
-               desc->errcode=NERR_notsupported;
+                         SERVICE(snum),count));
+
+               desc->errcode=NERR_Success;
+               goto done;
        }
-       free(line);
+
+  err:
+
+       DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
+       desc->errcode=NERR_notsupported;
+
+ done:
+       file_lines_free(lines); 
 }
 
 
@@ -629,23 +722,27 @@ static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
        }
 
        if (uLevel == 3 || uLevel == 4) {
+               pstring drivername;
+
                PACKI(desc,"W",5);              /* uPriority */
                PACKI(desc,"W",0);              /* uStarttime */
                PACKI(desc,"W",0);              /* uUntiltime */
                PACKI(desc,"W",5);              /* pad1 */
                PACKS(desc,"z","");             /* pszSepFile */
                PACKS(desc,"z","WinPrint");     /* pszPrProc */
-               PACKS(desc,"z","");             /* pszParms */
-               if (!status || !status->message[0]) {
-                       PACKS(desc,"z",Expand(conn,snum,lp_comment(snum))); /* pszComment */
+               PACKS(desc,"z",NULL);           /* pszParms */
+               PACKS(desc,"z",NULL);           /* pszComment - don't ask.... JRA */
+               /* "don't ask" that it's done this way to fix corrupted 
+                  Win9X/ME printer comments. */
+               if (!status) {
                        PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
                } else {
-                       PACKS(desc,"z",status->message); /* pszComment */
                        PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
                }
                PACKI(desc,(uLevel == 3 ? "W" : "N"),count);    /* cJobs */
                PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
-               PACKS(desc,"z",lp_printerdriver(snum));         /* pszDriverName */
+               get_driver_name(snum,drivername);
+               PACKS(desc,"z",drivername);             /* pszDriverName */
                PackDriverData(desc);   /* pDriverData */
        }
 
@@ -663,45 +760,81 @@ static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
 /* This function returns the number of files for a given driver */
 static int get_printerdrivernumber(int snum)
 {
-       int i=0,ok=0;
+       int i, result = 0;
+       BOOL ok = False;
        pstring tok;
        char *p;
-       char **lines, *line;
-
-       lines = file_lines_load(lp_driverfile(), NULL);
-       if (!lines) {
-               DEBUG(3,("get_printerdrivernumber: Can't open %s - %s\n",
-                        lp_driverfile(),strerror(errno)));
-               return(0);
-       }
+       char **lines = NULL;
+       pstring gen_line;
+       pstring drivername;
+       
+       /*
+        * Check in the tdb *first* before checking the legacy
+        * files. This allows an NT upload to take precedence over
+        * the existing fileset. JRA.
+        *
+        * we need to lookup the driver name prior to making the call
+        * to get_a_printer_driver_9x_compatible() and not rely on the
+        * 'print driver' parameter --jerry
+        */
+       
+       if ((get_driver_name(snum,drivername)) && 
+           (ok = get_a_printer_driver_9x_compatible(gen_line, drivername) == True)) 
+       {
+               p = gen_line;
+               DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
+       } 
+       else 
+       {
+               /* didn't find driver in tdb */
        
-       /* lookup the long printer driver name in the file description */
-       for (i=0;lines[i] && !ok; i++) {
-               p = lines[i];
-               if (next_token(&p,tok,":",sizeof(tok)) &&
-                   (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum))))) 
-                       ok=1;
+               DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
+                         snum, drivername, lp_driverfile(snum)));
+               
+               lines = file_lines_load(lp_driverfile(snum), NULL);
+               if (!lines) 
+               {
+                       DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
+                       goto done;
+               } 
+
+               /* lookup the long printer driver name in the file description */
+               for (i=0;lines[i] && !ok;i++) 
+               {
+                       p = lines[i];
+                       if (next_token(&p,tok,":",sizeof(tok)) &&
+                          (strlen(drivername) == strlen(tok)) &&
+                          (!strncmp(tok,drivername,strlen(drivername)))) 
+                       {
+                               ok = True;
+                       }
+               }
        }
-       line = strdup(p);
-       p = line;
-       file_lines_free(lines);
        
-       if (ok) {
+       if( ok ) 
+       {
                /* skip 5 fields */
                i = 5;
                while (*p && i) {
                        if (*p++ == ':') i--;
                }
-               if (!*p || i)
-                       return(0);
+               if (!*p || i) {
+                       DEBUG(3,("Can't determine number of printer driver files\n"));
+                       goto done;
+               }
                
                /* count the number of files */
                while (next_token(&p,tok,",",sizeof(tok)))
                        i++;
-       }
-       free(line);
        
-       return(i);
+               result = i;
+       }
+
+ done:
+
+       file_lines_free(lines);
+
+       return result;
 }
 
 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
@@ -710,112 +843,116 @@ static BOOL api_DosPrintQGetInfo(connection_struct *conn,
                                 char **rdata,char **rparam,
                                 int *rdata_len,int *rparam_len)
 {
-  char *str1 = param+2;
-  char *str2 = skip_string(str1,1);
-  char *p = skip_string(str2,1);
-  char *QueueName = p;
-  int uLevel;
-  int count=0;
-  int snum;
-  char* str3;
-  struct pack_desc desc;
-  print_queue_struct *queue=NULL;
-  print_status_struct status;
-  
-  memset((char *)&status,'\0',sizeof(status));
-  memset((char *)&desc,'\0',sizeof(desc));
+       char *str1 = param+2;
+       char *str2 = skip_string(str1,1);
+       char *p = skip_string(str2,1);
+       char *QueueName = p;
+       int uLevel;
+       int count=0;
+       int snum;
+       char* str3;
+       struct pack_desc desc;
+       print_queue_struct *queue=NULL;
+       print_status_struct status;
+       char* tmpdata=NULL;
+
+       memset((char *)&status,'\0',sizeof(status));
+       memset((char *)&desc,'\0',sizeof(desc));
  
-  p = skip_string(p,1);
-  uLevel = SVAL(p,0);
-  str3 = p + 4;
+       p = skip_string(p,1);
+       uLevel = SVAL(p,0);
+       str3 = p + 4;
  
-  /* remove any trailing username */
-  if ((p = strchr(QueueName,'%'))) *p = 0;
+       /* remove any trailing username */
+       if ((p = strchr_m(QueueName,'%')))
+               *p = 0;
  
-  DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
+       DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
  
-  /* check it's a supported varient */
-  if (!prefix_ok(str1,"zWrLh")) return False;
-  if (!check_printq_info(&desc,uLevel,str2,str3)) {
-    /*
-     * Patch from Scott Moomaw <scott@bridgewater.edu>
-     * to return the 'invalid info level' error if an
-     * unknown level was requested.
-     */
-    *rdata_len = 0;
-    *rparam_len = 6;
-    *rparam = REALLOC(*rparam,*rparam_len);
-    SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
-    SSVAL(*rparam,2,0);
-    SSVAL(*rparam,4,0);
-    return(True);
-  }
+       /* check it's a supported varient */
+       if (!prefix_ok(str1,"zWrLh"))
+               return False;
+       if (!check_printq_info(&desc,uLevel,str2,str3)) {
+               /*
+                * Patch from Scott Moomaw <scott@bridgewater.edu>
+                * to return the 'invalid info level' error if an
+                * unknown level was requested.
+                */
+               *rdata_len = 0;
+               *rparam_len = 6;
+               *rparam = REALLOC(*rparam,*rparam_len);
+               SSVALS(*rparam,0,ERRunknownlevel);
+               SSVAL(*rparam,2,0);
+               SSVAL(*rparam,4,0);
+               return(True);
+       }
  
-  snum = lp_servicenumber(QueueName);
-  if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
-    int pnum = lp_servicenumber(PRINTERS_NAME);
-    if (pnum >= 0) {
-      lp_add_printer(QueueName,pnum);
-      snum = lp_servicenumber(QueueName);
-    }
-  }
+       snum = lp_servicenumber(QueueName);
+       if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
+               int pnum = lp_servicenumber(PRINTERS_NAME);
+               if (pnum >= 0) {
+                       lp_add_printer(QueueName,pnum);
+                       snum = lp_servicenumber(QueueName);
+               }
+       }
   
-  if (snum < 0 || !VALID_SNUM(snum)) return(False);
+       if (snum < 0 || !VALID_SNUM(snum))
+               return(False);
 
-  if (uLevel==52) {
-         count = get_printerdrivernumber(snum);
-         DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
-  } else {
-         count = print_queue_status(snum, &queue,&status);
-  }
+       if (uLevel==52) {
+               count = get_printerdrivernumber(snum);
+               DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
+       } else {
+               count = print_queue_status(snum, &queue,&status);
+       }
 
-  if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
-  desc.base = *rdata;
-  desc.buflen = mdrcnt;
-  if (init_package(&desc,1,count)) {
-         desc.subcount = count;
-         fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
-  } else if(uLevel == 0) {
-       /*
-        * This is a *disgusting* hack.
-        * This is *so* bad that even I'm embarrassed (and I
-        * have no shame). Here's the deal :
-        * Until we get the correct SPOOLSS code into smbd
-        * then when we're running with NT SMB support then
-        * NT makes this call with a level of zero, and then
-        * immediately follows it with an open request to
-        * the \\SRVSVC pipe. If we allow that open to
-        * succeed then NT barfs when it cannot open the
-        * \\SPOOLSS pipe immediately after and continually
-        * whines saying "Printer name is invalid" forever
-        * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
-        * to fail, then NT downgrades to using the downlevel code
-        * and everything works as well as before. I hate
-        * myself for adding this code.... JRA.
-        */
-
-       fail_next_srvsvc_open();
-  }
+       if (mdrcnt > 0) {
+               *rdata = REALLOC(*rdata,mdrcnt);
+               desc.base = *rdata;
+               desc.buflen = mdrcnt;
+       } else {
+               /*
+                * Don't return data but need to get correct length
+                * init_package will return wrong size if buflen=0
+                */
+               desc.buflen = getlen(desc.format);
+               desc.base = tmpdata = (char *) malloc (desc.buflen);
+       }
 
-  *rdata_len = desc.usedlen;
+       if (init_package(&desc,1,count)) {
+               desc.subcount = count;
+               fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
+       }
+
+       *rdata_len = desc.usedlen;
   
-  *rparam_len = 6;
-  *rparam = REALLOC(*rparam,*rparam_len);
-  SSVALS(*rparam,0,desc.errcode);
-  SSVAL(*rparam,2,0);
-  SSVAL(*rparam,4,desc.neededlen);
+       /*
+        * We must set the return code to ERRbuftoosmall
+        * in order to support lanman style printing with Win NT/2k
+        * clients       --jerry
+        */
+       if (!mdrcnt && lp_disable_spoolss())
+               desc.errcode = ERRbuftoosmall;
+    *rdata_len = desc.usedlen;
+       *rparam_len = 6;
+       *rparam = REALLOC(*rparam,*rparam_len);
+       SSVALS(*rparam,0,desc.errcode);
+       SSVAL(*rparam,2,0);
+       SSVAL(*rparam,4,desc.neededlen);
   
-  DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
+       DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
 
-  if (queue) free(queue);
-  
-  return(True);
-}
+       SAFE_FREE(queue);
+       SAFE_FREE(tmpdata);
 
+       return(True);
+}
 
 /****************************************************************************
-  view list of all print jobs on all queues
-  ****************************************************************************/
+ View list of all print jobs on all queues.
+****************************************************************************/
+
 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
                              int mdrcnt, int mprcnt,
                              char **rdata, char** rparam,
@@ -848,7 +985,7 @@ static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param,
     *rdata_len = 0;
     *rparam_len = 6;
     *rparam = REALLOC(*rparam,*rparam_len);
-    SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
+    SSVALS(*rparam,0,ERRunknownlevel);
     SSVAL(*rparam,2,0);
     SSVAL(*rparam,4,0);
     return(True);
@@ -897,7 +1034,7 @@ static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param,
       }
   }
 
-  if (subcntarr) free(subcntarr);
+  SAFE_FREE(subcntarr);
  
   *rdata_len = desc.usedlen;
   *rparam_len = 8;
@@ -908,11 +1045,11 @@ static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param,
   SSVAL(*rparam,6,queuecnt);
   
   for (i = 0; i < queuecnt; i++) {
-    if (queue && queue[i]) free(queue[i]);
+    if (queue) SAFE_FREE(queue[i]);
   }
 
-  if (queue) free(queue);
-  if (status) free(status);
+  SAFE_FREE(queue);
+  SAFE_FREE(status);
   
   return True;
 }
@@ -982,10 +1119,16 @@ static int get_server_info(uint32 servertype,
     if (!*ptr) continue;
     
     if (count == alloced) {
+      struct srv_info_struct *ts;
+      
       alloced += 10;
-      (*servers) = (struct srv_info_struct *)
+      ts = (struct srv_info_struct *)
        Realloc(*servers,sizeof(**servers)*alloced);
-      if (!(*servers)) return(0);
+      if (!ts) {
+       DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
+       return(0);
+      }
+      else *servers = ts;
       memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
     }
     s = &(*servers)[count];
@@ -1104,15 +1247,15 @@ static int fill_srv_info(struct srv_info_struct *service,
   switch (uLevel)
     {
     case 0:
-      StrnCpy(p,service->name,15);
-      break;
+           push_ascii(p,service->name, 15, STR_TERMINATE);
+           break;
 
     case 1:
-      StrnCpy(p,service->name,15);
-      SIVAL(p,18,service->type);
-      SIVAL(p,22,PTR_DIFF(p2,baseaddr));
-      len += CopyAndAdvance(&p2,service->comment,&l2);
-      break;
+           push_ascii(p,service->name,15, STR_TERMINATE);
+           SIVAL(p,18,service->type);
+           SIVAL(p,22,PTR_DIFF(p2,baseaddr));
+           len += CopyAndAdvance(&p2,service->comment,&l2);
+           break;
     }
 
   if (stringbuf)
@@ -1189,9 +1332,9 @@ static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param
   DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
 
   if (strcmp(str1, "WrLehDz") == 0) {
-    StrnCpy(domain, p, sizeof(fstring)-1);
+         pull_ascii_fstring(domain, p);
   } else {
-    StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);    
+         fstrcpy(domain, global_myworkgroup);
   }
 
   if (lp_browse_list())
@@ -1200,7 +1343,8 @@ static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param
   data_len = fixed_len = string_len = 0;
   missed = 0;
 
-  qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
+  if (total > 0)
+    qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
 
   {
     char *lastname=NULL;
@@ -1255,7 +1399,7 @@ static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param
   SSVAL(*rparam,4,counted);
   SSVAL(*rparam,6,counted+missed);
 
-  if (servers) free(servers);
+  SAFE_FREE(servers);
 
   DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
           domain,uLevel,counted,counted+missed));
@@ -1363,15 +1507,15 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel,
     }
   if (!baseaddr) baseaddr = p;
   
-  StrnCpy(p,lp_servicename(snum),13);
+  push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
   
   if (uLevel > 0)
     {
       int type;
-      CVAL(p,13) = 0;
+      SCVAL(p,13,0);
       type = STYPE_DISKTREE;
       if (lp_print_ok(snum)) type = STYPE_PRINTQ;
-      if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
+      if (strequal("IPC",lp_fstype(snum))) type = STYPE_IPC;
       SSVAL(p,14,type);                /* device type */
       SIVAL(p,16,PTR_DIFF(p2,baseaddr));
       len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
@@ -1511,6 +1655,210 @@ static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,c
   return(True);
 }
 
+/****************************************************************************
+  Add a share
+  ****************************************************************************/
+static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid, char *param,char *data,
+                                int mdrcnt,int mprcnt,
+                                char **rdata,char **rparam,
+                                int *rdata_len,int *rparam_len)
+{
+  char *str1 = param+2;
+  char *str2 = skip_string(str1,1);
+  char *p = skip_string(str2,1);
+  int uLevel = SVAL(p,0);
+  fstring sharename;
+  fstring comment;
+  pstring pathname;
+  char *command, *cmdname;
+  uint offset;
+  int snum;
+  int res = ERRunsup;
+  
+  /* check it's a supported varient */
+  if (!prefix_ok(str1,RAP_WShareAdd_REQ)) return False;
+  if (!check_share_info(uLevel,str2)) return False;
+  if (uLevel != 2) return False;
+
+  pull_ascii_fstring(sharename,data);
+  snum = find_service(sharename);
+  if (snum >= 0) { /* already exists */
+    res = ERRfilexists;
+    goto error_exit;
+  }
+
+  /* only support disk share adds */
+  if (SVAL(data,14)!=STYPE_DISKTREE) return False;
+
+  offset = IVAL(data, 16);
+  if (offset >= mdrcnt) {
+    res = ERRinvalidparam;
+    goto error_exit;
+  }
+  pull_ascii_fstring(comment, offset? (data+offset) : "");
+
+  offset = IVAL(data, 26);
+  if (offset >= mdrcnt) {
+    res = ERRinvalidparam;
+    goto error_exit;
+  }
+  pull_ascii_pstring(pathname, offset? (data+offset) : "");
+
+  string_replace(sharename, '"', ' ');
+  string_replace(pathname, '"', ' ');
+  string_replace(comment, '"', ' ');
+
+  cmdname = lp_add_share_cmd();
+
+  if (!cmdname || *cmdname == '\0') return False;
+
+  asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
+          lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
+
+  if (command) {
+    DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
+    if ((res = smbrun(command, NULL)) != 0) {
+      DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
+      SAFE_FREE(command);
+      res = ERRnoaccess;
+      goto error_exit;
+    } else {
+      SAFE_FREE(command);
+      message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
+    }
+  } else return False;
+
+  *rparam_len = 6;
+  *rparam = REALLOC(*rparam,*rparam_len);
+  SSVAL(*rparam,0,NERR_Success);
+  SSVAL(*rparam,2,0);          /* converter word */
+  SSVAL(*rparam,4,*rdata_len);
+  *rdata_len = 0;
+  
+  return True;
+
+ error_exit:
+  *rparam_len = 4;
+  *rparam = REALLOC(*rparam,*rparam_len);
+  *rdata_len = 0;
+  SSVAL(*rparam,0,res);
+  SSVAL(*rparam,2,0);
+  return True;
+
+}
+
+/****************************************************************************
+  view list of groups available
+  ****************************************************************************/
+static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
+                             int mdrcnt,int mprcnt,
+                             char **rdata,char **rparam,
+                             int *rdata_len,int *rparam_len)
+{
+       char *str1 = param+2;
+       char *str2 = skip_string(str1,1);
+       char *p = skip_string(str2,1);
+       int uLevel = SVAL(p,0);
+       char *p2;
+       int count=0;
+
+       if (!prefix_ok(str1,"WrLeh")) return False;
+  
+       /* check it's a supported variant */
+       switch( uLevel )
+       {
+               case 0: 
+                       p2 = "B21"; 
+                       break;
+               default: 
+                       return False;
+       }
+
+       if (strcmp(p2,str2) != 0) return False;
+
+       *rdata_len = mdrcnt + 1024;
+       *rdata = REALLOC(*rdata,*rdata_len);
+
+       SSVAL(*rparam,0,NERR_Success);
+       SSVAL(*rparam,2,0);             /* converter word */
+
+       p = *rdata;
+
+       /* XXXX we need a real SAM database some day */
+       pstrcpy(p,"Users"); p += 21; count++;
+       pstrcpy(p,"Domain Users"); p += 21; count++;
+       pstrcpy(p,"Guests"); p += 21; count++;
+       pstrcpy(p,"Domain Guests"); p += 21; count++;
+
+       *rdata_len = PTR_DIFF(p,*rdata);
+
+       *rparam_len = 8;
+       *rparam = REALLOC(*rparam,*rparam_len);
+
+       SSVAL(*rparam,4,count); /* is this right?? */
+       SSVAL(*rparam,6,count); /* is this right?? */
+
+       DEBUG(3,("api_RNetGroupEnum gave %d entries\n", count));
+
+       return(True);
+}
+
+/****************************************************************************
+  view list of groups available
+  ****************************************************************************/
+static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
+                             int mdrcnt,int mprcnt,
+                             char **rdata,char **rparam,
+                             int *rdata_len,int *rparam_len)
+{
+       char *str1 = param+2;
+       char *str2 = skip_string(str1,1);
+       char *p = skip_string(str2,1);
+       int uLevel = SVAL(p,0);
+       char *p2;
+       int count=0;
+
+       if (!prefix_ok(str1,"WrLeh")) return False;
+  
+       /* check it's a supported variant */
+       switch( uLevel )
+       {
+               case 0: 
+                       p2 = "B21"; 
+                       break;
+               default: 
+                       return False;
+       }
+
+       if (strcmp(p2,str2) != 0) return False;
+
+       *rdata_len = mdrcnt + 1024;
+       *rdata = REALLOC(*rdata,*rdata_len);
+
+       SSVAL(*rparam,0,NERR_Success);
+       SSVAL(*rparam,2,0);             /* converter word */
+
+       p = *rdata;
+
+       /* XXXX we need a real SAM database some day */
+       pstrcpy(p,"Users"); p += 21; count++;
+       pstrcpy(p,"Domain Users"); p += 21; count++;
+       pstrcpy(p,"Guests"); p += 21; count++;
+       pstrcpy(p,"Domain Guests"); p += 21; count++;
+
+       *rdata_len = PTR_DIFF(p,*rdata);
+
+       *rparam_len = 8;
+       *rparam = REALLOC(*rparam,*rparam_len);
+
+       SSVAL(*rparam,4,count); /* is this right?? */
+       SSVAL(*rparam,6,count); /* is this right?? */
+
+       DEBUG(3,("api_RNetUserEnum gave %d entries\n", count));
+
+       return(True);
+}
+
 
 
 /****************************************************************************
@@ -1546,16 +1894,16 @@ static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,ch
     t = LocalTime(&unixdate);
 
     SIVAL(p,4,0);              /* msecs ? */
-    CVAL(p,8) = t->tm_hour;
-    CVAL(p,9) = t->tm_min;
-    CVAL(p,10) = t->tm_sec;
-    CVAL(p,11) = 0;            /* hundredths of seconds */
+    SCVAL(p,8,t->tm_hour);
+    SCVAL(p,9,t->tm_min);
+    SCVAL(p,10,t->tm_sec);
+    SCVAL(p,11,0);             /* hundredths of seconds */
     SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
     SSVAL(p,14,10000);         /* timer interval in 0.0001 of sec */
-    CVAL(p,16) = t->tm_mday;
-    CVAL(p,17) = t->tm_mon + 1;
+    SCVAL(p,16,t->tm_mday);
+    SCVAL(p,17,t->tm_mon + 1);
     SSVAL(p,18,1900+t->tm_year);
-    CVAL(p,20) = t->tm_wday;
+    SCVAL(p,20,t->tm_wday);
   }
 
 
@@ -1575,7 +1923,7 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param
   fstring user;
   fstring pass1,pass2;
 
-  fstrcpy(user,p);
+  pull_ascii_fstring(user,p);
 
   p = skip_string(p,1);
 
@@ -1594,62 +1942,41 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param
 
   DEBUG(3,("Set password for <%s>\n",user));
 
-  /*
-   * Pass the user through the NT -> unix user mapping
-   * function.
-   */
-
-  (void)map_username(user);
-
-  /*
-   * Do any UNIX username case mangling.
-   */
-  (void)Get_Pwnam( user, True);
-
   /*
    * Attempt to verify the old password against smbpasswd entries
    * Win98 clients send old and new password in plaintext for this call.
    */
 
   {
-    fstring saved_pass2;
-    struct smb_passwd *smbpw = NULL;
-
-    /*
-     * Save the new password as change_oem_password overwrites it
-     * with zeros.
-     */
-
-    fstrcpy(saved_pass2, pass2);
-
-    if (check_plaintext_password(user,pass1,strlen(pass1),&smbpw) &&
-        change_oem_password(smbpw,pass2,False))
-    {
-      SSVAL(*rparam,0,NERR_Success);
-
-      /*
-       * If unix password sync was requested, attempt to change
-       * the /etc/passwd database also. Return failure if this cannot
-       * be done.
-       */
-
-      if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
-        SSVAL(*rparam,0,NERR_badpass);
-    }
-  }
-
-  /*
-   * If the above failed, attempt the plaintext password change.
-   * This tests against the /etc/passwd database only.
-   */
-
-  if(SVAL(*rparam,0) != NERR_Success)
-  {
-    if (password_ok(user, pass1,strlen(pass1),NULL) &&
-        chgpasswd(user,pass1,pass2,False))
-    {
-      SSVAL(*rparam,0,NERR_Success);
-    }
+         auth_serversupplied_info *server_info = NULL;
+         DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
+         if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
+                 if (change_oem_password(server_info->sam_account,pass2))
+                 {
+                         SSVAL(*rparam,0,NERR_Success);
+                 }
+                 
+                 /*
+                  * If unix password sync was requested, attempt to change
+                  * the /etc/passwd database also. Return failure if this cannot
+                  * be done.
+                  *
+                  * This occours regardless of the previous result, becouse 
+                  * It might not have been testing the password against the SAM backend.
+                  * (and therefore the change_oem_password would fail).
+                  *
+                  * Conditional on lp_unix_password_sync() becouse we don't want
+                   * to touch the unix db unless we have admin permission.
+                  */
+                 
+                 if(lp_unix_password_sync() && !chgpasswd(pdb_get_username(server_info->sam_account),
+                                                          pass1,pass2,False)) {
+                         SSVAL(*rparam,0,NERR_badpass);
+                 }
+                 
+                 free_server_info(&server_info);
+         }
+         data_blob_clear_free(&password);
   }
 
   /*
@@ -1664,15 +1991,17 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param
 
   if(SVAL(*rparam,0) != NERR_Success)
   {
-    struct smb_passwd *sampw = NULL;
+    SAM_ACCOUNT *hnd = NULL;
 
-    if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &sampw) && 
-       change_lanman_password(sampw,(unsigned char *)pass1,(unsigned char *)pass2))
+    if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd) && 
+       change_lanman_password(hnd,(unsigned char *)pass1,(unsigned char *)pass2))
     {
       SSVAL(*rparam,0,NERR_Success);
     }
+       pdb_free_sam(&hnd);
   }
 
+
   memset((char *)pass1,'\0',sizeof(fstring));
   memset((char *)pass2,'\0',sizeof(fstring));   
         
@@ -1712,8 +2041,7 @@ static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *
   }
   p = skip_string(p,1);
 
-  fstrcpy(user,p);
-  p = skip_string(p,1);
+  p += pull_ascii_fstring(user,p);
 
   DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
 
@@ -1727,7 +2055,7 @@ static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *
   /*
    * Do any UNIX username case mangling.
    */
-  (void)Get_Pwnam( user, True);
+  (void)Get_Pwnam_Modify( user );
 
   if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
   {
@@ -1751,6 +2079,8 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param
        char *str2 = skip_string(str1,1);
        char *p = skip_string(str2,1);
        int jobid, errcode;
+       extern struct current_user current_user;
+       WERROR werr = WERR_OK;
 
        jobid = SVAL(p,0);
 
@@ -1771,15 +2101,21 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param
        
        switch (function) {
        case 81:                /* delete */ 
-               if (print_job_delete(jobid)) errcode = NERR_Success;
+               if (print_job_delete(&current_user, jobid, &werr)) 
+                       errcode = NERR_Success;
                break;
        case 82:                /* pause */
-               if (print_job_pause(jobid)) errcode = NERR_Success;
+               if (print_job_pause(&current_user, jobid, &werr)) 
+                       errcode = NERR_Success;
                break;
        case 83:                /* resume */
-               if (print_job_resume(jobid)) errcode = NERR_Success;
+               if (print_job_resume(&current_user, jobid, &werr)) 
+                       errcode = NERR_Success;
                break;
        }
+
+       if (!W_ERROR_IS_OK(werr))
+               errcode = W_ERROR_V(werr);
        
  out:
        SSVAL(*rparam,0,errcode);       
@@ -1791,7 +2127,7 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param
 /****************************************************************************
   Purge a print queue - or pause or resume it.
   ****************************************************************************/
-static BOOL api_WPrintQueuePurge(connection_struct *conn,uint16 vuid, char *param,char *data,
+static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
                                 int mdrcnt,int mprcnt,
                                 char **rdata,char **rparam,
                                 int *rdata_len,int *rparam_len)
@@ -1802,6 +2138,8 @@ static BOOL api_WPrintQueuePurge(connection_struct *conn,uint16 vuid, char *para
        char *QueueName = skip_string(str2,1);
        int errcode = NERR_notsupported;
        int snum;
+       WERROR werr = WERR_OK;
+       extern struct current_user current_user;
 
        /* check it's a supported varient */
        if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
@@ -1820,16 +2158,18 @@ static BOOL api_WPrintQueuePurge(connection_struct *conn,uint16 vuid, char *para
 
        switch (function) {
        case 74: /* Pause queue */
-               if (print_queue_pause(snum)) errcode = NERR_Success;
+               if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
                break;
        case 75: /* Resume queue */
-               if (print_queue_resume(snum)) errcode = NERR_Success;
+               if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
                break;
        case 103: /* Purge */
-               if (print_queue_purge(snum)) errcode = NERR_Success;
+               if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
                break;
        }
 
+       if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
+
  out:
        SSVAL(*rparam,0,errcode);
        SSVAL(*rparam,2,0);             /* converter word */
@@ -1854,6 +2194,7 @@ static int check_printjob_info(struct pack_desc* desc,
        case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
        case 2: desc->format = "WWzWWDDzz"; break;
        case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
+       case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
        default: return False;
        }
        if (strcmp(desc->format,id) != 0) return False;
@@ -1976,8 +2317,8 @@ static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *par
   p = *rdata;
   p2 = p + struct_len;
   if (uLevel != 20) {
-    StrnCpy(p,local_machine,16);
-    strupper(p);
+    srvstr_push(NULL, p,local_machine,16, 
+               STR_ASCII|STR_UPPER|STR_TERMINATE);
   }
   p += 16;
   if (uLevel > 0)
@@ -1997,7 +2338,7 @@ static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *par
            pstrcpy(comment,servers[i].comment);            
          }
       }
-      if (servers) free(servers);
+      SAFE_FREE(servers);
 
       SCVAL(p,0,lp_major_announce_version());
       SCVAL(p,1,lp_minor_announce_version());
@@ -2041,7 +2382,7 @@ static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param
   char *str2 = skip_string(str1,1);
   char *p = skip_string(str2,1);
   char *p2;
-  extern pstring sesssetup_user;
+  extern userdom_struct current_user_info;
   int level = SVAL(p,0);
 
   DEBUG(4,("NetWkstaGetInfo level %d\n",level));
@@ -2070,7 +2411,7 @@ static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param
   p += 4;
 
   SIVAL(p,0,PTR_DIFF(p2,*rdata));
-  pstrcpy(p2,sesssetup_user);
+  pstrcpy(p2,current_user_info.smb_name);
   p2 = skip_string(p2,1);
   p += 4;
 
@@ -2152,7 +2493,8 @@ Name            Value   Description
 AF_OP_PRINT     0       Print operator
 
 
-Leach, Naik                                        [Page 28]\r\f
+Leach, Naik                                        [Page 28]
+\f
 
 
 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
@@ -2214,7 +2556,8 @@ AF_OP_ACCOUNTS  3       Accounts operator
 
 
 
-Leach, Naik                                        [Page 29]\r\f
+Leach, Naik                                        [Page 29]
+\f
 
 
 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
@@ -2348,6 +2691,7 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param
                SIVALS(p,usri11_password_age,-1);               /* password age */
                SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
                pstrcpy(p2, lp_logon_home());
+               standard_sub_conn(conn, p2);
                p2 = skip_string(p2,1);
                SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
                pstrcpy(p2,"");
@@ -2384,6 +2728,7 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param
                conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
                SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
                pstrcpy(p2,lp_logon_home());
+               standard_sub_conn(conn, p2);
                p2 = skip_string(p2,1);
                SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
                *p2++ = 0;
@@ -2605,6 +2950,7 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para
   struct pack_desc desc;
   print_queue_struct *queue=NULL;
   print_status_struct status;
+  char *tmpdata=NULL;
 
   uLevel = SVAL(p,2);
 
@@ -2626,9 +2972,19 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para
   for (i = 0; i < count; i++) {
     if (queue[i].job == job) break;
   }
-  if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
-  desc.base = *rdata;
-  desc.buflen = mdrcnt;
+
+  if (mdrcnt > 0) {
+    *rdata = REALLOC(*rdata,mdrcnt);
+    desc.base = *rdata;
+    desc.buflen = mdrcnt;
+  } else {
+    /*
+     * Don't return data but need to get correct length
+     *  init_package will return wrong size if buflen=0
+     */
+    desc.buflen = getlen(desc.format);
+    desc.base = tmpdata = (char *)malloc ( desc.buflen );
+  }
 
   if (init_package(&desc,1,0)) {
     if (i < count) {
@@ -2647,7 +3003,8 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para
   SSVAL(*rparam,2,0);
   SSVAL(*rparam,4,desc.neededlen);
 
-  if (queue) free(queue);
+  SAFE_FREE(queue);
+  SAFE_FREE(tmpdata);
 
   DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
   return(True);
@@ -2716,7 +3073,7 @@ static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *pa
   SSVAL(*rparam,4,succnt);
   SSVAL(*rparam,6,count);
 
-  if (queue) free(queue);
+  SAFE_FREE(queue);
 
   DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
   return(True);
@@ -2782,6 +3139,7 @@ static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *par
   int uLevel;
   struct pack_desc desc;
   int snum;
+  char *tmpdata=NULL;
 
   memset((char *)&desc,'\0',sizeof(desc));
 
@@ -2809,9 +3167,18 @@ static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *par
     desc.neededlen = 0;
   }
   else {
-    if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
-    desc.base = *rdata;
-    desc.buflen = mdrcnt;
+    if (mdrcnt > 0) {
+      *rdata = REALLOC(*rdata,mdrcnt);
+      desc.base = *rdata;
+      desc.buflen = mdrcnt;
+    } else {
+      /*
+       * Don't return data but need to get correct length
+       *  init_package will return wrong size if buflen=0
+       */
+      desc.buflen = getlen(desc.format);
+      desc.base = tmpdata = (char *)malloc ( desc.buflen );
+    }
     if (init_package(&desc,1,0)) {
       fill_printdest_info(conn,snum,uLevel,&desc);
     }
@@ -2825,6 +3192,7 @@ static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *par
   SSVAL(*rparam,4,desc.neededlen);
 
   DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
+  SAFE_FREE(tmpdata);
   return(True);
 }
 
@@ -3020,6 +3388,110 @@ static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,
   return(True);
 }
 
+struct session_info {
+  char machine[31];
+  char username[24];
+  char clitype[24];
+  int opens;
+  int time;
+};
+
+struct sessions_info {
+  int count;
+  struct session_info *session_list;
+};
+
+static int gather_sessioninfo(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+  struct sessions_info *sinfo = state;
+  struct session_info *curinfo = NULL;
+  struct sessionid *sessid = (struct sessionid *) dbuf.dptr;
+
+  sinfo->count += 1;
+  sinfo->session_list = REALLOC(sinfo->session_list, sinfo->count * sizeof(struct session_info));
+
+  curinfo = &(sinfo->session_list[sinfo->count - 1]);
+
+  safe_strcpy(curinfo->machine, sessid->remote_machine, 
+             sizeof(curinfo->machine));
+  safe_strcpy(curinfo->username, uidtoname(sessid->uid), 
+         sizeof(curinfo->username));
+  DEBUG(7,("gather_sessioninfo session from %s@%s\n", 
+          curinfo->username, curinfo->machine));
+  return 0;
+}
+
+/****************************************************************************
+ List open sessions
+ ****************************************************************************/
+static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param, char *data,
+                              int mdrcnt,int mprcnt,
+                              char **rdata,char **rparam,
+                              int *rdata_len,int *rparam_len)
+
+{
+  char *str1 = param+2;
+  char *str2 = skip_string(str1,1);
+  char *p = skip_string(str2,1);
+  int uLevel;
+  struct pack_desc desc;
+  struct sessions_info sinfo;
+  int i;
+
+  memset((char *)&desc,'\0',sizeof(desc));
+
+  uLevel = SVAL(p,0);
+
+  DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
+  DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
+  DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
+
+  /* check it's a supported varient */
+  if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) return False;
+  if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) return False;
+
+  sinfo.count = 0;
+  sinfo.session_list = NULL;
+
+  if (!session_traverse(gather_sessioninfo, &sinfo)) {
+    DEBUG(4,("RNetSessionEnum session_traverse failed\n"));
+    return False;
+  }
+
+  if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
+  memset((char *)&desc,'\0',sizeof(desc));
+  desc.base = *rdata;
+  desc.buflen = mdrcnt;
+  desc.format = str2;
+  if (!init_package(&desc,sinfo.count,0)) {
+    return False;
+  }
+
+  for(i=0; i<sinfo.count; i++) {
+    PACKS(&desc, "z", sinfo.session_list[i].machine);
+    PACKS(&desc, "z", sinfo.session_list[i].username);
+    PACKI(&desc, "W", 1); /* num conns */
+    PACKI(&desc, "W", 0); /* num opens */
+    PACKI(&desc, "W", 1); /* num users */
+    PACKI(&desc, "D", 0); /* session time */
+    PACKI(&desc, "D", 0); /* idle time */
+    PACKI(&desc, "D", 0); /* flags */
+    PACKS(&desc, "z", "Unknown Client"); /* client type string */
+  }
+
+  *rdata_len = desc.usedlen;
+
+  *rparam_len = 8;
+  *rparam = REALLOC(*rparam,*rparam_len);
+  SSVALS(*rparam,0,desc.errcode);
+  SSVAL(*rparam,2,0); /* converter */
+  SSVAL(*rparam,4,sinfo.count); /* count */
+
+  DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
+  return True;
+}
+
+
 /****************************************************************************
  The buffer was too small
  ****************************************************************************/
@@ -3075,35 +3547,39 @@ struct
             int,int,char **,char **,int *,int *);
   int flags;
 } api_commands[] = {
-  {"RNetShareEnum",    0,      api_RNetShareEnum,0},
-  {"RNetShareGetInfo", 1,      api_RNetShareGetInfo,0},
-  {"RNetServerGetInfo",        13,     api_RNetServerGetInfo,0},
-  {"RNetGroupGetUsers", 52,    api_RNetGroupGetUsers,0},
-  {"RNetUserGetInfo",  56,     api_RNetUserGetInfo,0},
-  {"NetUserGetGroups", 59,     api_NetUserGetGroups,0},
-  {"NetWkstaGetInfo",  63,     api_NetWkstaGetInfo,0},
-  {"DosPrintQEnum",    69,     api_DosPrintQEnum,0},
-  {"DosPrintQGetInfo", 70,     api_DosPrintQGetInfo,0},
-  {"WPrintQueuePause",  74, api_WPrintQueuePurge,0},
-  {"WPrintQueueResume", 75, api_WPrintQueuePurge,0},
-  {"WPrintJobEnumerate",76,    api_WPrintJobEnumerate,0},
-  {"WPrintJobGetInfo", 77,     api_WPrintJobGetInfo,0},
-  {"RDosPrintJobDel",  81,     api_RDosPrintJobDel,0},
-  {"RDosPrintJobPause",        82,     api_RDosPrintJobDel,0},
-  {"RDosPrintJobResume",83,    api_RDosPrintJobDel,0},
-  {"WPrintDestEnum",   84,     api_WPrintDestEnum,0},
-  {"WPrintDestGetInfo",        85,     api_WPrintDestGetInfo,0},
-  {"NetRemoteTOD",     91,     api_NetRemoteTOD,0},
-  {"WPrintQueuePurge", 103,    api_WPrintQueuePurge,0},
-  {"NetServerEnum",    104,    api_RNetServerEnum,0},
-  {"WAccessGetUserPerms",105,  api_WAccessGetUserPerms,0},
-  {"SetUserPassword",  115,    api_SetUserPassword,0},
-  {"WWkstaUserLogon",  132,    api_WWkstaUserLogon,0},
-  {"PrintJobInfo",     147,    api_PrintJobInfo,0},
-  {"WPrintDriverEnum", 205,    api_WPrintDriverEnum,0},
-  {"WPrintQProcEnum",  206,    api_WPrintQProcEnum,0},
-  {"WPrintPortEnum",   207,    api_WPrintPortEnum,0},
-  {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
+  {"RNetShareEnum",    RAP_WshareEnum,         api_RNetShareEnum,0},
+  {"RNetShareGetInfo", RAP_WshareGetInfo,      api_RNetShareGetInfo,0},
+  {"RNetShareAdd",     RAP_WshareAdd,          api_RNetShareAdd,0},
+  {"RNetSessionEnum",  RAP_WsessionEnum,       api_RNetSessionEnum,0},
+  {"RNetServerGetInfo",        RAP_WserverGetInfo,     api_RNetServerGetInfo,0},
+  {"RNetGroupEnum",    RAP_WGroupEnum,         api_RNetGroupEnum,0},
+  {"RNetGroupGetUsers", RAP_WGroupGetUsers,    api_RNetGroupGetUsers,0},
+  {"RNetUserEnum",     RAP_WUserEnum,          api_RNetUserEnum,0},
+  {"RNetUserGetInfo",  RAP_WUserGetInfo,       api_RNetUserGetInfo,0},
+  {"NetUserGetGroups", RAP_WUserGetGroups,     api_NetUserGetGroups,0},
+  {"NetWkstaGetInfo",  RAP_WWkstaGetInfo,      api_NetWkstaGetInfo,0},
+  {"DosPrintQEnum",    RAP_WPrintQEnum,        api_DosPrintQEnum,0},
+  {"DosPrintQGetInfo", RAP_WPrintQGetInfo,     api_DosPrintQGetInfo,0},
+  {"WPrintQueuePause",  RAP_WPrintQPause,      api_WPrintQueueCtrl,0},
+  {"WPrintQueueResume", RAP_WPrintQContinue,   api_WPrintQueueCtrl,0},
+  {"WPrintJobEnumerate",RAP_WPrintJobEnum,     api_WPrintJobEnumerate,0},
+  {"WPrintJobGetInfo", RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo,0},
+  {"RDosPrintJobDel",  RAP_WPrintJobDel,       api_RDosPrintJobDel,0},
+  {"RDosPrintJobPause",        RAP_WPrintJobPause,     api_RDosPrintJobDel,0},
+  {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel,0},
+  {"WPrintDestEnum",   RAP_WPrintDestEnum,     api_WPrintDestEnum,0},
+  {"WPrintDestGetInfo",        RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo,0},
+  {"NetRemoteTOD",     RAP_NetRemoteTOD,       api_NetRemoteTOD,0},
+  {"WPrintQueuePurge", RAP_WPrintQPurge,       api_WPrintQueueCtrl,0},
+  {"NetServerEnum",    RAP_NetServerEnum2,     api_RNetServerEnum,0},
+  {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms,0},
+  {"SetUserPassword",  RAP_WUserPasswordSet2,  api_SetUserPassword,0},
+  {"WWkstaUserLogon",  RAP_WWkstaUserLogon,    api_WWkstaUserLogon,0},
+  {"PrintJobInfo",     RAP_WPrintJobSetInfo,   api_PrintJobInfo,0},
+  {"WPrintDriverEnum", RAP_WPrintDriverEnum,   api_WPrintDriverEnum,0},
+  {"WPrintQProcEnum",  RAP_WPrintQProcessorEnum,api_WPrintQProcEnum,0},
+  {"WPrintPortEnum",   RAP_WPrintPortEnum,     api_WPrintPortEnum,0},
+  {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword,0},
   {NULL,               -1,     api_Unsupported,0}};
 
 
@@ -3172,13 +3648,8 @@ int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *
 
   send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
 
-  if (rdata )
-    free(rdata);
-  if (rparam)
-    free(rparam);
+  SAFE_FREE(rdata);
+  SAFE_FREE(rparam);
   
   return -1;
 }
-
-
-#undef OLD_NTDOMAIN