r18271: Big change:
[ira/wip.git] / source3 / smbd / lanman.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Inter-process communication and named pipe handling
4    Copyright (C) Andrew Tridgell 1992-1998
5
6    SMB Version handling
7    Copyright (C) John H Terpstra 1995-1998
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22    */
23 /*
24    This file handles the named pipe and mailslot calls
25    in the SMBtrans protocol
26    */
27
28 #include "includes.h"
29
30 extern struct current_user current_user;
31 extern userdom_struct current_user_info;
32
33 #ifdef CHECK_TYPES
34 #undef CHECK_TYPES
35 #endif
36 #define CHECK_TYPES 0
37
38 #define NERR_Success 0
39 #define NERR_badpass 86
40 #define NERR_notsupported 50
41
42 #define NERR_BASE (2100)
43 #define NERR_BufTooSmall (NERR_BASE+23)
44 #define NERR_JobNotFound (NERR_BASE+51)
45 #define NERR_DestNotFound (NERR_BASE+52)
46
47 #define ACCESS_READ 0x01
48 #define ACCESS_WRITE 0x02
49 #define ACCESS_CREATE 0x04
50
51 #define SHPWLEN 8               /* share password length */
52
53 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param, char *data,
54                             int mdrcnt, int mprcnt,
55                             char **rdata, char **rparam,
56                             int *rdata_len, int *rparam_len);
57 static BOOL api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
58                          int mdrcnt, int mprcnt,
59                          char **rdata, char **rparam,
60                          int *rdata_len, int *rparam_len);
61
62
63 static int CopyExpanded(connection_struct *conn, 
64                         int snum, char **dst, char *src, int *n)
65 {
66         pstring buf;
67         int l;
68
69         if (!src || !dst || !n || !(*dst)) {
70                 return 0;
71         }
72
73         StrnCpy(buf,src,sizeof(buf)/2);
74         pstring_sub(buf,"%S",lp_servicename(snum));
75         standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
76                               conn->connectpath, conn->gid,
77                               get_current_username(),
78                               current_user_info.domain,
79                               buf, sizeof(buf));
80         l = push_ascii(*dst,buf,*n, STR_TERMINATE);
81         (*dst) += l;
82         (*n) -= l;
83         return l;
84 }
85
86 static int CopyAndAdvance(char **dst, char *src, int *n)
87 {
88         int l;
89         if (!src || !dst || !n || !(*dst)) {
90                 return 0;
91         }
92         l = push_ascii(*dst,src,*n, STR_TERMINATE);
93         (*dst) += l;
94         (*n) -= l;
95         return l;
96 }
97
98 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
99 {
100         pstring buf;
101         if (!s) {
102                 return 0;
103         }
104         StrnCpy(buf,s,sizeof(buf)/2);
105         pstring_sub(buf,"%S",lp_servicename(snum));
106         standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
107                               conn->connectpath, conn->gid,
108                               get_current_username(),
109                               current_user_info.domain,
110                               buf, sizeof(buf));
111         return strlen(buf) + 1;
112 }
113
114 static char *Expand(connection_struct *conn, int snum, char *s)
115 {
116         static pstring buf;
117         if (!s) {
118                 return NULL;
119         }
120         StrnCpy(buf,s,sizeof(buf)/2);
121         pstring_sub(buf,"%S",lp_servicename(snum));
122         standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
123                               conn->connectpath, conn->gid,
124                               get_current_username(),
125                               current_user_info.domain,
126                               buf, sizeof(buf));
127         return &buf[0];
128 }
129
130 /*******************************************************************
131  Check a API string for validity when we only need to check the prefix.
132 ******************************************************************/
133
134 static BOOL prefix_ok(const char *str, const char *prefix)
135 {
136         return(strncmp(str,prefix,strlen(prefix)) == 0);
137 }
138
139 struct pack_desc {
140         const char *format;         /* formatstring for structure */
141         const char *subformat;  /* subformat for structure */
142         char *base;         /* baseaddress of buffer */
143         int buflen;        /* remaining size for fixed part; on init: length of base */
144         int subcount;       /* count of substructures */
145         char *structbuf;  /* pointer into buffer for remaining fixed part */
146         int stringlen;    /* remaining size for variable part */                
147         char *stringbuf;  /* pointer into buffer for remaining variable part */
148         int neededlen;    /* total needed size */
149         int usedlen;        /* total used size (usedlen <= neededlen and usedlen <= buflen) */
150         const char *curpos;         /* current position; pointer into format or subformat */
151         int errcode;
152 };
153
154 static int get_counter(const char **p)
155 {
156         int i, n;
157         if (!p || !(*p)) {
158                 return 1;
159         }
160         if (!isdigit((int)**p)) {
161                 return 1;
162         }
163         for (n = 0;;) {
164                 i = **p;
165                 if (isdigit(i)) {
166                         n = 10 * n + (i - '0');
167                 } else {
168                         return n;
169                 }
170                 (*p)++;
171         }
172 }
173
174 static int getlen(const char *p)
175 {
176         int n = 0;
177         if (!p) {
178                 return 0;
179         }
180
181         while (*p) {
182                 switch( *p++ ) {
183                 case 'W':                       /* word (2 byte) */
184                         n += 2;
185                         break;
186                 case 'K':                       /* status word? (2 byte) */
187                         n += 2;
188                         break;
189                 case 'N':                       /* count of substructures (word) at end */
190                         n += 2;
191                         break;
192                 case 'D':                       /* double word (4 byte) */
193                 case 'z':                       /* offset to zero terminated string (4 byte) */
194                 case 'l':                       /* offset to user data (4 byte) */
195                         n += 4;
196                         break;
197                 case 'b':                       /* offset to data (with counter) (4 byte) */
198                         n += 4;
199                         get_counter(&p);
200                         break;
201                 case 'B':                       /* byte (with optional counter) */
202                         n += get_counter(&p);
203                         break;
204                 }
205         }
206         return n;
207 }
208
209 static BOOL init_package(struct pack_desc *p, int count, int subcount)
210 {
211         int n = p->buflen;
212         int i;
213
214         if (!p->format || !p->base) {
215                 return False;
216         }
217
218         i = count * getlen(p->format);
219         if (p->subformat) {
220                 i += subcount * getlen(p->subformat);
221         }
222         p->structbuf = p->base;
223         p->neededlen = 0;
224         p->usedlen = 0;
225         p->subcount = 0;
226         p->curpos = p->format;
227         if (i > n) {
228                 p->neededlen = i;
229                 i = n = 0;
230 #if 0
231                 /*
232                  * This is the old error code we used. Aparently
233                  * WinNT/2k systems return ERRbuftoosmall (2123) and
234                  * OS/2 needs this. I'm leaving this here so we can revert
235                  * if needed. JRA.
236                  */
237                 p->errcode = ERRmoredata;
238 #else
239                 p->errcode = ERRbuftoosmall;
240 #endif
241         } else {
242                 p->errcode = NERR_Success;
243         }
244         p->buflen = i;
245         n -= i;
246         p->stringbuf = p->base + i;
247         p->stringlen = n;
248         return (p->errcode == NERR_Success);
249 }
250
251 static int package(struct pack_desc *p, ...)
252 {
253         va_list args;
254         int needed=0, stringneeded;
255         const char *str=NULL;
256         int is_string=0, stringused;
257         int32 temp;
258
259         va_start(args,p);
260
261         if (!*p->curpos) {
262                 if (!p->subcount) {
263                         p->curpos = p->format;
264                 } else {
265                         p->curpos = p->subformat;
266                         p->subcount--;
267                 }
268         }
269 #if CHECK_TYPES
270         str = va_arg(args,char*);
271         SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
272 #endif
273         stringneeded = -1;
274
275         if (!p->curpos) {
276                 va_end(args);
277                 return 0;
278         }
279
280         switch( *p->curpos++ ) {
281                 case 'W':                       /* word (2 byte) */
282                         needed = 2;
283                         temp = va_arg(args,int);
284                         if (p->buflen >= needed) {
285                                 SSVAL(p->structbuf,0,temp);
286                         }
287                         break;
288                 case 'K':                       /* status word? (2 byte) */
289                         needed = 2;
290                         temp = va_arg(args,int);
291                         if (p->buflen >= needed) {
292                                 SSVAL(p->structbuf,0,temp);
293                         }
294                         break;
295                 case 'N':                       /* count of substructures (word) at end */
296                         needed = 2;
297                         p->subcount = va_arg(args,int);
298                         if (p->buflen >= needed) {
299                                 SSVAL(p->structbuf,0,p->subcount);
300                         }
301                         break;
302                 case 'D':                       /* double word (4 byte) */
303                         needed = 4;
304                         temp = va_arg(args,int);
305                         if (p->buflen >= needed) {
306                                 SIVAL(p->structbuf,0,temp);
307                         }
308                         break;
309                 case 'B':                       /* byte (with optional counter) */
310                         needed = get_counter(&p->curpos);
311                         {
312                                 char *s = va_arg(args,char*);
313                                 if (p->buflen >= needed) {
314                                         StrnCpy(p->structbuf,s?s:"",needed-1);
315                                 }
316                         }
317                         break;
318                 case 'z':                       /* offset to zero terminated string (4 byte) */
319                         str = va_arg(args,char*);
320                         stringneeded = (str ? strlen(str)+1 : 0);
321                         is_string = 1;
322                         break;
323                 case 'l':                       /* offset to user data (4 byte) */
324                         str = va_arg(args,char*);
325                         stringneeded = va_arg(args,int);
326                         is_string = 0;
327                         break;
328                 case 'b':                       /* offset to data (with counter) (4 byte) */
329                         str = va_arg(args,char*);
330                         stringneeded = get_counter(&p->curpos);
331                         is_string = 0;
332                         break;
333         }
334
335         va_end(args);
336         if (stringneeded >= 0) {
337                 needed = 4;
338                 if (p->buflen >= needed) {
339                         stringused = stringneeded;
340                         if (stringused > p->stringlen) {
341                                 stringused = (is_string ? p->stringlen : 0);
342                                 if (p->errcode == NERR_Success) {
343                                         p->errcode = ERRmoredata;
344                                 }
345                         }
346                         if (!stringused) {
347                                 SIVAL(p->structbuf,0,0);
348                         } else {
349                                 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
350                                 memcpy(p->stringbuf,str?str:"",stringused);
351                                 if (is_string) {
352                                         p->stringbuf[stringused-1] = '\0';
353                                 }
354                                 p->stringbuf += stringused;
355                                 p->stringlen -= stringused;
356                                 p->usedlen += stringused;
357                         }
358                 }
359                 p->neededlen += stringneeded;
360         }
361
362         p->neededlen += needed;
363         if (p->buflen >= needed) {
364                 p->structbuf += needed;
365                 p->buflen -= needed;
366                 p->usedlen += needed;
367         } else {
368                 if (p->errcode == NERR_Success) {
369                         p->errcode = ERRmoredata;
370                 }
371         }
372         return 1;
373 }
374
375 #if CHECK_TYPES
376 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
377 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
378 #else
379 #define PACK(desc,t,v) package(desc,v)
380 #define PACKl(desc,t,v,l) package(desc,v,l)
381 #endif
382
383 static void PACKI(struct pack_desc* desc, const char *t,int v)
384 {
385         PACK(desc,t,v);
386 }
387
388 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
389 {
390         PACK(desc,t,v);
391 }
392
393 /****************************************************************************
394  Get a print queue.
395 ****************************************************************************/
396
397 static void PackDriverData(struct pack_desc* desc)
398 {
399         char drivdata[4+4+32];
400         SIVAL(drivdata,0,sizeof drivdata); /* cb */
401         SIVAL(drivdata,4,1000); /* lVersion */
402         memset(drivdata+8,0,32);        /* szDeviceName */
403         push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
404         PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
405 }
406
407 static int check_printq_info(struct pack_desc* desc,
408                                 unsigned int uLevel, char *id1, char *id2)
409 {
410         desc->subformat = NULL;
411         switch( uLevel ) {
412                 case 0:
413                         desc->format = "B13";
414                         break;
415                 case 1:
416                         desc->format = "B13BWWWzzzzzWW";
417                         break;
418                 case 2:
419                         desc->format = "B13BWWWzzzzzWN";
420                         desc->subformat = "WB21BB16B10zWWzDDz";
421                         break;
422                 case 3:
423                         desc->format = "zWWWWzzzzWWzzl";
424                         break;
425                 case 4:
426                         desc->format = "zWWWWzzzzWNzzl";
427                         desc->subformat = "WWzWWDDzz";
428                         break;
429                 case 5:
430                         desc->format = "z";
431                         break;
432                 case 51:
433                         desc->format = "K";
434                         break;
435                 case 52:
436                         desc->format = "WzzzzzzzzN";
437                         desc->subformat = "z";
438                         break;
439                 default:
440                         return False;
441         }
442         if (strcmp(desc->format,id1) != 0) {
443                 return False;
444         }
445         if (desc->subformat && strcmp(desc->subformat,id2) != 0) {
446                 return False;
447         }
448         return True;
449 }
450
451
452 #define RAP_JOB_STATUS_QUEUED 0
453 #define RAP_JOB_STATUS_PAUSED 1
454 #define RAP_JOB_STATUS_SPOOLING 2
455 #define RAP_JOB_STATUS_PRINTING 3
456 #define RAP_JOB_STATUS_PRINTED 4
457
458 #define RAP_QUEUE_STATUS_PAUSED 1
459 #define RAP_QUEUE_STATUS_ERROR 2
460
461 /* turn a print job status into a on the wire status 
462 */
463 static int printj_status(int v)
464 {
465         switch (v) {
466         case LPQ_QUEUED:
467                 return RAP_JOB_STATUS_QUEUED;
468         case LPQ_PAUSED:
469                 return RAP_JOB_STATUS_PAUSED;
470         case LPQ_SPOOLING:
471                 return RAP_JOB_STATUS_SPOOLING;
472         case LPQ_PRINTING:
473                 return RAP_JOB_STATUS_PRINTING;
474         }
475         return 0;
476 }
477
478 /* turn a print queue status into a on the wire status 
479 */
480 static int printq_status(int v)
481 {
482         switch (v) {
483         case LPQ_QUEUED:
484                 return 0;
485         case LPQ_PAUSED:
486                 return RAP_QUEUE_STATUS_PAUSED;
487         }
488         return RAP_QUEUE_STATUS_ERROR;
489 }
490
491 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
492                                struct pack_desc *desc,
493                                print_queue_struct *queue, int n)
494 {
495         time_t t = queue->time;
496
497         /* the client expects localtime */
498         t -= get_time_zone(t);
499
500         PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
501         if (uLevel == 1) {
502                 PACKS(desc,"B21",queue->fs_user); /* szUserName */
503                 PACKS(desc,"B","");             /* pad */
504                 PACKS(desc,"B16","");   /* szNotifyName */
505                 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
506                 PACKS(desc,"z","");             /* pszParms */
507                 PACKI(desc,"W",n+1);            /* uPosition */
508                 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
509                 PACKS(desc,"z","");             /* pszStatus */
510                 PACKI(desc,"D",t); /* ulSubmitted */
511                 PACKI(desc,"D",queue->size); /* ulSize */
512                 PACKS(desc,"z",queue->fs_file); /* pszComment */
513         }
514         if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
515                 PACKI(desc,"W",queue->priority);                /* uPriority */
516                 PACKS(desc,"z",queue->fs_user); /* pszUserName */
517                 PACKI(desc,"W",n+1);            /* uPosition */
518                 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
519                 PACKI(desc,"D",t); /* ulSubmitted */
520                 PACKI(desc,"D",queue->size); /* ulSize */
521                 PACKS(desc,"z","Samba");        /* pszComment */
522                 PACKS(desc,"z",queue->fs_file); /* pszDocument */
523                 if (uLevel == 3) {
524                         PACKS(desc,"z","");     /* pszNotifyName */
525                         PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
526                         PACKS(desc,"z","");     /* pszParms */
527                         PACKS(desc,"z","");     /* pszStatus */
528                         PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
529                         PACKS(desc,"z","lpd");  /* pszQProcName */
530                         PACKS(desc,"z","");     /* pszQProcParms */
531                         PACKS(desc,"z","NULL"); /* pszDriverName */
532                         PackDriverData(desc);   /* pDriverData */
533                         PACKS(desc,"z","");     /* pszPrinterName */
534                 } else if (uLevel == 4) {   /* OS2 */
535                         PACKS(desc,"z","");       /* pszSpoolFileName  */
536                         PACKS(desc,"z","");       /* pszPortName       */
537                         PACKS(desc,"z","");       /* pszStatus         */
538                         PACKI(desc,"D",0);        /* ulPagesSpooled    */
539                         PACKI(desc,"D",0);        /* ulPagesSent       */
540                         PACKI(desc,"D",0);        /* ulPagesPrinted    */
541                         PACKI(desc,"D",0);        /* ulTimePrinted     */
542                         PACKI(desc,"D",0);        /* ulExtendJobStatus */
543                         PACKI(desc,"D",0);        /* ulStartPage       */
544                         PACKI(desc,"D",0);        /* ulEndPage         */
545                 }
546         }
547 }
548
549 /********************************************************************
550  Return a driver name given an snum.
551  Returns True if from tdb, False otherwise.
552  ********************************************************************/
553
554 static BOOL get_driver_name(int snum, pstring drivername)
555 {
556         NT_PRINTER_INFO_LEVEL *info = NULL;
557         BOOL in_tdb = False;
558
559         get_a_printer (NULL, &info, 2, lp_servicename(snum));
560         if (info != NULL) {
561                 pstrcpy( drivername, info->info_2->drivername);
562                 in_tdb = True;
563                 free_a_printer(&info, 2);
564         }
565
566         return in_tdb;
567 }
568
569 /********************************************************************
570  Respond to the DosPrintQInfo command with a level of 52
571  This is used to get printer driver information for Win9x clients
572  ********************************************************************/
573 static void fill_printq_info_52(connection_struct *conn, int snum, 
574                                 struct pack_desc* desc, int count )
575 {
576         int                             i;
577         fstring                         location;
578         NT_PRINTER_DRIVER_INFO_LEVEL    driver;
579         NT_PRINTER_INFO_LEVEL           *printer = NULL;
580
581         ZERO_STRUCT(driver);
582
583         if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
584                 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n", 
585                         lp_servicename(snum)));
586                 goto err;
587         }
588                 
589         if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, 
590                 "Windows 4.0", 0)) )
591         {
592                 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n", 
593                         printer->info_2->drivername));
594                 goto err;
595         }
596
597         trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
598         trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
599         trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
600         
601         PACKI(desc, "W", 0x0400);                     /* don't know */
602         PACKS(desc, "z", driver.info_3->name);        /* long printer name */
603         PACKS(desc, "z", driver.info_3->driverpath);  /* Driverfile Name */
604         PACKS(desc, "z", driver.info_3->datafile);    /* Datafile name */
605         PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
606         
607         fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
608         standard_sub_basic( "", "", location, sizeof(location)-1 );
609         PACKS(desc,"z", location);                          /* share to retrieve files */
610         
611         PACKS(desc,"z", driver.info_3->defaultdatatype);    /* default data type */
612         PACKS(desc,"z", driver.info_3->helpfile);           /* helpfile name */
613         PACKS(desc,"z", driver.info_3->driverpath);               /* driver name */
614
615         DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
616         DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
617         DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
618         DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
619         DEBUG(3,("Driver Location: %s:\n",location));
620         DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
621         DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
622         PACKI(desc,"N",count);                     /* number of files to copy */
623
624         for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++) 
625         {
626                 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
627                 PACKS(desc,"z",driver.info_3->dependentfiles[i]);         /* driver files to copy */
628                 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
629         }
630         
631         /* sanity check */
632         if ( i != count )
633                 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
634                         count, i));
635                 
636         DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
637
638         desc->errcode=NERR_Success;
639         goto done;
640
641 err:
642         DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
643         desc->errcode=NERR_notsupported;
644
645 done:
646         if ( printer )
647                 free_a_printer( &printer, 2 );
648                 
649         if ( driver.info_3 )
650                 free_a_printer_driver( driver, 3 );
651 }
652
653
654 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
655                              struct pack_desc* desc,
656                              int count, print_queue_struct* queue,
657                              print_status_struct* status)
658 {
659         switch (uLevel) {
660         case 1:
661         case 2:
662                 PACKS(desc,"B13",SERVICE(snum));
663                 break;
664         case 3:
665         case 4:
666         case 5:
667                 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
668                 break;
669         case 51:
670                 PACKI(desc,"K",printq_status(status->status));
671                 break;
672         }
673
674         if (uLevel == 1 || uLevel == 2) {
675                 PACKS(desc,"B","");             /* alignment */
676                 PACKI(desc,"W",5);              /* priority */
677                 PACKI(desc,"W",0);              /* start time */
678                 PACKI(desc,"W",0);              /* until time */
679                 PACKS(desc,"z","");             /* pSepFile */
680                 PACKS(desc,"z","lpd");  /* pPrProc */
681                 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
682                 PACKS(desc,"z","");             /* pParms */
683                 if (snum < 0) {
684                         PACKS(desc,"z","UNKNOWN PRINTER");
685                         PACKI(desc,"W",LPSTAT_ERROR);
686                 }
687                 else if (!status || !status->message[0]) {
688                         PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
689                         PACKI(desc,"W",LPSTAT_OK); /* status */
690                 } else {
691                         PACKS(desc,"z",status->message);
692                         PACKI(desc,"W",printq_status(status->status)); /* status */
693                 }
694                 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
695         }
696
697         if (uLevel == 3 || uLevel == 4) {
698                 pstring drivername;
699
700                 PACKI(desc,"W",5);              /* uPriority */
701                 PACKI(desc,"W",0);              /* uStarttime */
702                 PACKI(desc,"W",0);              /* uUntiltime */
703                 PACKI(desc,"W",5);              /* pad1 */
704                 PACKS(desc,"z","");             /* pszSepFile */
705                 PACKS(desc,"z","WinPrint");     /* pszPrProc */
706                 PACKS(desc,"z",NULL);           /* pszParms */
707                 PACKS(desc,"z",NULL);           /* pszComment - don't ask.... JRA */
708                 /* "don't ask" that it's done this way to fix corrupted 
709                    Win9X/ME printer comments. */
710                 if (!status) {
711                         PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
712                 } else {
713                         PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
714                 }
715                 PACKI(desc,(uLevel == 3 ? "W" : "N"),count);    /* cJobs */
716                 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
717                 get_driver_name(snum,drivername);
718                 PACKS(desc,"z",drivername);             /* pszDriverName */
719                 PackDriverData(desc);   /* pDriverData */
720         }
721
722         if (uLevel == 2 || uLevel == 4) {
723                 int i;
724                 for (i=0;i<count;i++)
725                         fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
726         }
727
728         if (uLevel==52)
729                 fill_printq_info_52( conn, snum, desc, count );
730 }
731
732 /* This function returns the number of files for a given driver */
733 static int get_printerdrivernumber(int snum)
734 {
735         int                             result = 0;
736         NT_PRINTER_DRIVER_INFO_LEVEL    driver;
737         NT_PRINTER_INFO_LEVEL           *printer = NULL;
738
739         ZERO_STRUCT(driver);
740
741         if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
742                 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n", 
743                         lp_servicename(snum)));
744                 goto done;
745         }
746                 
747         if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, 
748                 "Windows 4.0", 0)) )
749         {
750                 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n", 
751                         printer->info_2->drivername));
752                 goto done;
753         }
754         
755         /* count the number of files */
756         while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
757                         result++;
758                         \
759  done:
760         if ( printer )
761                 free_a_printer( &printer, 2 );
762                 
763         if ( driver.info_3 )
764                 free_a_printer_driver( driver, 3 );
765                 
766         return result;
767 }
768
769 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
770                                  uint16 vuid, char *param,char *data,
771                                  int mdrcnt,int mprcnt,
772                                  char **rdata,char **rparam,
773                                  int *rdata_len,int *rparam_len)
774 {
775         char *str1 = param+2;
776         char *str2 = skip_string(str1,1);
777         char *p = skip_string(str2,1);
778         char *QueueName = p;
779         unsigned int uLevel;
780         int count=0;
781         int snum;
782         char* str3;
783         struct pack_desc desc;
784         print_queue_struct *queue=NULL;
785         print_status_struct status;
786         char* tmpdata=NULL;
787
788         memset((char *)&status,'\0',sizeof(status));
789         memset((char *)&desc,'\0',sizeof(desc));
790  
791         p = skip_string(p,1);
792         uLevel = SVAL(p,0);
793         str3 = p + 4;
794  
795         /* remove any trailing username */
796         if ((p = strchr_m(QueueName,'%')))
797                 *p = 0;
798  
799         DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
800  
801         /* check it's a supported varient */
802         if (!prefix_ok(str1,"zWrLh"))
803                 return False;
804         if (!check_printq_info(&desc,uLevel,str2,str3)) {
805                 /*
806                  * Patch from Scott Moomaw <scott@bridgewater.edu>
807                  * to return the 'invalid info level' error if an
808                  * unknown level was requested.
809                  */
810                 *rdata_len = 0;
811                 *rparam_len = 6;
812                 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
813                 if (!*rparam) {
814                         return False;
815                 }
816                 SSVALS(*rparam,0,ERRunknownlevel);
817                 SSVAL(*rparam,2,0);
818                 SSVAL(*rparam,4,0);
819                 return(True);
820         }
821  
822         snum = find_service(QueueName);
823         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
824                 return False;
825                 
826         if (uLevel==52) {
827                 count = get_printerdrivernumber(snum);
828                 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
829         } else {
830                 count = print_queue_status(snum, &queue,&status);
831         }
832
833         if (mdrcnt > 0) {
834                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
835                 if (!*rdata) {
836                         return False;
837                 }
838                 desc.base = *rdata;
839                 desc.buflen = mdrcnt;
840         } else {
841                 /*
842                  * Don't return data but need to get correct length
843                  * init_package will return wrong size if buflen=0
844                  */
845                 desc.buflen = getlen(desc.format);
846                 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
847         }
848
849         if (init_package(&desc,1,count)) {
850                 desc.subcount = count;
851                 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
852         }
853
854         *rdata_len = desc.usedlen;
855   
856         /*
857          * We must set the return code to ERRbuftoosmall
858          * in order to support lanman style printing with Win NT/2k
859          * clients       --jerry
860          */
861         if (!mdrcnt && lp_disable_spoolss())
862                 desc.errcode = ERRbuftoosmall;
863  
864         *rdata_len = desc.usedlen;
865         *rparam_len = 6;
866         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
867         if (!*rparam) {
868                 return False;
869         }
870         SSVALS(*rparam,0,desc.errcode);
871         SSVAL(*rparam,2,0);
872         SSVAL(*rparam,4,desc.neededlen);
873   
874         DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
875
876         SAFE_FREE(queue);
877         SAFE_FREE(tmpdata);
878
879         return(True);
880 }
881
882 /****************************************************************************
883  View list of all print jobs on all queues.
884 ****************************************************************************/
885
886 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
887                               int mdrcnt, int mprcnt,
888                               char **rdata, char** rparam,
889                               int *rdata_len, int *rparam_len)
890 {
891         char *param_format = param+2;
892         char *output_format1 = skip_string(param_format,1);
893         char *p = skip_string(output_format1,1);
894         unsigned int uLevel = SVAL(p,0);
895         char *output_format2 = p + 4;
896         int services = lp_numservices();
897         int i, n;
898         struct pack_desc desc;
899         print_queue_struct **queue = NULL;
900         print_status_struct *status = NULL;
901         int *subcntarr = NULL;
902         int queuecnt = 0, subcnt = 0, succnt = 0;
903  
904         memset((char *)&desc,'\0',sizeof(desc));
905
906         DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
907  
908         if (!prefix_ok(param_format,"WrLeh")) {
909                 return False;
910         }
911         if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
912                 /*
913                  * Patch from Scott Moomaw <scott@bridgewater.edu>
914                  * to return the 'invalid info level' error if an
915                  * unknown level was requested.
916                  */
917                 *rdata_len = 0;
918                 *rparam_len = 6;
919                 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
920                 if (!*rparam) {
921                         return False;
922                 }
923                 SSVALS(*rparam,0,ERRunknownlevel);
924                 SSVAL(*rparam,2,0);
925                 SSVAL(*rparam,4,0);
926                 return(True);
927         }
928
929         for (i = 0; i < services; i++) {
930                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
931                         queuecnt++;
932                 }
933         }
934
935         if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
936                 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
937                 goto err;
938         }
939         memset(queue,0,queuecnt*sizeof(print_queue_struct*));
940         if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
941                 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
942                 goto err;
943         }
944         memset(status,0,queuecnt*sizeof(print_status_struct));
945         if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
946                 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
947                 goto err;
948         }
949
950         subcnt = 0;
951         n = 0;
952         for (i = 0; i < services; i++) {
953                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
954                         subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
955                         subcnt += subcntarr[n];
956                         n++;
957                 }
958         }
959
960         if (mdrcnt > 0) {
961                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
962                 if (!*rdata) {
963                         goto err;
964                 }
965         }
966         desc.base = *rdata;
967         desc.buflen = mdrcnt;
968
969         if (init_package(&desc,queuecnt,subcnt)) {
970                 n = 0;
971                 succnt = 0;
972                 for (i = 0; i < services; i++) {
973                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
974                                 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
975                                 n++;
976                                 if (desc.errcode == NERR_Success) {
977                                         succnt = n;
978                                 }
979                         }
980                 }
981         }
982
983         SAFE_FREE(subcntarr);
984  
985         *rdata_len = desc.usedlen;
986         *rparam_len = 8;
987         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
988         if (!*rparam) {
989                 goto err;
990         }
991         SSVALS(*rparam,0,desc.errcode);
992         SSVAL(*rparam,2,0);
993         SSVAL(*rparam,4,succnt);
994         SSVAL(*rparam,6,queuecnt);
995   
996         for (i = 0; i < queuecnt; i++) {
997                 if (queue) {
998                         SAFE_FREE(queue[i]);
999                 }
1000         }
1001
1002         SAFE_FREE(queue);
1003         SAFE_FREE(status);
1004   
1005         return True;
1006
1007   err:
1008
1009         SAFE_FREE(subcntarr);
1010         for (i = 0; i < queuecnt; i++) {
1011                 if (queue) {
1012                         SAFE_FREE(queue[i]);
1013                 }
1014         }
1015         SAFE_FREE(queue);
1016         SAFE_FREE(status);
1017
1018         return False;
1019 }
1020
1021 /****************************************************************************
1022  Get info level for a server list query.
1023 ****************************************************************************/
1024
1025 static BOOL check_server_info(int uLevel, char* id)
1026 {
1027         switch( uLevel ) {
1028                 case 0:
1029                         if (strcmp(id,"B16") != 0) {
1030                                 return False;
1031                         }
1032                         break;
1033                 case 1:
1034                         if (strcmp(id,"B16BBDz") != 0) {
1035                                 return False;
1036                         }
1037                         break;
1038                 default: 
1039                         return False;
1040         }
1041         return True;
1042 }
1043
1044 struct srv_info_struct {
1045         fstring name;
1046         uint32 type;
1047         fstring comment;
1048         fstring domain;
1049         BOOL server_added;
1050 };
1051
1052 /*******************************************************************
1053  Get server info lists from the files saved by nmbd. Return the
1054  number of entries.
1055 ******************************************************************/
1056
1057 static int get_server_info(uint32 servertype, 
1058                            struct srv_info_struct **servers,
1059                            const char *domain)
1060 {
1061         int count=0;
1062         int alloced=0;
1063         char **lines;
1064         BOOL local_list_only;
1065         int i;
1066
1067         lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1068         if (!lines) {
1069                 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1070                 return 0;
1071         }
1072
1073         /* request for everything is code for request all servers */
1074         if (servertype == SV_TYPE_ALL) {
1075                 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1076         }
1077
1078         local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1079
1080         DEBUG(4,("Servertype search: %8x\n",servertype));
1081
1082         for (i=0;lines[i];i++) {
1083                 fstring stype;
1084                 struct srv_info_struct *s;
1085                 const char *ptr = lines[i];
1086                 BOOL ok = True;
1087
1088                 if (!*ptr) {
1089                         continue;
1090                 }
1091     
1092                 if (count == alloced) {
1093                         alloced += 10;
1094                         *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1095                         if (!*servers) {
1096                                 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1097                                 file_lines_free(lines);
1098                                 return 0;
1099                         }
1100                         memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1101                 }
1102                 s = &(*servers)[count];
1103     
1104                 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1105                         continue;
1106                 }
1107                 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1108                         continue;
1109                 }
1110                 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1111                         continue;
1112                 }
1113                 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1114                         /* this allows us to cope with an old nmbd */
1115                         fstrcpy(s->domain,lp_workgroup()); 
1116                 }
1117     
1118                 if (sscanf(stype,"%X",&s->type) != 1) { 
1119                         DEBUG(4,("r:host file ")); 
1120                         ok = False; 
1121                 }
1122     
1123                 /* Filter the servers/domains we return based on what was asked for. */
1124
1125                 /* Check to see if we are being asked for a local list only. */
1126                 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1127                         DEBUG(4,("r: local list only"));
1128                         ok = False;
1129                 }
1130
1131                 /* doesn't match up: don't want it */
1132                 if (!(servertype & s->type)) { 
1133                         DEBUG(4,("r:serv type ")); 
1134                         ok = False; 
1135                 }
1136     
1137                 if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1138                                 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1139                         DEBUG(4,("s: dom mismatch "));
1140                         ok = False;
1141                 }
1142     
1143                 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1144                         ok = False;
1145                 }
1146     
1147                 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1148                 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1149
1150                 if (ok) {
1151                         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1152                                 s->name, s->type, s->comment, s->domain));
1153                         s->server_added = True;
1154                         count++;
1155                 } else {
1156                         DEBUG(4,("%20s %8x %25s %15s\n",
1157                                 s->name, s->type, s->comment, s->domain));
1158                 }
1159         }
1160   
1161         file_lines_free(lines);
1162         return count;
1163 }
1164
1165 /*******************************************************************
1166  Fill in a server info structure.
1167 ******************************************************************/
1168
1169 static int fill_srv_info(struct srv_info_struct *service, 
1170                          int uLevel, char **buf, int *buflen, 
1171                          char **stringbuf, int *stringspace, char *baseaddr)
1172 {
1173         int struct_len;
1174         char* p;
1175         char* p2;
1176         int l2;
1177         int len;
1178  
1179         switch (uLevel) {
1180                 case 0:
1181                         struct_len = 16;
1182                         break;
1183                 case 1:
1184                         struct_len = 26;
1185                         break;
1186                 default:
1187                         return -1;
1188         }
1189  
1190         if (!buf) {
1191                 len = 0;
1192                 switch (uLevel) {
1193                         case 1:
1194                                 len = strlen(service->comment)+1;
1195                                 break;
1196                 }
1197
1198                 *buflen = struct_len;
1199                 *stringspace = len;
1200                 return struct_len + len;
1201         }
1202   
1203         len = struct_len;
1204         p = *buf;
1205         if (*buflen < struct_len) {
1206                 return -1;
1207         }
1208         if (stringbuf) {
1209                 p2 = *stringbuf;
1210                 l2 = *stringspace;
1211         } else {
1212                 p2 = p + struct_len;
1213                 l2 = *buflen - struct_len;
1214         }
1215         if (!baseaddr) {
1216                 baseaddr = p;
1217         }
1218   
1219         switch (uLevel) {
1220                 case 0:
1221                         push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1222                         break;
1223
1224                 case 1:
1225                         push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1226                         SIVAL(p,18,service->type);
1227                         SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1228                         len += CopyAndAdvance(&p2,service->comment,&l2);
1229                         break;
1230         }
1231
1232         if (stringbuf) {
1233                 *buf = p + struct_len;
1234                 *buflen -= struct_len;
1235                 *stringbuf = p2;
1236                 *stringspace = l2;
1237         } else {
1238                 *buf = p2;
1239                 *buflen -= len;
1240         }
1241         return len;
1242 }
1243
1244
1245 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1246 {
1247         return(strcmp(s1->name,s2->name));
1248 }
1249
1250 /****************************************************************************
1251  View list of servers available (or possibly domains). The info is
1252  extracted from lists saved by nmbd on the local host.
1253 ****************************************************************************/
1254
1255 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1256                                int mdrcnt, int mprcnt, char **rdata, 
1257                                char **rparam, int *rdata_len, int *rparam_len)
1258 {
1259         char *str1 = param+2;
1260         char *str2 = skip_string(str1,1);
1261         char *p = skip_string(str2,1);
1262         int uLevel = SVAL(p,0);
1263         int buf_len = SVAL(p,2);
1264         uint32 servertype = IVAL(p,4);
1265         char *p2;
1266         int data_len, fixed_len, string_len;
1267         int f_len = 0, s_len = 0;
1268         struct srv_info_struct *servers=NULL;
1269         int counted=0,total=0;
1270         int i,missed;
1271         fstring domain;
1272         BOOL domain_request;
1273         BOOL local_request;
1274
1275         /* If someone sets all the bits they don't really mean to set
1276            DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1277            known servers. */
1278
1279         if (servertype == SV_TYPE_ALL) {
1280                 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1281         }
1282
1283         /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1284            any other bit (they may just set this bit on it's own) they 
1285            want all the locally seen servers. However this bit can be 
1286            set on its own so set the requested servers to be 
1287            ALL - DOMAIN_ENUM. */
1288
1289         if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1290                 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1291         }
1292
1293         domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1294         local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1295
1296         p += 8;
1297
1298         if (!prefix_ok(str1,"WrLehD")) {
1299                 return False;
1300         }
1301         if (!check_server_info(uLevel,str2)) {
1302                 return False;
1303         }
1304   
1305         DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1306         DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1307         DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1308
1309         if (strcmp(str1, "WrLehDz") == 0) {
1310                 pull_ascii_fstring(domain, p);
1311         } else {
1312                 fstrcpy(domain, lp_workgroup());
1313         }
1314
1315         if (lp_browse_list()) {
1316                 total = get_server_info(servertype,&servers,domain);
1317         }
1318
1319         data_len = fixed_len = string_len = 0;
1320         missed = 0;
1321
1322         if (total > 0) {
1323                 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1324         }
1325
1326         {
1327                 char *lastname=NULL;
1328
1329                 for (i=0;i<total;i++) {
1330                         struct srv_info_struct *s = &servers[i];
1331
1332                         if (lastname && strequal(lastname,s->name)) {
1333                                 continue;
1334                         }
1335                         lastname = s->name;
1336                         data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1337                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1338                                 s->name, s->type, s->comment, s->domain));
1339       
1340                         if (data_len <= buf_len) {
1341                                 counted++;
1342                                 fixed_len += f_len;
1343                                 string_len += s_len;
1344                         } else {
1345                                 missed++;
1346                         }
1347                 }
1348         }
1349
1350         *rdata_len = fixed_len + string_len;
1351         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1352         if (!*rdata) {
1353                 return False;
1354         }
1355         memset(*rdata,'\0',*rdata_len);
1356   
1357         p2 = (*rdata) + fixed_len;      /* auxilliary data (strings) will go here */
1358         p = *rdata;
1359         f_len = fixed_len;
1360         s_len = string_len;
1361
1362         {
1363                 char *lastname=NULL;
1364                 int count2 = counted;
1365
1366                 for (i = 0; i < total && count2;i++) {
1367                         struct srv_info_struct *s = &servers[i];
1368
1369                         if (lastname && strequal(lastname,s->name)) {
1370                                 continue;
1371                         }
1372                         lastname = s->name;
1373                         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1374                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1375                                 s->name, s->type, s->comment, s->domain));
1376                         count2--;
1377                 }
1378         }
1379   
1380         *rparam_len = 8;
1381         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1382         if (!*rparam) {
1383                 return False;
1384         }
1385         SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1386         SSVAL(*rparam,2,0);
1387         SSVAL(*rparam,4,counted);
1388         SSVAL(*rparam,6,counted+missed);
1389
1390         SAFE_FREE(servers);
1391
1392         DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1393                 domain,uLevel,counted,counted+missed));
1394
1395         return True;
1396 }
1397
1398 /****************************************************************************
1399   command 0x34 - suspected of being a "Lookup Names" stub api
1400   ****************************************************************************/
1401
1402 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1403                                int mdrcnt, int mprcnt, char **rdata, 
1404                                char **rparam, int *rdata_len, int *rparam_len)
1405 {
1406         char *str1 = param+2;
1407         char *str2 = skip_string(str1,1);
1408         char *p = skip_string(str2,1);
1409         int uLevel = SVAL(p,0);
1410         int buf_len = SVAL(p,2);
1411         int counted=0;
1412         int missed=0;
1413
1414         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1415                 str1, str2, p, uLevel, buf_len));
1416
1417         if (!prefix_ok(str1,"zWrLeh")) {
1418                 return False;
1419         }
1420   
1421         *rdata_len = 0;
1422   
1423         *rparam_len = 8;
1424         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1425         if (!*rparam) {
1426                 return False;
1427         }
1428
1429         SSVAL(*rparam,0,0x08AC); /* informational warning message */
1430         SSVAL(*rparam,2,0);
1431         SSVAL(*rparam,4,counted);
1432         SSVAL(*rparam,6,counted+missed);
1433
1434         return True;
1435 }
1436
1437 /****************************************************************************
1438   get info about a share
1439   ****************************************************************************/
1440
1441 static BOOL check_share_info(int uLevel, char* id)
1442 {
1443         switch( uLevel ) {
1444                 case 0:
1445                         if (strcmp(id,"B13") != 0) {
1446                                 return False;
1447                         }
1448                         break;
1449                 case 1:
1450                         if (strcmp(id,"B13BWz") != 0) {
1451                                 return False;
1452                         }
1453                         break;
1454                 case 2:
1455                         if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1456                                 return False;
1457                         }
1458                         break;
1459                 case 91:
1460                         if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1461                                 return False;
1462                         }
1463                         break;
1464                 default:
1465                         return False;
1466         }
1467         return True;
1468 }
1469
1470 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1471                            char** buf, int* buflen,
1472                            char** stringbuf, int* stringspace, char* baseaddr)
1473 {
1474         int struct_len;
1475         char* p;
1476         char* p2;
1477         int l2;
1478         int len;
1479  
1480         switch( uLevel ) {
1481                 case 0:
1482                         struct_len = 13;
1483                         break;
1484                 case 1:
1485                         struct_len = 20;
1486                         break;
1487                 case 2:
1488                         struct_len = 40;
1489                         break;
1490                 case 91:
1491                         struct_len = 68;
1492                         break;
1493                 default:
1494                         return -1;
1495         }
1496   
1497  
1498         if (!buf) {
1499                 len = 0;
1500
1501                 if (uLevel > 0) {
1502                         len += StrlenExpanded(conn,snum,lp_comment(snum));
1503                 }
1504                 if (uLevel > 1) {
1505                         len += strlen(lp_pathname(snum)) + 1;
1506                 }
1507                 if (buflen) {
1508                         *buflen = struct_len;
1509                 }
1510                 if (stringspace) {
1511                         *stringspace = len;
1512                 }
1513                 return struct_len + len;
1514         }
1515   
1516         len = struct_len;
1517         p = *buf;
1518         if ((*buflen) < struct_len) {
1519                 return -1;
1520         }
1521
1522         if (stringbuf) {
1523                 p2 = *stringbuf;
1524                 l2 = *stringspace;
1525         } else {
1526                 p2 = p + struct_len;
1527                 l2 = (*buflen) - struct_len;
1528         }
1529
1530         if (!baseaddr) {
1531                 baseaddr = p;
1532         }
1533   
1534         push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1535   
1536         if (uLevel > 0) {
1537                 int type;
1538
1539                 SCVAL(p,13,0);
1540                 type = STYPE_DISKTREE;
1541                 if (lp_print_ok(snum)) {
1542                         type = STYPE_PRINTQ;
1543                 }
1544                 if (strequal("IPC",lp_fstype(snum))) {
1545                         type = STYPE_IPC;
1546                 }
1547                 SSVAL(p,14,type);               /* device type */
1548                 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1549                 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1550         }
1551   
1552         if (uLevel > 1) {
1553                 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1554                 SSVALS(p,22,-1);                /* max uses */
1555                 SSVAL(p,24,1); /* current uses */
1556                 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1557                 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1558                 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1559         }
1560   
1561         if (uLevel > 2) {
1562                 memset(p+40,0,SHPWLEN+2);
1563                 SSVAL(p,50,0);
1564                 SIVAL(p,52,0);
1565                 SSVAL(p,56,0);
1566                 SSVAL(p,58,0);
1567                 SIVAL(p,60,0);
1568                 SSVAL(p,64,0);
1569                 SSVAL(p,66,0);
1570         }
1571        
1572         if (stringbuf) {
1573                 (*buf) = p + struct_len;
1574                 (*buflen) -= struct_len;
1575                 (*stringbuf) = p2;
1576                 (*stringspace) = l2;
1577         } else {
1578                 (*buf) = p2;
1579                 (*buflen) -= len;
1580         }
1581
1582         return len;
1583 }
1584
1585 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1586                                  int mdrcnt,int mprcnt,
1587                                  char **rdata,char **rparam,
1588                                  int *rdata_len,int *rparam_len)
1589 {
1590         char *str1 = param+2;
1591         char *str2 = skip_string(str1,1);
1592         char *netname = skip_string(str2,1);
1593         char *p = skip_string(netname,1);
1594         int uLevel = SVAL(p,0);
1595         int snum = find_service(netname);
1596   
1597         if (snum < 0) {
1598                 return False;
1599         }
1600   
1601         /* check it's a supported varient */
1602         if (!prefix_ok(str1,"zWrLh")) {
1603                 return False;
1604         }
1605         if (!check_share_info(uLevel,str2)) {
1606                 return False;
1607         }
1608  
1609         *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
1610         if (!*rdata) {
1611                 return False;
1612         }
1613         p = *rdata;
1614         *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1615         if (*rdata_len < 0) {
1616                 return False;
1617         }
1618  
1619         *rparam_len = 6;
1620         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1621         if (!*rparam) {
1622                 return False;
1623         }
1624         SSVAL(*rparam,0,NERR_Success);
1625         SSVAL(*rparam,2,0);             /* converter word */
1626         SSVAL(*rparam,4,*rdata_len);
1627  
1628         return True;
1629 }
1630
1631 /****************************************************************************
1632   View the list of available shares.
1633
1634   This function is the server side of the NetShareEnum() RAP call.
1635   It fills the return buffer with share names and share comments.
1636   Note that the return buffer normally (in all known cases) allows only
1637   twelve byte strings for share names (plus one for a nul terminator).
1638   Share names longer than 12 bytes must be skipped.
1639  ****************************************************************************/
1640
1641 static BOOL api_RNetShareEnum( connection_struct *conn,
1642                                uint16             vuid,
1643                                char              *param,
1644                                char              *data,
1645                                int                mdrcnt,
1646                                int                mprcnt,
1647                                char             **rdata,
1648                                char             **rparam,
1649                                int               *rdata_len,
1650                                int               *rparam_len )
1651 {
1652         char *str1 = param+2;
1653         char *str2 = skip_string(str1,1);
1654         char *p = skip_string(str2,1);
1655         int uLevel = SVAL(p,0);
1656         int buf_len = SVAL(p,2);
1657         char *p2;
1658         int count = 0;
1659         int total=0,counted=0;
1660         BOOL missed = False;
1661         int i;
1662         int data_len, fixed_len, string_len;
1663         int f_len = 0, s_len = 0;
1664  
1665         if (!prefix_ok(str1,"WrLeh")) {
1666                 return False;
1667         }
1668         if (!check_share_info(uLevel,str2)) {
1669                 return False;
1670         }
1671   
1672         /* Ensure all the usershares are loaded. */
1673         become_root();
1674         count = load_usershare_shares();
1675         unbecome_root();
1676
1677         data_len = fixed_len = string_len = 0;
1678         for (i=0;i<count;i++) {
1679                 fstring servicename_dos;
1680                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1681                         continue;
1682                 }
1683                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1684                 /* Maximum name length = 13. */
1685                 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1686                         total++;
1687                         data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1688                         if (data_len <= buf_len) {
1689                                 counted++;
1690                                 fixed_len += f_len;
1691                                 string_len += s_len;
1692                         } else {
1693                                 missed = True;
1694                         }
1695                 }
1696         }
1697
1698         *rdata_len = fixed_len + string_len;
1699         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1700         if (!*rdata) {
1701                 return False;
1702         }
1703         memset(*rdata,0,*rdata_len);
1704   
1705         p2 = (*rdata) + fixed_len;      /* auxiliary data (strings) will go here */
1706         p = *rdata;
1707         f_len = fixed_len;
1708         s_len = string_len;
1709
1710         for( i = 0; i < count; i++ ) {
1711                 fstring servicename_dos;
1712                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1713                         continue;
1714                 }
1715
1716                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1717                 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1718                         if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1719                                 break;
1720                         }
1721                 }
1722         }
1723   
1724         *rparam_len = 8;
1725         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1726         if (!*rparam) {
1727                 return False;
1728         }
1729         SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1730         SSVAL(*rparam,2,0);
1731         SSVAL(*rparam,4,counted);
1732         SSVAL(*rparam,6,total);
1733   
1734         DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1735                 counted,total,uLevel,
1736                 buf_len,*rdata_len,mdrcnt));
1737
1738         return True;
1739 }
1740
1741 /****************************************************************************
1742   Add a share
1743   ****************************************************************************/
1744
1745 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid, char *param,char *data,
1746                                  int mdrcnt,int mprcnt,
1747                                  char **rdata,char **rparam,
1748                                  int *rdata_len,int *rparam_len)
1749 {
1750         char *str1 = param+2;
1751         char *str2 = skip_string(str1,1);
1752         char *p = skip_string(str2,1);
1753         int uLevel = SVAL(p,0);
1754         fstring sharename;
1755         fstring comment;
1756         pstring pathname;
1757         char *command, *cmdname;
1758         unsigned int offset;
1759         int snum;
1760         int res = ERRunsup;
1761   
1762         /* check it's a supported varient */
1763         if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1764                 return False;
1765         }
1766         if (!check_share_info(uLevel,str2)) {
1767                 return False;
1768         }
1769         if (uLevel != 2) {
1770                 return False;
1771         }
1772
1773         pull_ascii_fstring(sharename,data);
1774         snum = find_service(sharename);
1775         if (snum >= 0) { /* already exists */
1776                 res = ERRfilexists;
1777                 goto error_exit;
1778         }
1779
1780         /* only support disk share adds */
1781         if (SVAL(data,14)!=STYPE_DISKTREE) {
1782                 return False;
1783         }
1784
1785         offset = IVAL(data, 16);
1786         if (offset >= mdrcnt) {
1787                 res = ERRinvalidparam;
1788                 goto error_exit;
1789         }
1790
1791         pull_ascii_fstring(comment, offset? (data+offset) : "");
1792
1793         offset = IVAL(data, 26);
1794
1795         if (offset >= mdrcnt) {
1796                 res = ERRinvalidparam;
1797                 goto error_exit;
1798         }
1799
1800         pull_ascii_pstring(pathname, offset? (data+offset) : "");
1801
1802         string_replace(sharename, '"', ' ');
1803         string_replace(pathname, '"', ' ');
1804         string_replace(comment, '"', ' ');
1805
1806         cmdname = lp_add_share_cmd();
1807
1808         if (!cmdname || *cmdname == '\0') {
1809                 return False;
1810         }
1811
1812         asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1813                 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1814
1815         if (command) {
1816                 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1817
1818                 if ((res = smbrun(command, NULL)) != 0) {
1819                         DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1820                         SAFE_FREE(command);
1821                         res = ERRnoaccess;
1822                         goto error_exit;
1823                 } else {
1824                         SAFE_FREE(command);
1825                         message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
1826                 }
1827         } else {
1828                 return False;
1829         }
1830
1831         *rparam_len = 6;
1832         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1833         if (!*rparam) {
1834                 return False;
1835         }
1836         SSVAL(*rparam,0,NERR_Success);
1837         SSVAL(*rparam,2,0);             /* converter word */
1838         SSVAL(*rparam,4,*rdata_len);
1839         *rdata_len = 0;
1840   
1841         return True;
1842
1843   error_exit:
1844
1845         *rparam_len = 4;
1846         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1847         if (!*rparam) {
1848                 return False;
1849         }
1850         *rdata_len = 0;
1851         SSVAL(*rparam,0,res);
1852         SSVAL(*rparam,2,0);
1853         return True;
1854 }
1855
1856 /****************************************************************************
1857   view list of groups available
1858   ****************************************************************************/
1859
1860 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1861                               int mdrcnt,int mprcnt,
1862                               char **rdata,char **rparam,
1863                               int *rdata_len,int *rparam_len)
1864 {
1865         int i;
1866         int errflags=0;
1867         int resume_context, cli_buf_size;
1868         char *str1 = param+2;
1869         char *str2 = skip_string(str1,1);
1870         char *p = skip_string(str2,1);
1871
1872         struct pdb_search *search;
1873         struct samr_displayentry *entries;
1874
1875         int num_entries;
1876  
1877         if (strcmp(str1,"WrLeh") != 0) {
1878                 return False;
1879         }
1880
1881         /* parameters  
1882          * W-> resume context (number of users to skip)
1883          * r -> return parameter pointer to receive buffer 
1884          * L -> length of receive buffer
1885          * e -> return parameter number of entries
1886          * h -> return parameter total number of users
1887          */
1888
1889         if (strcmp("B21",str2) != 0) {
1890                 return False;
1891         }
1892
1893         /* get list of domain groups SID_DOMAIN_GRP=2 */
1894         become_root();
1895         search = pdb_search_groups();
1896         unbecome_root();
1897
1898         if (search == NULL) {
1899                 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1900                 return False;
1901         }
1902
1903         resume_context = SVAL(p,0); 
1904         cli_buf_size=SVAL(p+2,0);
1905         DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1906                   "%d\n", resume_context, cli_buf_size));
1907
1908         become_root();
1909         num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1910                                          &entries);
1911         unbecome_root();
1912
1913         *rdata_len = cli_buf_size;
1914         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1915         if (!*rdata) {
1916                 return False;
1917         }
1918
1919         p = *rdata;
1920
1921         for(i=0; i<num_entries; i++) {
1922                 fstring name;
1923                 fstrcpy(name, entries[i].account_name);
1924                 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
1925                         /* truncate the name at 21 chars. */
1926                         memcpy(p, name, 21); 
1927                         DEBUG(10,("adding entry %d group %s\n", i, p));
1928                         p += 21;
1929                         p += 5; /* Both NT4 and W2k3SP1 do padding here.
1930                                    No idea why... */
1931                 } else {
1932                         /* set overflow error */
1933                         DEBUG(3,("overflow on entry %d group %s\n", i, name));
1934                         errflags=234;
1935                         break;
1936                 }
1937         }
1938
1939         pdb_search_destroy(search);
1940
1941         *rdata_len = PTR_DIFF(p,*rdata);
1942
1943         *rparam_len = 8;
1944         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1945         if (!*rparam) {
1946                 return False;
1947         }
1948         SSVAL(*rparam, 0, errflags);
1949         SSVAL(*rparam, 2, 0);           /* converter word */
1950         SSVAL(*rparam, 4, i);   /* is this right?? */
1951         SSVAL(*rparam, 6, resume_context+num_entries);  /* is this right?? */
1952
1953         return(True);
1954 }
1955
1956 /*******************************************************************
1957  Get groups that a user is a member of.
1958 ******************************************************************/
1959
1960 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
1961                               int mdrcnt,int mprcnt,
1962                               char **rdata,char **rparam,
1963                               int *rdata_len,int *rparam_len)
1964 {
1965         char *str1 = param+2;
1966         char *str2 = skip_string(str1,1);
1967         char *UserName = skip_string(str2,1);
1968         char *p = skip_string(UserName,1);
1969         int uLevel = SVAL(p,0);
1970         const char *level_string;
1971         int count=0;
1972         struct samu *sampw = NULL;
1973         BOOL ret = False;
1974         DOM_SID *sids;
1975         gid_t *gids;
1976         size_t num_groups;
1977         size_t i;
1978         NTSTATUS result;
1979         DOM_SID user_sid;
1980         enum lsa_SidType type;
1981         TALLOC_CTX *mem_ctx;
1982
1983         *rparam_len = 8;
1984         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1985         if (!*rparam) {
1986                 return False;
1987         }
1988   
1989         /* check it's a supported varient */
1990         
1991         if ( strcmp(str1,"zWrLeh") != 0 )
1992                 return False;
1993                 
1994         switch( uLevel ) {
1995                 case 0:
1996                         level_string = "B21";
1997                         break;
1998                 default:
1999                         return False;
2000         }
2001
2002         if (strcmp(level_string,str2) != 0)
2003                 return False;
2004
2005         *rdata_len = mdrcnt + 1024;
2006         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2007         if (!*rdata) {
2008                 return False;
2009         }
2010         SSVAL(*rparam,0,NERR_Success);
2011         SSVAL(*rparam,2,0);             /* converter word */
2012
2013         p = *rdata;
2014
2015         mem_ctx = talloc_new(NULL);
2016         if (mem_ctx == NULL) {
2017                 DEBUG(0, ("talloc_new failed\n"));
2018                 return False;
2019         }
2020
2021         if ( !(sampw = samu_new(mem_ctx)) ) {
2022                 DEBUG(0, ("samu_new() failed!\n"));
2023                 TALLOC_FREE(mem_ctx);
2024                 return False;
2025         }
2026
2027         /* Lookup the user information; This should only be one of 
2028            our accounts (not remote domains) */
2029
2030         become_root();                                  /* ROOT BLOCK */
2031
2032         if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2033                          NULL, NULL, &user_sid, &type)) {
2034                 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2035                 goto done;
2036         }
2037
2038         if (type != SID_NAME_USER) {
2039                 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2040                            sid_type_lookup(type)));
2041                 goto done;
2042         }
2043
2044         if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2045                 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2046                            sid_string_static(&user_sid), UserName));
2047                 goto done;
2048         }
2049
2050         gids = NULL;
2051         sids = NULL;
2052         num_groups = 0;
2053
2054         result = pdb_enum_group_memberships(mem_ctx, sampw,
2055                                             &sids, &gids, &num_groups);
2056
2057         if (!NT_STATUS_IS_OK(result)) {
2058                 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2059                            UserName));
2060                 goto done;
2061         }
2062
2063         for (i=0; i<num_groups; i++) {
2064
2065                 const char *grp_name;
2066         
2067                 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2068                         pstrcpy(p, grp_name);
2069                         p += 21; 
2070                         count++;
2071                 }
2072         }
2073
2074         *rdata_len = PTR_DIFF(p,*rdata);
2075
2076         SSVAL(*rparam,4,count); /* is this right?? */
2077         SSVAL(*rparam,6,count); /* is this right?? */
2078
2079         ret = True;
2080
2081 done:
2082         unbecome_root();                                /* END ROOT BLOCK */
2083
2084         TALLOC_FREE(mem_ctx);
2085
2086         return ret;
2087 }
2088
2089 /*******************************************************************
2090  Get all users.
2091 ******************************************************************/
2092
2093 static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2094                                  int mdrcnt,int mprcnt,
2095                                  char **rdata,char **rparam,
2096                                  int *rdata_len,int *rparam_len)
2097 {
2098         int count_sent=0;
2099         int num_users=0;
2100         int errflags=0;
2101         int i, resume_context, cli_buf_size;
2102         struct pdb_search *search;
2103         struct samr_displayentry *users;
2104
2105         char *str1 = param+2;
2106         char *str2 = skip_string(str1,1);
2107         char *p = skip_string(str2,1);
2108
2109         if (strcmp(str1,"WrLeh") != 0)
2110                 return False;
2111         /* parameters
2112           * W-> resume context (number of users to skip)
2113           * r -> return parameter pointer to receive buffer
2114           * L -> length of receive buffer
2115           * e -> return parameter number of entries
2116           * h -> return parameter total number of users
2117           */
2118   
2119         resume_context = SVAL(p,0);
2120         cli_buf_size=SVAL(p+2,0);
2121         DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2122                         resume_context, cli_buf_size));
2123
2124         *rparam_len = 8;
2125         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2126         if (!*rparam) {
2127                 return False;
2128         }
2129
2130         /* check it's a supported varient */
2131         if (strcmp("B21",str2) != 0)
2132                 return False;
2133
2134         *rdata_len = cli_buf_size;
2135         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2136         if (!*rdata) {
2137                 return False;
2138         }
2139
2140         p = *rdata;
2141
2142         become_root();
2143         search = pdb_search_users(ACB_NORMAL);
2144         unbecome_root();
2145         if (search == NULL) {
2146                 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2147                 return False;
2148         }
2149
2150         become_root();
2151         num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2152                                        &users);
2153         unbecome_root();
2154
2155         errflags=NERR_Success;
2156
2157         for (i=0; i<num_users; i++) {
2158                 const char *name = users[i].account_name;
2159                 
2160                 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2161                         pstrcpy(p,name); 
2162                         DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2163                                   "%s\n",count_sent,p));
2164                         p += 21; 
2165                         count_sent++; 
2166                 } else {
2167                         /* set overflow error */
2168                         DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2169                                   "username %s\n",count_sent,name));
2170                         errflags=234;
2171                         break;
2172                 }
2173         }
2174
2175         pdb_search_destroy(search);
2176
2177         *rdata_len = PTR_DIFF(p,*rdata);
2178
2179         SSVAL(*rparam,0,errflags);
2180         SSVAL(*rparam,2,0);           /* converter word */
2181         SSVAL(*rparam,4,count_sent);  /* is this right?? */
2182         SSVAL(*rparam,6,num_users); /* is this right?? */
2183
2184         return True;
2185 }
2186
2187 /****************************************************************************
2188  Get the time of day info.
2189 ****************************************************************************/
2190
2191 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
2192                              int mdrcnt,int mprcnt,
2193                              char **rdata,char **rparam,
2194                              int *rdata_len,int *rparam_len)
2195 {
2196         struct tm *t;
2197         time_t unixdate = time(NULL);
2198         char *p;
2199
2200         *rparam_len = 4;
2201         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2202         if (!*rparam) {
2203                 return False;
2204         }
2205
2206         *rdata_len = 21;
2207         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2208         if (!*rdata) {
2209                 return False;
2210         }
2211
2212         SSVAL(*rparam,0,NERR_Success);
2213         SSVAL(*rparam,2,0);             /* converter word */
2214
2215         p = *rdata;
2216
2217         srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2218                                             by NT in a "net time" operation,
2219                                             it seems to ignore the one below */
2220
2221         /* the client expects to get localtime, not GMT, in this bit 
2222                 (I think, this needs testing) */
2223         t = localtime(&unixdate);
2224         if (!t) {
2225                 return False;
2226         }
2227
2228         SIVAL(p,4,0);           /* msecs ? */
2229         SCVAL(p,8,t->tm_hour);
2230         SCVAL(p,9,t->tm_min);
2231         SCVAL(p,10,t->tm_sec);
2232         SCVAL(p,11,0);          /* hundredths of seconds */
2233         SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2234         SSVAL(p,14,10000);              /* timer interval in 0.0001 of sec */
2235         SCVAL(p,16,t->tm_mday);
2236         SCVAL(p,17,t->tm_mon + 1);
2237         SSVAL(p,18,1900+t->tm_year);
2238         SCVAL(p,20,t->tm_wday);
2239
2240         return True;
2241 }
2242
2243 /****************************************************************************
2244  Set the user password.
2245 *****************************************************************************/
2246
2247 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
2248                                 int mdrcnt,int mprcnt,
2249                                 char **rdata,char **rparam,
2250                                 int *rdata_len,int *rparam_len)
2251 {
2252         char *p = skip_string(param+2,2);
2253         fstring user;
2254         fstring pass1,pass2;
2255
2256         pull_ascii_fstring(user,p);
2257
2258         p = skip_string(p,1);
2259
2260         memset(pass1,'\0',sizeof(pass1));
2261         memset(pass2,'\0',sizeof(pass2));
2262         memcpy(pass1,p,16);
2263         memcpy(pass2,p+16,16);
2264
2265         *rparam_len = 4;
2266         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2267         if (!*rparam) {
2268                 return False;
2269         }
2270
2271         *rdata_len = 0;
2272
2273         SSVAL(*rparam,0,NERR_badpass);
2274         SSVAL(*rparam,2,0);             /* converter word */
2275
2276         DEBUG(3,("Set password for <%s>\n",user));
2277
2278         /*
2279          * Attempt to verify the old password against smbpasswd entries
2280          * Win98 clients send old and new password in plaintext for this call.
2281          */
2282
2283         {
2284                 auth_serversupplied_info *server_info = NULL;
2285                 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2286
2287                 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2288
2289                         become_root();
2290                         if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2291                                 SSVAL(*rparam,0,NERR_Success);
2292                         }
2293                         unbecome_root();
2294
2295                         TALLOC_FREE(server_info);
2296                 }
2297                 data_blob_clear_free(&password);
2298         }
2299
2300         /*
2301          * If the plaintext change failed, attempt
2302          * the old encrypted method. NT will generate this
2303          * after trying the samr method. Note that this
2304          * method is done as a last resort as this
2305          * password change method loses the NT password hash
2306          * and cannot change the UNIX password as no plaintext
2307          * is received.
2308          */
2309
2310         if(SVAL(*rparam,0) != NERR_Success) {
2311                 struct samu *hnd = NULL;
2312
2313                 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2314                         become_root();
2315                         if (change_lanman_password(hnd,(uchar *)pass2)) {
2316                                 SSVAL(*rparam,0,NERR_Success);
2317                         }
2318                         unbecome_root();
2319                         TALLOC_FREE(hnd);
2320                 }
2321         }
2322
2323         memset((char *)pass1,'\0',sizeof(fstring));
2324         memset((char *)pass2,'\0',sizeof(fstring));      
2325          
2326         return(True);
2327 }
2328
2329 /****************************************************************************
2330   Set the user password (SamOEM version - gets plaintext).
2331 ****************************************************************************/
2332
2333 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
2334                                 int mdrcnt,int mprcnt,
2335                                 char **rdata,char **rparam,
2336                                 int *rdata_len,int *rparam_len)
2337 {
2338         fstring user;
2339         char *p = param + 2;
2340         *rparam_len = 2;
2341         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2342         if (!*rparam) {
2343                 return False;
2344         }
2345
2346         *rdata_len = 0;
2347
2348         SSVAL(*rparam,0,NERR_badpass);
2349
2350         /*
2351          * Check the parameter definition is correct.
2352          */
2353
2354         if(!strequal(param + 2, "zsT")) {
2355                 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
2356                 return False;
2357         }
2358         p = skip_string(p, 1);
2359
2360         if(!strequal(p, "B516B16")) {
2361                 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2362                 return False;
2363         }
2364         p = skip_string(p,1);
2365         p += pull_ascii_fstring(user,p);
2366
2367         DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2368
2369         /*
2370          * Pass the user through the NT -> unix user mapping
2371          * function.
2372          */
2373
2374         (void)map_username(user);
2375
2376         if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2377                 SSVAL(*rparam,0,NERR_Success);
2378         }
2379
2380         return(True);
2381 }
2382
2383 /****************************************************************************
2384   delete a print job
2385   Form: <W> <> 
2386   ****************************************************************************/
2387
2388 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
2389                                 int mdrcnt,int mprcnt,
2390                                 char **rdata,char **rparam,
2391                                 int *rdata_len,int *rparam_len)
2392 {
2393         int function = SVAL(param,0);
2394         char *str1 = param+2;
2395         char *str2 = skip_string(str1,1);
2396         char *p = skip_string(str2,1);
2397         uint32 jobid;
2398         int snum;
2399         fstring sharename;
2400         int errcode;
2401         WERROR werr = WERR_OK;
2402
2403         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2404                 return False;
2405
2406         /* check it's a supported varient */
2407         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2408                 return(False);
2409
2410         *rparam_len = 4;
2411         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);       
2412         if (!*rparam) {
2413                 return False;
2414         }
2415         *rdata_len = 0;
2416
2417         if (!print_job_exists(sharename, jobid)) {
2418                 errcode = NERR_JobNotFound;
2419                 goto out;
2420         }
2421
2422         snum = lp_servicenumber( sharename);
2423         if (snum == -1) {
2424                 errcode = NERR_DestNotFound;
2425                 goto out;
2426         }
2427
2428         errcode = NERR_notsupported;
2429         
2430         switch (function) {
2431         case 81:                /* delete */ 
2432                 if (print_job_delete(&current_user, snum, jobid, &werr)) 
2433                         errcode = NERR_Success;
2434                 break;
2435         case 82:                /* pause */
2436                 if (print_job_pause(&current_user, snum, jobid, &werr)) 
2437                         errcode = NERR_Success;
2438                 break;
2439         case 83:                /* resume */
2440                 if (print_job_resume(&current_user, snum, jobid, &werr)) 
2441                         errcode = NERR_Success;
2442                 break;
2443         }
2444
2445         if (!W_ERROR_IS_OK(werr))
2446                 errcode = W_ERROR_V(werr);
2447         
2448  out:
2449         SSVAL(*rparam,0,errcode);       
2450         SSVAL(*rparam,2,0);             /* converter word */
2451
2452         return(True);
2453 }
2454
2455 /****************************************************************************
2456   Purge a print queue - or pause or resume it.
2457   ****************************************************************************/
2458
2459 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
2460                                  int mdrcnt,int mprcnt,
2461                                  char **rdata,char **rparam,
2462                                  int *rdata_len,int *rparam_len)
2463 {
2464         int function = SVAL(param,0);
2465         char *str1 = param+2;
2466         char *str2 = skip_string(str1,1);
2467         char *QueueName = skip_string(str2,1);
2468         int errcode = NERR_notsupported;
2469         int snum;
2470         WERROR werr = WERR_OK;
2471
2472         /* check it's a supported varient */
2473         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2474                 return(False);
2475
2476         *rparam_len = 4;
2477         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2478         if (!*rparam) {
2479                 return False;
2480         }
2481         *rdata_len = 0;
2482
2483         snum = print_queue_snum(QueueName);
2484
2485         if (snum == -1) {
2486                 errcode = NERR_JobNotFound;
2487                 goto out;
2488         }
2489
2490         switch (function) {
2491         case 74: /* Pause queue */
2492                 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2493                 break;
2494         case 75: /* Resume queue */
2495                 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2496                 break;
2497         case 103: /* Purge */
2498                 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2499                 break;
2500         }
2501
2502         if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2503
2504  out:
2505         SSVAL(*rparam,0,errcode);
2506         SSVAL(*rparam,2,0);             /* converter word */
2507
2508         return(True);
2509 }
2510
2511 /****************************************************************************
2512   set the property of a print job (undocumented?)
2513   ? function = 0xb -> set name of print job
2514   ? function = 0x6 -> move print job up/down
2515   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2516   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2517 ****************************************************************************/
2518
2519 static int check_printjob_info(struct pack_desc* desc,
2520                                int uLevel, char* id)
2521 {
2522         desc->subformat = NULL;
2523         switch( uLevel ) {
2524         case 0: desc->format = "W"; break;
2525         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2526         case 2: desc->format = "WWzWWDDzz"; break;
2527         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2528         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2529         default: return False;
2530         }
2531         if (strcmp(desc->format,id) != 0) return False;
2532         return True;
2533 }
2534
2535 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2536                              int mdrcnt,int mprcnt,
2537                              char **rdata,char **rparam,
2538                              int *rdata_len,int *rparam_len)
2539 {
2540         struct pack_desc desc;
2541         char *str1 = param+2;
2542         char *str2 = skip_string(str1,1);
2543         char *p = skip_string(str2,1);
2544         uint32 jobid;
2545         fstring sharename;
2546         int uLevel = SVAL(p,2);
2547         int function = SVAL(p,4);
2548         int place, errcode;
2549
2550         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2551                 return False;
2552         *rparam_len = 4;
2553         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2554         if (!*rparam) {
2555                 return False;
2556         }
2557
2558         if (!share_defined(sharename)) {
2559                 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2560                          sharename));
2561                 return False;
2562         }
2563   
2564         *rdata_len = 0;
2565         
2566         /* check it's a supported varient */
2567         if ((strcmp(str1,"WWsTP")) || 
2568             (!check_printjob_info(&desc,uLevel,str2)))
2569                 return(False);
2570
2571         if (!print_job_exists(sharename, jobid)) {
2572                 errcode=NERR_JobNotFound;
2573                 goto out;
2574         }
2575
2576         errcode = NERR_notsupported;
2577
2578         switch (function) {
2579         case 0x6:
2580                 /* change job place in the queue, 
2581                    data gives the new place */
2582                 place = SVAL(data,0);
2583                 if (print_job_set_place(sharename, jobid, place)) {
2584                         errcode=NERR_Success;
2585                 }
2586                 break;
2587
2588         case 0xb:   
2589                 /* change print job name, data gives the name */
2590                 if (print_job_set_name(sharename, jobid, data)) {
2591                         errcode=NERR_Success;
2592                 }
2593                 break;
2594
2595         default:
2596                 return False;
2597         }
2598
2599  out:
2600         SSVALS(*rparam,0,errcode);
2601         SSVAL(*rparam,2,0);             /* converter word */
2602         
2603         return(True);
2604 }
2605
2606
2607 /****************************************************************************
2608  Get info about the server.
2609 ****************************************************************************/
2610
2611 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2612                                   int mdrcnt,int mprcnt,
2613                                   char **rdata,char **rparam,
2614                                   int *rdata_len,int *rparam_len)
2615 {
2616         char *str1 = param+2;
2617         char *str2 = skip_string(str1,1);
2618         char *p = skip_string(str2,1);
2619         int uLevel = SVAL(p,0);
2620         char *p2;
2621         int struct_len;
2622
2623         DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2624
2625         /* check it's a supported varient */
2626         if (!prefix_ok(str1,"WrLh")) {
2627                 return False;
2628         }
2629
2630         switch( uLevel ) {
2631                 case 0:
2632                         if (strcmp(str2,"B16") != 0) {
2633                                 return False;
2634                         }
2635                         struct_len = 16;
2636                         break;
2637                 case 1:
2638                         if (strcmp(str2,"B16BBDz") != 0) {
2639                                 return False;
2640                         }
2641                         struct_len = 26;
2642                         break;
2643                 case 2:
2644                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2645                                 return False;
2646                         }
2647                         struct_len = 134;
2648                         break;
2649                 case 3:
2650                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2651                                 return False;
2652                         }
2653                         struct_len = 144;
2654                         break;
2655                 case 20:
2656                         if (strcmp(str2,"DN") != 0) {
2657                                 return False;
2658                         }
2659                         struct_len = 6;
2660                         break;
2661                 case 50:
2662                         if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2663                                 return False;
2664                         }
2665                         struct_len = 42;
2666                         break;
2667                 default:
2668                         return False;
2669         }
2670
2671         *rdata_len = mdrcnt;
2672         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2673         if (!*rdata) {
2674                 return False;
2675         }
2676
2677         p = *rdata;
2678         p2 = p + struct_len;
2679         if (uLevel != 20) {
2680                 srvstr_push(NULL, p,get_local_machine_name(),16, 
2681                         STR_ASCII|STR_UPPER|STR_TERMINATE);
2682         }
2683         p += 16;
2684         if (uLevel > 0) {
2685                 struct srv_info_struct *servers=NULL;
2686                 int i,count;
2687                 pstring comment;
2688                 uint32 servertype= lp_default_server_announce();
2689
2690                 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2691
2692                 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2693                         for (i=0;i<count;i++) {
2694                                 if (strequal(servers[i].name,get_local_machine_name())) {
2695                                         servertype = servers[i].type;
2696                                         push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2697                                 }
2698                         }
2699                 }
2700
2701                 SAFE_FREE(servers);
2702
2703                 SCVAL(p,0,lp_major_announce_version());
2704                 SCVAL(p,1,lp_minor_announce_version());
2705                 SIVAL(p,2,servertype);
2706
2707                 if (mdrcnt == struct_len) {
2708                         SIVAL(p,6,0);
2709                 } else {
2710                         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2711                         standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2712                                               conn->connectpath, conn->gid,
2713                                               get_current_username(),
2714                                               current_user_info.domain,
2715                                               comment, sizeof(comment));
2716                         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2717                         p2 = skip_string(p2,1);
2718                 }
2719         }
2720
2721         if (uLevel > 1) {
2722                 return False;           /* not yet implemented */
2723         }
2724
2725         *rdata_len = PTR_DIFF(p2,*rdata);
2726
2727         *rparam_len = 6;
2728         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2729         if (!*rparam) {
2730                 return False;
2731         }
2732         SSVAL(*rparam,0,NERR_Success);
2733         SSVAL(*rparam,2,0);             /* converter word */
2734         SSVAL(*rparam,4,*rdata_len);
2735
2736         return True;
2737 }
2738
2739 /****************************************************************************
2740  Get info about the server.
2741 ****************************************************************************/
2742
2743 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2744                                 int mdrcnt,int mprcnt,
2745                                 char **rdata,char **rparam,
2746                                 int *rdata_len,int *rparam_len)
2747 {
2748         char *str1 = param+2;
2749         char *str2 = skip_string(str1,1);
2750         char *p = skip_string(str2,1);
2751         char *p2;
2752         int level = SVAL(p,0);
2753
2754         DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2755
2756         *rparam_len = 6;
2757         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2758         if (!*rparam) {
2759                 return False;
2760         }
2761
2762         /* check it's a supported varient */
2763         if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2764                 return False;
2765         }
2766
2767         *rdata_len = mdrcnt + 1024;
2768         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2769         if (!*rdata) {
2770                 return False;
2771         }
2772
2773         SSVAL(*rparam,0,NERR_Success);
2774         SSVAL(*rparam,2,0);             /* converter word */
2775
2776         p = *rdata;
2777         p2 = p + 22;
2778
2779         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2780         pstrcpy(p2,get_local_machine_name());
2781         strupper_m(p2);
2782         p2 = skip_string(p2,1);
2783         p += 4;
2784
2785         SIVAL(p,0,PTR_DIFF(p2,*rdata));
2786         pstrcpy(p2,current_user_info.smb_name);
2787         p2 = skip_string(p2,1);
2788         p += 4;
2789
2790         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2791         pstrcpy(p2,lp_workgroup());
2792         strupper_m(p2);
2793         p2 = skip_string(p2,1);
2794         p += 4;
2795
2796         SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2797         SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2798         p += 2;
2799
2800         SIVAL(p,0,PTR_DIFF(p2,*rdata));
2801         pstrcpy(p2,lp_workgroup());     /* don't know.  login domain?? */
2802         p2 = skip_string(p2,1);
2803         p += 4;
2804
2805         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2806         pstrcpy(p2,"");
2807         p2 = skip_string(p2,1);
2808         p += 4;
2809
2810         *rdata_len = PTR_DIFF(p2,*rdata);
2811
2812         SSVAL(*rparam,4,*rdata_len);
2813
2814         return True;
2815 }
2816
2817 /****************************************************************************
2818   get info about a user
2819
2820     struct user_info_11 {
2821         char                usri11_name[21];  0-20 
2822         char                usri11_pad;       21 
2823         char                *usri11_comment;  22-25 
2824         char            *usri11_usr_comment;  26-29
2825         unsigned short      usri11_priv;      30-31
2826         unsigned long       usri11_auth_flags; 32-35
2827         long                usri11_password_age; 36-39
2828         char                *usri11_homedir; 40-43
2829         char            *usri11_parms; 44-47
2830         long                usri11_last_logon; 48-51
2831         long                usri11_last_logoff; 52-55
2832         unsigned short      usri11_bad_pw_count; 56-57
2833         unsigned short      usri11_num_logons; 58-59
2834         char                *usri11_logon_server; 60-63
2835         unsigned short      usri11_country_code; 64-65
2836         char            *usri11_workstations; 66-69
2837         unsigned long       usri11_max_storage; 70-73
2838         unsigned short      usri11_units_per_week; 74-75
2839         unsigned char       *usri11_logon_hours; 76-79
2840         unsigned short      usri11_code_page; 80-81
2841     };
2842
2843 where:
2844
2845   usri11_name specifies the user name for which information is retireved
2846
2847   usri11_pad aligns the next data structure element to a word boundary
2848
2849   usri11_comment is a null terminated ASCII comment
2850
2851   usri11_user_comment is a null terminated ASCII comment about the user
2852
2853   usri11_priv specifies the level of the privilege assigned to the user.
2854        The possible values are:
2855
2856 Name             Value  Description
2857 USER_PRIV_GUEST  0      Guest privilege
2858 USER_PRIV_USER   1      User privilege
2859 USER_PRV_ADMIN   2      Administrator privilege
2860
2861   usri11_auth_flags specifies the account operator privileges. The
2862        possible values are:
2863
2864 Name            Value   Description
2865 AF_OP_PRINT     0       Print operator
2866
2867
2868 Leach, Naik                                        [Page 28]
2869 \f
2870
2871
2872 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2873
2874
2875 AF_OP_COMM      1       Communications operator
2876 AF_OP_SERVER    2       Server operator
2877 AF_OP_ACCOUNTS  3       Accounts operator
2878
2879
2880   usri11_password_age specifies how many seconds have elapsed since the
2881        password was last changed.
2882
2883   usri11_home_dir points to a null terminated ASCII string that contains
2884        the path name of the user's home directory.
2885
2886   usri11_parms points to a null terminated ASCII string that is set
2887        aside for use by applications.
2888
2889   usri11_last_logon specifies the time when the user last logged on.
2890        This value is stored as the number of seconds elapsed since
2891        00:00:00, January 1, 1970.
2892
2893   usri11_last_logoff specifies the time when the user last logged off.
2894        This value is stored as the number of seconds elapsed since
2895        00:00:00, January 1, 1970. A value of 0 means the last logoff
2896        time is unknown.
2897
2898   usri11_bad_pw_count specifies the number of incorrect passwords
2899        entered since the last successful logon.
2900
2901   usri11_log1_num_logons specifies the number of times this user has
2902        logged on. A value of -1 means the number of logons is unknown.
2903
2904   usri11_logon_server points to a null terminated ASCII string that
2905        contains the name of the server to which logon requests are sent.
2906        A null string indicates logon requests should be sent to the
2907        domain controller.
2908
2909   usri11_country_code specifies the country code for the user's language
2910        of choice.
2911
2912   usri11_workstations points to a null terminated ASCII string that
2913        contains the names of workstations the user may log on from.
2914        There may be up to 8 workstations, with the names separated by
2915        commas. A null strings indicates there are no restrictions.
2916
2917   usri11_max_storage specifies the maximum amount of disk space the user
2918        can occupy. A value of 0xffffffff indicates there are no
2919        restrictions.
2920
2921   usri11_units_per_week specifies the equal number of time units into
2922        which a week is divided. This value must be equal to 168.
2923
2924   usri11_logon_hours points to a 21 byte (168 bits) string that
2925        specifies the time during which the user can log on. Each bit
2926        represents one unique hour in a week. The first bit (bit 0, word
2927        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2928
2929
2930
2931 Leach, Naik                                        [Page 29]
2932 \f
2933
2934
2935 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2936
2937
2938        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2939        are no restrictions.
2940
2941   usri11_code_page specifies the code page for the user's language of
2942        choice
2943
2944 All of the pointers in this data structure need to be treated
2945 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2946 to be ignored. The converter word returned in the parameters section
2947 needs to be subtracted from the lower 16 bits to calculate an offset
2948 into the return buffer where this ASCII string resides.
2949
2950 There is no auxiliary data in the response.
2951
2952   ****************************************************************************/
2953
2954 #define usri11_name           0 
2955 #define usri11_pad            21
2956 #define usri11_comment        22
2957 #define usri11_usr_comment    26
2958 #define usri11_full_name      30
2959 #define usri11_priv           34
2960 #define usri11_auth_flags     36
2961 #define usri11_password_age   40
2962 #define usri11_homedir        44
2963 #define usri11_parms          48
2964 #define usri11_last_logon     52
2965 #define usri11_last_logoff    56
2966 #define usri11_bad_pw_count   60
2967 #define usri11_num_logons     62
2968 #define usri11_logon_server   64
2969 #define usri11_country_code   68
2970 #define usri11_workstations   70
2971 #define usri11_max_storage    74
2972 #define usri11_units_per_week 78
2973 #define usri11_logon_hours    80
2974 #define usri11_code_page      84
2975 #define usri11_end            86
2976
2977 #define USER_PRIV_GUEST 0
2978 #define USER_PRIV_USER 1
2979 #define USER_PRIV_ADMIN 2
2980
2981 #define AF_OP_PRINT     0 
2982 #define AF_OP_COMM      1
2983 #define AF_OP_SERVER    2
2984 #define AF_OP_ACCOUNTS  3
2985
2986
2987 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2988                                 int mdrcnt,int mprcnt,
2989                                 char **rdata,char **rparam,
2990                                 int *rdata_len,int *rparam_len)
2991 {
2992         char *str1 = param+2;
2993         char *str2 = skip_string(str1,1);
2994         char *UserName = skip_string(str2,1);
2995         char *p = skip_string(UserName,1);
2996         int uLevel = SVAL(p,0);
2997         char *p2;
2998         const char *level_string;
2999
3000         /* get NIS home of a previously validated user - simeon */
3001         /* With share level security vuid will always be zero.
3002            Don't depend on vuser being non-null !!. JRA */
3003         user_struct *vuser = get_valid_user_struct(vuid);
3004         if(vuser != NULL) {
3005                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
3006                         vuser->user.unix_name));
3007         }
3008
3009         *rparam_len = 6;
3010         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3011         if (!*rparam) {
3012                 return False;
3013         }
3014
3015         DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3016   
3017         /* check it's a supported variant */
3018         if (strcmp(str1,"zWrLh") != 0) {
3019                 return False;
3020         }
3021         switch( uLevel ) {
3022                 case 0: level_string = "B21"; break;
3023                 case 1: level_string = "B21BB16DWzzWz"; break;
3024                 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3025                 case 10: level_string = "B21Bzzz"; break;
3026                 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3027                 default: return False;
3028         }
3029
3030         if (strcmp(level_string,str2) != 0) {
3031                 return False;
3032         }
3033
3034         *rdata_len = mdrcnt + 1024;
3035         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
3036         if (!*rdata) {
3037                 return False;
3038         }
3039
3040         SSVAL(*rparam,0,NERR_Success);
3041         SSVAL(*rparam,2,0);             /* converter word */
3042
3043         p = *rdata;
3044         p2 = p + usri11_end;
3045
3046         memset(p,0,21); 
3047         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3048
3049         if (uLevel > 0) {
3050                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3051                 *p2 = 0;
3052         }
3053
3054         if (uLevel >= 10) {
3055                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3056                 pstrcpy(p2,"Comment");
3057                 p2 = skip_string(p2,1);
3058
3059                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3060                 pstrcpy(p2,"UserComment");
3061                 p2 = skip_string(p2,1);
3062
3063                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3064                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3065                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3066                 p2 = skip_string(p2,1);
3067         }
3068
3069         if (uLevel == 11) {
3070                 /* modelled after NTAS 3.51 reply */
3071                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
3072                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
3073                 SIVALS(p,usri11_password_age,-1);               /* password age */
3074                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3075                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3076                 p2 = skip_string(p2,1);
3077                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3078                 pstrcpy(p2,"");
3079                 p2 = skip_string(p2,1);
3080                 SIVAL(p,usri11_last_logon,0);           /* last logon */
3081                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
3082                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
3083                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
3084                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3085                 pstrcpy(p2,"\\\\*");
3086                 p2 = skip_string(p2,1);
3087                 SSVAL(p,usri11_country_code,0);         /* country code */
3088
3089                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3090                 pstrcpy(p2,"");
3091                 p2 = skip_string(p2,1);
3092
3093                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
3094                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
3095                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3096
3097                 /* a simple way to get logon hours at all times. */
3098                 memset(p2,0xff,21);
3099                 SCVAL(p2,21,0);           /* fix zero termination */
3100                 p2 = skip_string(p2,1);
3101
3102                 SSVAL(p,usri11_code_page,0);            /* code page */
3103         }
3104
3105         if (uLevel == 1 || uLevel == 2) {
3106                 memset(p+22,' ',16);    /* password */
3107                 SIVALS(p,38,-1);                /* password age */
3108                 SSVAL(p,42,
3109                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3110                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3111                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3112                 p2 = skip_string(p2,1);
3113                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3114                 *p2++ = 0;
3115                 SSVAL(p,52,0);          /* flags */
3116                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
3117                 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3118                 p2 = skip_string(p2,1);
3119                 if (uLevel == 2) {
3120                         SIVAL(p,60,0);          /* auth_flags */
3121                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3122                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3123                         p2 = skip_string(p2,1);
3124                         SIVAL(p,68,0);          /* urs_comment */
3125                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3126                         pstrcpy(p2,"");
3127                         p2 = skip_string(p2,1);
3128                         SIVAL(p,76,0);          /* workstations */
3129                         SIVAL(p,80,0);          /* last_logon */
3130                         SIVAL(p,84,0);          /* last_logoff */
3131                         SIVALS(p,88,-1);                /* acct_expires */
3132                         SIVALS(p,92,-1);                /* max_storage */
3133                         SSVAL(p,96,168);        /* units_per_week */
3134                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3135                         memset(p2,-1,21);
3136                         p2 += 21;
3137                         SSVALS(p,102,-1);       /* bad_pw_count */
3138                         SSVALS(p,104,-1);       /* num_logons */
3139                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3140                         {
3141                                 pstring tmp;
3142                                 pstrcpy(tmp, "\\\\%L");
3143                                 standard_sub_basic("", "", tmp, sizeof(tmp));
3144                                 pstrcpy(p2, tmp);
3145                         }
3146                         p2 = skip_string(p2,1);
3147                         SSVAL(p,110,49);        /* country_code */
3148                         SSVAL(p,112,860);       /* code page */
3149                 }
3150         }
3151
3152         *rdata_len = PTR_DIFF(p2,*rdata);
3153
3154         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
3155
3156         return(True);
3157 }
3158
3159 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
3160                                 int mdrcnt,int mprcnt,
3161                                 char **rdata,char **rparam,
3162                                 int *rdata_len,int *rparam_len)
3163 {
3164         char *str1 = param+2;
3165         char *str2 = skip_string(str1,1);
3166         char *p = skip_string(str2,1);
3167         int uLevel;
3168         struct pack_desc desc;
3169         char* name;
3170                 /* With share level security vuid will always be zero.
3171                    Don't depend on vuser being non-null !!. JRA */
3172         user_struct *vuser = get_valid_user_struct(vuid);
3173
3174         if(vuser != NULL) {
3175                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
3176                         vuser->user.unix_name));
3177         }
3178
3179         uLevel = SVAL(p,0);
3180         name = p + 2;
3181
3182         memset((char *)&desc,'\0',sizeof(desc));
3183
3184         DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3185
3186         /* check it's a supported varient */
3187         if (strcmp(str1,"OOWb54WrLh") != 0) {
3188                 return False;
3189         }
3190         if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3191                 return False;
3192         }
3193         if (mdrcnt > 0) {
3194                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3195                 if (!*rdata) {
3196                         return False;
3197                 }
3198         }
3199
3200         desc.base = *rdata;
3201         desc.buflen = mdrcnt;
3202         desc.subformat = NULL;
3203         desc.format = str2;
3204   
3205         if (init_package(&desc,1,0)) {
3206                 PACKI(&desc,"W",0);             /* code */
3207                 PACKS(&desc,"B21",name);        /* eff. name */
3208                 PACKS(&desc,"B","");            /* pad */
3209                 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3210                 PACKI(&desc,"D",0);             /* auth flags XXX */
3211                 PACKI(&desc,"W",0);             /* num logons */
3212                 PACKI(&desc,"W",0);             /* bad pw count */
3213                 PACKI(&desc,"D",0);             /* last logon */
3214                 PACKI(&desc,"D",-1);            /* last logoff */
3215                 PACKI(&desc,"D",-1);            /* logoff time */
3216                 PACKI(&desc,"D",-1);            /* kickoff time */
3217                 PACKI(&desc,"D",0);             /* password age */
3218                 PACKI(&desc,"D",0);             /* password can change */
3219                 PACKI(&desc,"D",-1);            /* password must change */
3220
3221                 {
3222                         fstring mypath;
3223                         fstrcpy(mypath,"\\\\");
3224                         fstrcat(mypath,get_local_machine_name());
3225                         strupper_m(mypath);
3226                         PACKS(&desc,"z",mypath); /* computer */
3227                 }
3228
3229                 PACKS(&desc,"z",lp_workgroup());/* domain */
3230                 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3231                 PACKI(&desc,"D",0x00000000);            /* reserved */
3232         }
3233
3234         *rdata_len = desc.usedlen;
3235         *rparam_len = 6;
3236         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3237         if (!*rparam) {
3238                 return False;
3239         }
3240         SSVALS(*rparam,0,desc.errcode);
3241         SSVAL(*rparam,2,0);
3242         SSVAL(*rparam,4,desc.neededlen);
3243
3244         DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3245
3246         return True;
3247 }
3248
3249 /****************************************************************************
3250  api_WAccessGetUserPerms
3251 ****************************************************************************/
3252
3253 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
3254                                     int mdrcnt,int mprcnt,
3255                                     char **rdata,char **rparam,
3256                                     int *rdata_len,int *rparam_len)
3257 {
3258         char *str1 = param+2;
3259         char *str2 = skip_string(str1,1);
3260         char *user = skip_string(str2,1);
3261         char *resource = skip_string(user,1);
3262
3263         DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3264
3265         /* check it's a supported varient */
3266         if (strcmp(str1,"zzh") != 0) {
3267                 return False;
3268         }
3269         if (strcmp(str2,"") != 0) {
3270                 return False;
3271         }
3272
3273         *rparam_len = 6;
3274         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3275         if (!*rparam) {
3276                 return False;
3277         }
3278         SSVALS(*rparam,0,0);            /* errorcode */
3279         SSVAL(*rparam,2,0);             /* converter word */
3280         SSVAL(*rparam,4,0x7f);  /* permission flags */
3281
3282         return True;
3283 }
3284
3285 /****************************************************************************
3286   api_WPrintJobEnumerate
3287   ****************************************************************************/
3288
3289 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
3290                                  int mdrcnt,int mprcnt,
3291                                  char **rdata,char **rparam,
3292                                  int *rdata_len,int *rparam_len)
3293 {
3294         char *str1 = param+2;
3295         char *str2 = skip_string(str1,1);
3296         char *p = skip_string(str2,1);
3297         int uLevel;
3298         int count;
3299         int i;
3300         int snum;
3301         fstring sharename;
3302         uint32 jobid;
3303         struct pack_desc desc;
3304         print_queue_struct *queue=NULL;
3305         print_status_struct status;
3306         char *tmpdata=NULL;
3307
3308         uLevel = SVAL(p,2);
3309
3310         memset((char *)&desc,'\0',sizeof(desc));
3311         memset((char *)&status,'\0',sizeof(status));
3312
3313         DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3314
3315         /* check it's a supported varient */
3316         if (strcmp(str1,"WWrLh") != 0) {
3317                 return False;
3318         }
3319         if (!check_printjob_info(&desc,uLevel,str2)) {
3320                 return False;
3321         }
3322
3323         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3324                 return False;
3325         }
3326
3327         snum = lp_servicenumber( sharename);
3328         if (snum < 0 || !VALID_SNUM(snum)) {
3329                 return(False);
3330         }
3331
3332         count = print_queue_status(snum,&queue,&status);
3333         for (i = 0; i < count; i++) {
3334                 if (queue[i].job == jobid) {
3335                         break;
3336                 }
3337         }
3338
3339         if (mdrcnt > 0) {
3340                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3341                 if (!*rdata) {
3342                         return False;
3343                 }
3344                 desc.base = *rdata;
3345                 desc.buflen = mdrcnt;
3346         } else {
3347                 /*
3348                  * Don't return data but need to get correct length
3349                  *  init_package will return wrong size if buflen=0
3350                  */
3351                 desc.buflen = getlen(desc.format);
3352                 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3353         }
3354
3355         if (init_package(&desc,1,0)) {
3356                 if (i < count) {
3357                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3358                         *rdata_len = desc.usedlen;
3359                 } else {
3360                         desc.errcode = NERR_JobNotFound;
3361                         *rdata_len = 0;
3362                 }
3363         }
3364
3365         *rparam_len = 6;
3366         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3367         if (!*rparam) {
3368                 return False;
3369         }
3370         SSVALS(*rparam,0,desc.errcode);
3371         SSVAL(*rparam,2,0);
3372         SSVAL(*rparam,4,desc.neededlen);
3373
3374         SAFE_FREE(queue);
3375         SAFE_FREE(tmpdata);
3376
3377         DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3378
3379         return True;
3380 }
3381
3382 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
3383                                    int mdrcnt,int mprcnt,
3384                                    char **rdata,char **rparam,
3385                                    int *rdata_len,int *rparam_len)
3386 {
3387         char *str1 = param+2;
3388         char *str2 = skip_string(str1,1);
3389         char *p = skip_string(str2,1);
3390         char* name = p;
3391         int uLevel;
3392         int count;
3393         int i, succnt=0;
3394         int snum;
3395         struct pack_desc desc;
3396         print_queue_struct *queue=NULL;
3397         print_status_struct status;
3398
3399         memset((char *)&desc,'\0',sizeof(desc));
3400         memset((char *)&status,'\0',sizeof(status));
3401
3402         p = skip_string(p,1);
3403         uLevel = SVAL(p,0);
3404
3405         DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3406
3407         /* check it's a supported variant */
3408         if (strcmp(str1,"zWrLeh") != 0) {
3409                 return False;
3410         }
3411     
3412         if (uLevel > 2) {
3413                 return False;   /* defined only for uLevel 0,1,2 */
3414         }
3415     
3416         if (!check_printjob_info(&desc,uLevel,str2)) { 
3417                 return False;
3418         }
3419
3420         snum = find_service(name);
3421         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3422                 return False;
3423         }
3424
3425         count = print_queue_status(snum,&queue,&status);
3426         if (mdrcnt > 0) {
3427                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3428                 if (!*rdata) {
3429                         return False;
3430                 }
3431         }
3432         desc.base = *rdata;
3433         desc.buflen = mdrcnt;
3434
3435         if (init_package(&desc,count,0)) {
3436                 succnt = 0;
3437                 for (i = 0; i < count; i++) {
3438                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3439                         if (desc.errcode == NERR_Success) {
3440                                 succnt = i+1;
3441                         }
3442                 }
3443         }
3444
3445         *rdata_len = desc.usedlen;
3446
3447         *rparam_len = 8;
3448         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3449         if (!*rparam) {
3450                 return False;
3451         }
3452         SSVALS(*rparam,0,desc.errcode);
3453         SSVAL(*rparam,2,0);
3454         SSVAL(*rparam,4,succnt);
3455         SSVAL(*rparam,6,count);
3456
3457         SAFE_FREE(queue);
3458
3459         DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3460
3461         return True;
3462 }
3463
3464 static int check_printdest_info(struct pack_desc* desc,
3465                                 int uLevel, char* id)
3466 {
3467         desc->subformat = NULL;
3468         switch( uLevel ) {
3469                 case 0:
3470                         desc->format = "B9";
3471                         break;
3472                 case 1:
3473                         desc->format = "B9B21WWzW";
3474                         break;
3475                 case 2:
3476                         desc->format = "z";
3477                         break;
3478                 case 3:
3479                         desc->format = "zzzWWzzzWW";
3480                         break;
3481                 default:
3482                         return False;
3483         }
3484         if (strcmp(desc->format,id) != 0) {
3485                 return False;
3486         }
3487         return True;
3488 }
3489
3490 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3491                                 struct pack_desc* desc)
3492 {
3493         char buf[100];
3494
3495         strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3496         buf[sizeof(buf)-1] = 0;
3497         strupper_m(buf);
3498
3499         if (uLevel <= 1) {
3500                 PACKS(desc,"B9",buf);   /* szName */
3501                 if (uLevel == 1) {
3502                         PACKS(desc,"B21","");   /* szUserName */
3503                         PACKI(desc,"W",0);              /* uJobId */
3504                         PACKI(desc,"W",0);              /* fsStatus */
3505                         PACKS(desc,"z","");     /* pszStatus */
3506                         PACKI(desc,"W",0);              /* time */
3507                 }
3508         }
3509
3510         if (uLevel == 2 || uLevel == 3) {
3511                 PACKS(desc,"z",buf);            /* pszPrinterName */
3512                 if (uLevel == 3) {
3513                         PACKS(desc,"z","");     /* pszUserName */
3514                         PACKS(desc,"z","");     /* pszLogAddr */
3515                         PACKI(desc,"W",0);              /* uJobId */
3516                         PACKI(desc,"W",0);              /* fsStatus */
3517                         PACKS(desc,"z","");     /* pszStatus */
3518                         PACKS(desc,"z","");     /* pszComment */
3519                         PACKS(desc,"z","NULL"); /* pszDrivers */
3520                         PACKI(desc,"W",0);              /* time */
3521                         PACKI(desc,"W",0);              /* pad1 */
3522                 }
3523         }
3524 }
3525
3526 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
3527                                   int mdrcnt,int mprcnt,
3528                                   char **rdata,char **rparam,
3529                                   int *rdata_len,int *rparam_len)
3530 {
3531         char *str1 = param+2;
3532         char *str2 = skip_string(str1,1);
3533         char *p = skip_string(str2,1);
3534         char* PrinterName = p;
3535         int uLevel;
3536         struct pack_desc desc;
3537         int snum;
3538         char *tmpdata=NULL;
3539
3540         memset((char *)&desc,'\0',sizeof(desc));
3541
3542         p = skip_string(p,1);
3543         uLevel = SVAL(p,0);
3544
3545         DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3546
3547         /* check it's a supported varient */
3548         if (strcmp(str1,"zWrLh") != 0) {
3549                 return False;
3550         }
3551         if (!check_printdest_info(&desc,uLevel,str2)) {
3552                 return False;
3553         }
3554
3555         snum = find_service(PrinterName);
3556         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3557                 *rdata_len = 0;
3558                 desc.errcode = NERR_DestNotFound;
3559                 desc.neededlen = 0;
3560         } else {
3561                 if (mdrcnt > 0) {
3562                         *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3563                         if (!*rdata) {
3564                                 return False;
3565                         }
3566                         desc.base = *rdata;
3567                         desc.buflen = mdrcnt;
3568                 } else {
3569                         /*
3570                          * Don't return data but need to get correct length
3571                          * init_package will return wrong size if buflen=0
3572                          */
3573                         desc.buflen = getlen(desc.format);
3574                         desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3575                 }
3576                 if (init_package(&desc,1,0)) {
3577                         fill_printdest_info(conn,snum,uLevel,&desc);
3578                 }
3579                 *rdata_len = desc.usedlen;
3580         }
3581
3582         *rparam_len = 6;
3583         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3584         if (!*rparam) {
3585                 return False;
3586         }
3587         SSVALS(*rparam,0,desc.errcode);
3588         SSVAL(*rparam,2,0);
3589         SSVAL(*rparam,4,desc.neededlen);
3590
3591         DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3592         SAFE_FREE(tmpdata);
3593
3594         return True;
3595 }
3596
3597 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3598                                int mdrcnt,int mprcnt,
3599                                char **rdata,char **rparam,
3600                                int *rdata_len,int *rparam_len)
3601 {
3602         char *str1 = param+2;
3603         char *str2 = skip_string(str1,1);
3604         char *p = skip_string(str2,1);
3605         int uLevel;
3606         int queuecnt;
3607         int i, n, succnt=0;
3608         struct pack_desc desc;
3609         int services = lp_numservices();
3610
3611         memset((char *)&desc,'\0',sizeof(desc));
3612
3613         uLevel = SVAL(p,0);
3614
3615         DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3616
3617         /* check it's a supported varient */
3618         if (strcmp(str1,"WrLeh") != 0) {
3619                 return False;
3620         }
3621         if (!check_printdest_info(&desc,uLevel,str2)) {
3622                 return False;
3623         }
3624
3625         queuecnt = 0;
3626         for (i = 0; i < services; i++) {
3627                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3628                         queuecnt++;
3629                 }
3630         }
3631
3632         if (mdrcnt > 0) {
3633                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3634                 if (!*rdata) {
3635                         return False;
3636                 }
3637         }
3638
3639         desc.base = *rdata;
3640         desc.buflen = mdrcnt;
3641         if (init_package(&desc,queuecnt,0)) {    
3642                 succnt = 0;
3643                 n = 0;
3644                 for (i = 0; i < services; i++) {
3645                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3646                                 fill_printdest_info(conn,i,uLevel,&desc);
3647                                 n++;
3648                                 if (desc.errcode == NERR_Success) {
3649                                         succnt = n;
3650                                 }
3651                         }
3652                 }
3653         }
3654
3655         *rdata_len = desc.usedlen;
3656
3657         *rparam_len = 8;
3658         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3659         if (!*rparam) {
3660                 return False;
3661         }
3662         SSVALS(*rparam,0,desc.errcode);
3663         SSVAL(*rparam,2,0);
3664         SSVAL(*rparam,4,succnt);
3665         SSVAL(*rparam,6,queuecnt);
3666
3667         DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3668
3669         return True;
3670 }
3671
3672 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3673                                  int mdrcnt,int mprcnt,
3674                                  char **rdata,char **rparam,
3675                                  int *rdata_len,int *rparam_len)
3676 {
3677         char *str1 = param+2;
3678         char *str2 = skip_string(str1,1);
3679         char *p = skip_string(str2,1);
3680         int uLevel;
3681         int succnt;
3682         struct pack_desc desc;
3683
3684         memset((char *)&desc,'\0',sizeof(desc));
3685
3686         uLevel = SVAL(p,0);
3687
3688         DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3689
3690         /* check it's a supported varient */
3691         if (strcmp(str1,"WrLeh") != 0) {
3692                 return False;
3693         }
3694         if (uLevel != 0 || strcmp(str2,"B41") != 0) {
3695                 return False;
3696         }
3697
3698         if (mdrcnt > 0) {
3699                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3700                 if (!*rdata) {
3701                         return False;
3702                 }
3703         }
3704         desc.base = *rdata;
3705         desc.buflen = mdrcnt;
3706         if (init_package(&desc,1,0)) {
3707                 PACKS(&desc,"B41","NULL");
3708         }
3709
3710         succnt = (desc.errcode == NERR_Success ? 1 : 0);
3711
3712         *rdata_len = desc.usedlen;
3713
3714         *rparam_len = 8;
3715         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3716         if (!*rparam) {
3717                 return False;
3718         }
3719         SSVALS(*rparam,0,desc.errcode);
3720         SSVAL(*rparam,2,0);
3721         SSVAL(*rparam,4,succnt);
3722         SSVAL(*rparam,6,1);
3723
3724         DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3725
3726         return True;
3727 }
3728
3729 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3730                                 int mdrcnt,int mprcnt,
3731                                 char **rdata,char **rparam,
3732                                 int *rdata_len,int *rparam_len)
3733 {
3734         char *str1 = param+2;
3735         char *str2 = skip_string(str1,1);
3736         char *p = skip_string(str2,1);
3737         int uLevel;
3738         int succnt;
3739         struct pack_desc desc;
3740
3741         memset((char *)&desc,'\0',sizeof(desc));
3742
3743         uLevel = SVAL(p,0);
3744
3745         DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3746
3747         /* check it's a supported varient */
3748         if (strcmp(str1,"WrLeh") != 0) {
3749                 return False;
3750         }
3751         if (uLevel != 0 || strcmp(str2,"B13") != 0) {
3752                 return False;
3753         }
3754
3755         if (mdrcnt > 0) {
3756                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3757                 if (!*rdata) {
3758                         return False;
3759                 }
3760         }
3761         desc.base = *rdata;
3762         desc.buflen = mdrcnt;
3763         desc.format = str2;
3764         if (init_package(&desc,1,0)) {
3765                 PACKS(&desc,"B13","lpd");
3766         }
3767
3768         succnt = (desc.errcode == NERR_Success ? 1 : 0);
3769
3770         *rdata_len = desc.usedlen;
3771
3772         *rparam_len = 8;
3773         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3774         if (!*rparam) {
3775                 return False;
3776         }
3777         SSVALS(*rparam,0,desc.errcode);
3778         SSVAL(*rparam,2,0);
3779         SSVAL(*rparam,4,succnt);
3780         SSVAL(*rparam,6,1);
3781
3782         DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3783
3784         return True;
3785 }
3786
3787 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3788                                int mdrcnt,int mprcnt,
3789                                char **rdata,char **rparam,
3790                                int *rdata_len,int *rparam_len)
3791 {
3792         char *str1 = param+2;
3793         char *str2 = skip_string(str1,1);
3794         char *p = skip_string(str2,1);
3795         int uLevel;
3796         int succnt;
3797         struct pack_desc desc;
3798
3799         memset((char *)&desc,'\0',sizeof(desc));
3800
3801         uLevel = SVAL(p,0);
3802
3803         DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3804
3805         /* check it's a supported varient */
3806         if (strcmp(str1,"WrLeh") != 0) {
3807                 return False;
3808         }
3809         if (uLevel != 0 || strcmp(str2,"B9") != 0) {
3810                 return False;
3811         }
3812
3813         if (mdrcnt > 0) {
3814                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3815                 if (!*rdata) {
3816                         return False;
3817                 }
3818         }
3819         memset((char *)&desc,'\0',sizeof(desc));
3820         desc.base = *rdata;
3821         desc.buflen = mdrcnt;
3822         desc.format = str2;
3823         if (init_package(&desc,1,0)) {
3824                 PACKS(&desc,"B13","lp0");
3825         }
3826
3827         succnt = (desc.errcode == NERR_Success ? 1 : 0);
3828
3829         *rdata_len = desc.usedlen;
3830
3831         *rparam_len = 8;
3832         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3833         if (!*rparam) {
3834                 return False;
3835         }
3836         SSVALS(*rparam,0,desc.errcode);
3837         SSVAL(*rparam,2,0);
3838         SSVAL(*rparam,4,succnt);
3839         SSVAL(*rparam,6,1);
3840
3841         DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3842
3843         return True;
3844 }
3845
3846
3847 /****************************************************************************
3848  List open sessions
3849  ****************************************************************************/
3850 static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param, char *data,
3851                                int mdrcnt,int mprcnt,
3852                                char **rdata,char **rparam,
3853                                int *rdata_len,int *rparam_len)
3854
3855 {
3856         char *str1 = param+2;
3857         char *str2 = skip_string(str1,1);
3858         char *p = skip_string(str2,1);
3859         int uLevel;
3860         struct pack_desc desc;
3861         struct sessionid *session_list;
3862         int i, num_sessions;
3863
3864         memset((char *)&desc,'\0',sizeof(desc));
3865
3866         uLevel = SVAL(p,0);
3867
3868         DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
3869         DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
3870         DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
3871
3872         /* check it's a supported varient */
3873         if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
3874                 return False;
3875         }
3876         if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
3877                 return False;
3878         }
3879
3880         num_sessions = list_sessions(&session_list);
3881
3882         if (mdrcnt > 0) {
3883                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3884                 if (!*rdata) {
3885                         return False;
3886                 }
3887         }
3888         memset((char *)&desc,'\0',sizeof(desc));
3889         desc.base = *rdata;
3890         desc.buflen = mdrcnt;
3891         desc.format = str2;
3892         if (!init_package(&desc,num_sessions,0)) {
3893                 return False;
3894         }
3895
3896         for(i=0; i<num_sessions; i++) {
3897                 PACKS(&desc, "z", session_list[i].remote_machine);
3898                 PACKS(&desc, "z", session_list[i].username);
3899                 PACKI(&desc, "W", 1); /* num conns */
3900                 PACKI(&desc, "W", 0); /* num opens */
3901                 PACKI(&desc, "W", 1); /* num users */
3902                 PACKI(&desc, "D", 0); /* session time */
3903                 PACKI(&desc, "D", 0); /* idle time */
3904                 PACKI(&desc, "D", 0); /* flags */
3905                 PACKS(&desc, "z", "Unknown Client"); /* client type string */
3906         }
3907
3908         *rdata_len = desc.usedlen;
3909
3910         *rparam_len = 8;
3911         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3912         if (!*rparam) {
3913                 return False;
3914         }
3915         SSVALS(*rparam,0,desc.errcode);
3916         SSVAL(*rparam,2,0); /* converter */
3917         SSVAL(*rparam,4,num_sessions); /* count */
3918
3919         DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
3920
3921         return True;
3922 }
3923
3924
3925 /****************************************************************************
3926  The buffer was too small.
3927  ****************************************************************************/
3928
3929 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
3930                          int mdrcnt, int mprcnt,
3931                          char **rdata, char **rparam,
3932                          int *rdata_len, int *rparam_len)
3933 {
3934         *rparam_len = MIN(*rparam_len,mprcnt);
3935         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3936         if (!*rparam) {
3937                 return False;
3938         }
3939
3940         *rdata_len = 0;
3941
3942         SSVAL(*rparam,0,NERR_BufTooSmall);
3943
3944         DEBUG(3,("Supplied buffer too small in API command\n"));
3945
3946         return True;
3947 }
3948
3949 /****************************************************************************
3950  The request is not supported.
3951  ****************************************************************************/
3952
3953 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid, char *param, char *data,
3954                             int mdrcnt, int mprcnt,
3955                             char **rdata, char **rparam,
3956                             int *rdata_len, int *rparam_len)
3957 {
3958         *rparam_len = 4;
3959         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3960         if (!*rparam) {
3961                 return False;
3962         }
3963
3964         *rdata_len = 0;
3965
3966         SSVAL(*rparam,0,NERR_notsupported);
3967         SSVAL(*rparam,2,0);             /* converter word */
3968
3969         DEBUG(3,("Unsupported API command\n"));
3970
3971         return True;
3972 }
3973
3974 static const struct {
3975         const char *name;
3976         int id;
3977         BOOL (*fn)(connection_struct *,uint16,char *,char *,
3978                         int,int,char **,char **,int *,int *);
3979         BOOL auth_user;         /* Deny anonymous access? */
3980 } api_commands[] = {
3981         {"RNetShareEnum",       RAP_WshareEnum,         api_RNetShareEnum, True},
3982         {"RNetShareGetInfo",    RAP_WshareGetInfo,      api_RNetShareGetInfo},
3983         {"RNetShareAdd",        RAP_WshareAdd,          api_RNetShareAdd},
3984         {"RNetSessionEnum",     RAP_WsessionEnum,       api_RNetSessionEnum, True},
3985         {"RNetServerGetInfo",   RAP_WserverGetInfo,     api_RNetServerGetInfo},
3986         {"RNetGroupEnum",       RAP_WGroupEnum,         api_RNetGroupEnum, True},
3987         {"RNetGroupGetUsers", RAP_WGroupGetUsers,       api_RNetGroupGetUsers, True},
3988         {"RNetUserEnum",        RAP_WUserEnum,          api_RNetUserEnum, True},
3989         {"RNetUserGetInfo",     RAP_WUserGetInfo,       api_RNetUserGetInfo},
3990         {"NetUserGetGroups",    RAP_WUserGetGroups,     api_NetUserGetGroups},
3991         {"NetWkstaGetInfo",     RAP_WWkstaGetInfo,      api_NetWkstaGetInfo},
3992         {"DosPrintQEnum",       RAP_WPrintQEnum,        api_DosPrintQEnum, True},
3993         {"DosPrintQGetInfo",    RAP_WPrintQGetInfo,     api_DosPrintQGetInfo},
3994         {"WPrintQueuePause",  RAP_WPrintQPause, api_WPrintQueueCtrl},
3995         {"WPrintQueueResume", RAP_WPrintQContinue,      api_WPrintQueueCtrl},
3996         {"WPrintJobEnumerate",RAP_WPrintJobEnum,        api_WPrintJobEnumerate},
3997         {"WPrintJobGetInfo",    RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo},
3998         {"RDosPrintJobDel",     RAP_WPrintJobDel,       api_RDosPrintJobDel},
3999         {"RDosPrintJobPause",   RAP_WPrintJobPause,     api_RDosPrintJobDel},
4000         {"RDosPrintJobResume",RAP_WPrintJobContinue,    api_RDosPrintJobDel},
4001         {"WPrintDestEnum",      RAP_WPrintDestEnum,     api_WPrintDestEnum},
4002         {"WPrintDestGetInfo",   RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo},
4003         {"NetRemoteTOD",        RAP_NetRemoteTOD,       api_NetRemoteTOD},
4004         {"WPrintQueuePurge",    RAP_WPrintQPurge,       api_WPrintQueueCtrl},
4005         {"NetServerEnum",       RAP_NetServerEnum2,     api_RNetServerEnum}, /* anon OK */
4006         {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4007         {"SetUserPassword",     RAP_WUserPasswordSet2,  api_SetUserPassword},
4008         {"WWkstaUserLogon",     RAP_WWkstaUserLogon,    api_WWkstaUserLogon},
4009         {"PrintJobInfo",        RAP_WPrintJobSetInfo,   api_PrintJobInfo},
4010         {"WPrintDriverEnum",    RAP_WPrintDriverEnum,   api_WPrintDriverEnum},
4011         {"WPrintQProcEnum",     RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4012         {"WPrintPortEnum",      RAP_WPrintPortEnum,     api_WPrintPortEnum},
4013         {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4014         {NULL,          -1,     api_Unsupported}
4015         /*  The following RAP calls are not implemented by Samba:
4016
4017         RAP_WFileEnum2 - anon not OK 
4018         */
4019 };
4020
4021
4022 /****************************************************************************
4023  Handle remote api calls
4024  ****************************************************************************/
4025
4026 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
4027                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
4028 {
4029         int api_command;
4030         char *rdata = NULL;
4031         char *rparam = NULL;
4032         int rdata_len = 0;
4033         int rparam_len = 0;
4034         BOOL reply=False;
4035         int i;
4036
4037         if (!params) {
4038                 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4039                 return 0;
4040         }
4041
4042         api_command = SVAL(params,0);
4043
4044         DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4045                 api_command,
4046                 params+2,
4047                 skip_string(params+2,1),
4048                 tdscnt,tpscnt,mdrcnt,mprcnt));
4049
4050         for (i=0;api_commands[i].name;i++) {
4051                 if (api_commands[i].id == api_command && api_commands[i].fn) {
4052                         DEBUG(3,("Doing %s\n",api_commands[i].name));
4053                         break;
4054                 }
4055         }
4056
4057         /* Check whether this api call can be done anonymously */
4058
4059         if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4060                 user_struct *user = get_valid_user_struct(vuid);
4061
4062                 if (!user || user->guest) {
4063                         return ERROR_NT(NT_STATUS_ACCESS_DENIED);
4064                 }
4065         }
4066
4067         rdata = (char *)SMB_MALLOC(1024);
4068         if (rdata) {
4069                 memset(rdata,'\0',1024);
4070         }
4071
4072         rparam = (char *)SMB_MALLOC(1024);
4073         if (rparam) {
4074                 memset(rparam,'\0',1024);
4075         }
4076
4077         if(!rdata || !rparam) {
4078                 DEBUG(0,("api_reply: malloc fail !\n"));
4079                 SAFE_FREE(rdata);
4080                 SAFE_FREE(rparam);
4081                 return -1;
4082         }
4083
4084         reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
4085                                 &rdata,&rparam,&rdata_len,&rparam_len);
4086
4087
4088         if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4089                 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4090                                         &rdata,&rparam,&rdata_len,&rparam_len);
4091         }
4092
4093         /* if we get False back then it's actually unsupported */
4094         if (!reply) {
4095                 reply = api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
4096                         &rdata,&rparam,&rdata_len,&rparam_len);
4097         }
4098
4099         /* If api_Unsupported returns false we can't return anything. */
4100         if (reply) {
4101                 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
4102         }
4103
4104         SAFE_FREE(rdata);
4105         SAFE_FREE(rparam);
4106         return -1;
4107 }