r16945: Sync trunk -> 3.0 for 3.0.24 code. Still need
[vlendec/samba-autobuild/.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                 if (buflen) {
1199                         *buflen = struct_len;
1200                 }
1201                 if (stringspace) {
1202                         *stringspace = len;
1203                 }
1204                 return struct_len + len;
1205         }
1206   
1207         len = struct_len;
1208         p = *buf;
1209         if (*buflen < struct_len) {
1210                 return -1;
1211         }
1212         if (stringbuf) {
1213                 p2 = *stringbuf;
1214                 l2 = *stringspace;
1215         } else {
1216                 p2 = p + struct_len;
1217                 l2 = *buflen - struct_len;
1218         }
1219         if (!baseaddr) {
1220                 baseaddr = p;
1221         }
1222   
1223         switch (uLevel) {
1224                 case 0:
1225                         push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1226                         break;
1227
1228                 case 1:
1229                         push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1230                         SIVAL(p,18,service->type);
1231                         SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1232                         len += CopyAndAdvance(&p2,service->comment,&l2);
1233                         break;
1234         }
1235
1236         if (stringbuf) {
1237                 *buf = p + struct_len;
1238                 *buflen -= struct_len;
1239                 *stringbuf = p2;
1240                 *stringspace = l2;
1241         } else {
1242                 *buf = p2;
1243                 *buflen -= len;
1244         }
1245         return len;
1246 }
1247
1248
1249 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1250 {
1251         return(strcmp(s1->name,s2->name));
1252 }
1253
1254 /****************************************************************************
1255  View list of servers available (or possibly domains). The info is
1256  extracted from lists saved by nmbd on the local host.
1257 ****************************************************************************/
1258
1259 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1260                                int mdrcnt, int mprcnt, char **rdata, 
1261                                char **rparam, int *rdata_len, int *rparam_len)
1262 {
1263         char *str1 = param+2;
1264         char *str2 = skip_string(str1,1);
1265         char *p = skip_string(str2,1);
1266         int uLevel = SVAL(p,0);
1267         int buf_len = SVAL(p,2);
1268         uint32 servertype = IVAL(p,4);
1269         char *p2;
1270         int data_len, fixed_len, string_len;
1271         int f_len = 0, s_len = 0;
1272         struct srv_info_struct *servers=NULL;
1273         int counted=0,total=0;
1274         int i,missed;
1275         fstring domain;
1276         BOOL domain_request;
1277         BOOL local_request;
1278
1279         /* If someone sets all the bits they don't really mean to set
1280            DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1281            known servers. */
1282
1283         if (servertype == SV_TYPE_ALL) {
1284                 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1285         }
1286
1287         /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1288            any other bit (they may just set this bit on it's own) they 
1289            want all the locally seen servers. However this bit can be 
1290            set on its own so set the requested servers to be 
1291            ALL - DOMAIN_ENUM. */
1292
1293         if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1294                 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1295         }
1296
1297         domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1298         local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1299
1300         p += 8;
1301
1302         if (!prefix_ok(str1,"WrLehD")) {
1303                 return False;
1304         }
1305         if (!check_server_info(uLevel,str2)) {
1306                 return False;
1307         }
1308   
1309         DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1310         DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1311         DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1312
1313         if (strcmp(str1, "WrLehDz") == 0) {
1314                 pull_ascii_fstring(domain, p);
1315         } else {
1316                 fstrcpy(domain, lp_workgroup());
1317         }
1318
1319         if (lp_browse_list()) {
1320                 total = get_server_info(servertype,&servers,domain);
1321         }
1322
1323         data_len = fixed_len = string_len = 0;
1324         missed = 0;
1325
1326         if (total > 0) {
1327                 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1328         }
1329
1330         {
1331                 char *lastname=NULL;
1332
1333                 for (i=0;i<total;i++) {
1334                         struct srv_info_struct *s = &servers[i];
1335
1336                         if (lastname && strequal(lastname,s->name)) {
1337                                 continue;
1338                         }
1339                         lastname = s->name;
1340                         data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1341                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1342                                 s->name, s->type, s->comment, s->domain));
1343       
1344                         if (data_len <= buf_len) {
1345                                 counted++;
1346                                 fixed_len += f_len;
1347                                 string_len += s_len;
1348                         } else {
1349                                 missed++;
1350                         }
1351                 }
1352         }
1353
1354         *rdata_len = fixed_len + string_len;
1355         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1356         if (!*rdata) {
1357                 return False;
1358         }
1359         memset(*rdata,'\0',*rdata_len);
1360   
1361         p2 = (*rdata) + fixed_len;      /* auxilliary data (strings) will go here */
1362         p = *rdata;
1363         f_len = fixed_len;
1364         s_len = string_len;
1365
1366         {
1367                 char *lastname=NULL;
1368                 int count2 = counted;
1369
1370                 for (i = 0; i < total && count2;i++) {
1371                         struct srv_info_struct *s = &servers[i];
1372
1373                         if (lastname && strequal(lastname,s->name)) {
1374                                 continue;
1375                         }
1376                         lastname = s->name;
1377                         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1378                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1379                                 s->name, s->type, s->comment, s->domain));
1380                         count2--;
1381                 }
1382         }
1383   
1384         *rparam_len = 8;
1385         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1386         if (!*rparam) {
1387                 return False;
1388         }
1389         SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1390         SSVAL(*rparam,2,0);
1391         SSVAL(*rparam,4,counted);
1392         SSVAL(*rparam,6,counted+missed);
1393
1394         SAFE_FREE(servers);
1395
1396         DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1397                 domain,uLevel,counted,counted+missed));
1398
1399         return True;
1400 }
1401
1402 /****************************************************************************
1403   command 0x34 - suspected of being a "Lookup Names" stub api
1404   ****************************************************************************/
1405
1406 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1407                                int mdrcnt, int mprcnt, char **rdata, 
1408                                char **rparam, int *rdata_len, int *rparam_len)
1409 {
1410         char *str1 = param+2;
1411         char *str2 = skip_string(str1,1);
1412         char *p = skip_string(str2,1);
1413         int uLevel = SVAL(p,0);
1414         int buf_len = SVAL(p,2);
1415         int counted=0;
1416         int missed=0;
1417
1418         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1419                 str1, str2, p, uLevel, buf_len));
1420
1421         if (!prefix_ok(str1,"zWrLeh")) {
1422                 return False;
1423         }
1424   
1425         *rdata_len = 0;
1426   
1427         *rparam_len = 8;
1428         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1429         if (!*rparam) {
1430                 return False;
1431         }
1432
1433         SSVAL(*rparam,0,0x08AC); /* informational warning message */
1434         SSVAL(*rparam,2,0);
1435         SSVAL(*rparam,4,counted);
1436         SSVAL(*rparam,6,counted+missed);
1437
1438         return True;
1439 }
1440
1441 /****************************************************************************
1442   get info about a share
1443   ****************************************************************************/
1444
1445 static BOOL check_share_info(int uLevel, char* id)
1446 {
1447         switch( uLevel ) {
1448                 case 0:
1449                         if (strcmp(id,"B13") != 0) {
1450                                 return False;
1451                         }
1452                         break;
1453                 case 1:
1454                         if (strcmp(id,"B13BWz") != 0) {
1455                                 return False;
1456                         }
1457                         break;
1458                 case 2:
1459                         if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1460                                 return False;
1461                         }
1462                         break;
1463                 case 91:
1464                         if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1465                                 return False;
1466                         }
1467                         break;
1468                 default:
1469                         return False;
1470         }
1471         return True;
1472 }
1473
1474 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1475                            char** buf, int* buflen,
1476                            char** stringbuf, int* stringspace, char* baseaddr)
1477 {
1478         int struct_len;
1479         char* p;
1480         char* p2;
1481         int l2;
1482         int len;
1483  
1484         switch( uLevel ) {
1485                 case 0:
1486                         struct_len = 13;
1487                         break;
1488                 case 1:
1489                         struct_len = 20;
1490                         break;
1491                 case 2:
1492                         struct_len = 40;
1493                         break;
1494                 case 91:
1495                         struct_len = 68;
1496                         break;
1497                 default:
1498                         return -1;
1499         }
1500   
1501  
1502         if (!buf) {
1503                 len = 0;
1504
1505                 if (uLevel > 0) {
1506                         len += StrlenExpanded(conn,snum,lp_comment(snum));
1507                 }
1508                 if (uLevel > 1) {
1509                         len += strlen(lp_pathname(snum)) + 1;
1510                 }
1511                 if (buflen) {
1512                         *buflen = struct_len;
1513                 }
1514                 if (stringspace) {
1515                         *stringspace = len;
1516                 }
1517                 return struct_len + len;
1518         }
1519   
1520         len = struct_len;
1521         p = *buf;
1522         if ((*buflen) < struct_len) {
1523                 return -1;
1524         }
1525
1526         if (stringbuf) {
1527                 p2 = *stringbuf;
1528                 l2 = *stringspace;
1529         } else {
1530                 p2 = p + struct_len;
1531                 l2 = (*buflen) - struct_len;
1532         }
1533
1534         if (!baseaddr) {
1535                 baseaddr = p;
1536         }
1537   
1538         push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1539   
1540         if (uLevel > 0) {
1541                 int type;
1542
1543                 SCVAL(p,13,0);
1544                 type = STYPE_DISKTREE;
1545                 if (lp_print_ok(snum)) {
1546                         type = STYPE_PRINTQ;
1547                 }
1548                 if (strequal("IPC",lp_fstype(snum))) {
1549                         type = STYPE_IPC;
1550                 }
1551                 SSVAL(p,14,type);               /* device type */
1552                 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1553                 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1554         }
1555   
1556         if (uLevel > 1) {
1557                 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1558                 SSVALS(p,22,-1);                /* max uses */
1559                 SSVAL(p,24,1); /* current uses */
1560                 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1561                 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1562                 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1563         }
1564   
1565         if (uLevel > 2) {
1566                 memset(p+40,0,SHPWLEN+2);
1567                 SSVAL(p,50,0);
1568                 SIVAL(p,52,0);
1569                 SSVAL(p,56,0);
1570                 SSVAL(p,58,0);
1571                 SIVAL(p,60,0);
1572                 SSVAL(p,64,0);
1573                 SSVAL(p,66,0);
1574         }
1575        
1576         if (stringbuf) {
1577                 (*buf) = p + struct_len;
1578                 (*buflen) -= struct_len;
1579                 (*stringbuf) = p2;
1580                 (*stringspace) = l2;
1581         } else {
1582                 (*buf) = p2;
1583                 (*buflen) -= len;
1584         }
1585
1586         return len;
1587 }
1588
1589 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1590                                  int mdrcnt,int mprcnt,
1591                                  char **rdata,char **rparam,
1592                                  int *rdata_len,int *rparam_len)
1593 {
1594         char *str1 = param+2;
1595         char *str2 = skip_string(str1,1);
1596         char *netname = skip_string(str2,1);
1597         char *p = skip_string(netname,1);
1598         int uLevel = SVAL(p,0);
1599         int snum = find_service(netname);
1600   
1601         if (snum < 0) {
1602                 return False;
1603         }
1604   
1605         /* check it's a supported varient */
1606         if (!prefix_ok(str1,"zWrLh")) {
1607                 return False;
1608         }
1609         if (!check_share_info(uLevel,str2)) {
1610                 return False;
1611         }
1612  
1613         *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
1614         if (!*rdata) {
1615                 return False;
1616         }
1617         p = *rdata;
1618         *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1619         if (*rdata_len < 0) {
1620                 return False;
1621         }
1622  
1623         *rparam_len = 6;
1624         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1625         if (!*rparam) {
1626                 return False;
1627         }
1628         SSVAL(*rparam,0,NERR_Success);
1629         SSVAL(*rparam,2,0);             /* converter word */
1630         SSVAL(*rparam,4,*rdata_len);
1631  
1632         return True;
1633 }
1634
1635 /****************************************************************************
1636   View the list of available shares.
1637
1638   This function is the server side of the NetShareEnum() RAP call.
1639   It fills the return buffer with share names and share comments.
1640   Note that the return buffer normally (in all known cases) allows only
1641   twelve byte strings for share names (plus one for a nul terminator).
1642   Share names longer than 12 bytes must be skipped.
1643  ****************************************************************************/
1644
1645 static BOOL api_RNetShareEnum( connection_struct *conn,
1646                                uint16             vuid,
1647                                char              *param,
1648                                char              *data,
1649                                int                mdrcnt,
1650                                int                mprcnt,
1651                                char             **rdata,
1652                                char             **rparam,
1653                                int               *rdata_len,
1654                                int               *rparam_len )
1655 {
1656         char *str1 = param+2;
1657         char *str2 = skip_string(str1,1);
1658         char *p = skip_string(str2,1);
1659         int uLevel = SVAL(p,0);
1660         int buf_len = SVAL(p,2);
1661         char *p2;
1662         int count = 0;
1663         int total=0,counted=0;
1664         BOOL missed = False;
1665         int i;
1666         int data_len, fixed_len, string_len;
1667         int f_len = 0, s_len = 0;
1668  
1669         if (!prefix_ok(str1,"WrLeh")) {
1670                 return False;
1671         }
1672         if (!check_share_info(uLevel,str2)) {
1673                 return False;
1674         }
1675   
1676         /* Ensure all the usershares are loaded. */
1677         become_root();
1678         count = load_usershare_shares();
1679         unbecome_root();
1680
1681         data_len = fixed_len = string_len = 0;
1682         for (i=0;i<count;i++) {
1683                 fstring servicename_dos;
1684                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1685                         continue;
1686                 }
1687                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1688                 /* Maximum name length = 13. */
1689                 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1690                         total++;
1691                         data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1692                         if (data_len <= buf_len) {
1693                                 counted++;
1694                                 fixed_len += f_len;
1695                                 string_len += s_len;
1696                         } else {
1697                                 missed = True;
1698                         }
1699                 }
1700         }
1701
1702         *rdata_len = fixed_len + string_len;
1703         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1704         if (!*rdata) {
1705                 return False;
1706         }
1707         memset(*rdata,0,*rdata_len);
1708   
1709         p2 = (*rdata) + fixed_len;      /* auxiliary data (strings) will go here */
1710         p = *rdata;
1711         f_len = fixed_len;
1712         s_len = string_len;
1713
1714         for( i = 0; i < count; i++ ) {
1715                 fstring servicename_dos;
1716                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1717                         continue;
1718                 }
1719
1720                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1721                 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1722                         if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1723                                 break;
1724                         }
1725                 }
1726         }
1727   
1728         *rparam_len = 8;
1729         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1730         if (!*rparam) {
1731                 return False;
1732         }
1733         SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1734         SSVAL(*rparam,2,0);
1735         SSVAL(*rparam,4,counted);
1736         SSVAL(*rparam,6,total);
1737   
1738         DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1739                 counted,total,uLevel,
1740                 buf_len,*rdata_len,mdrcnt));
1741
1742         return True;
1743 }
1744
1745 /****************************************************************************
1746   Add a share
1747   ****************************************************************************/
1748
1749 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid, char *param,char *data,
1750                                  int mdrcnt,int mprcnt,
1751                                  char **rdata,char **rparam,
1752                                  int *rdata_len,int *rparam_len)
1753 {
1754         char *str1 = param+2;
1755         char *str2 = skip_string(str1,1);
1756         char *p = skip_string(str2,1);
1757         int uLevel = SVAL(p,0);
1758         fstring sharename;
1759         fstring comment;
1760         pstring pathname;
1761         char *command, *cmdname;
1762         unsigned int offset;
1763         int snum;
1764         int res = ERRunsup;
1765   
1766         /* check it's a supported varient */
1767         if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1768                 return False;
1769         }
1770         if (!check_share_info(uLevel,str2)) {
1771                 return False;
1772         }
1773         if (uLevel != 2) {
1774                 return False;
1775         }
1776
1777         pull_ascii_fstring(sharename,data);
1778         snum = find_service(sharename);
1779         if (snum >= 0) { /* already exists */
1780                 res = ERRfilexists;
1781                 goto error_exit;
1782         }
1783
1784         /* only support disk share adds */
1785         if (SVAL(data,14)!=STYPE_DISKTREE) {
1786                 return False;
1787         }
1788
1789         offset = IVAL(data, 16);
1790         if (offset >= mdrcnt) {
1791                 res = ERRinvalidparam;
1792                 goto error_exit;
1793         }
1794
1795         pull_ascii_fstring(comment, offset? (data+offset) : "");
1796
1797         offset = IVAL(data, 26);
1798
1799         if (offset >= mdrcnt) {
1800                 res = ERRinvalidparam;
1801                 goto error_exit;
1802         }
1803
1804         pull_ascii_pstring(pathname, offset? (data+offset) : "");
1805
1806         string_replace(sharename, '"', ' ');
1807         string_replace(pathname, '"', ' ');
1808         string_replace(comment, '"', ' ');
1809
1810         cmdname = lp_add_share_cmd();
1811
1812         if (!cmdname || *cmdname == '\0') {
1813                 return False;
1814         }
1815
1816         asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1817                 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1818
1819         if (command) {
1820                 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1821
1822                 if ((res = smbrun(command, NULL)) != 0) {
1823                         DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1824                         SAFE_FREE(command);
1825                         res = ERRnoaccess;
1826                         goto error_exit;
1827                 } else {
1828                         SAFE_FREE(command);
1829                         message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
1830                 }
1831         } else {
1832                 return False;
1833         }
1834
1835         *rparam_len = 6;
1836         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1837         if (!*rparam) {
1838                 return False;
1839         }
1840         SSVAL(*rparam,0,NERR_Success);
1841         SSVAL(*rparam,2,0);             /* converter word */
1842         SSVAL(*rparam,4,*rdata_len);
1843         *rdata_len = 0;
1844   
1845         return True;
1846
1847   error_exit:
1848
1849         *rparam_len = 4;
1850         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1851         if (!*rparam) {
1852                 return False;
1853         }
1854         *rdata_len = 0;
1855         SSVAL(*rparam,0,res);
1856         SSVAL(*rparam,2,0);
1857         return True;
1858 }
1859
1860 /****************************************************************************
1861   view list of groups available
1862   ****************************************************************************/
1863
1864 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1865                               int mdrcnt,int mprcnt,
1866                               char **rdata,char **rparam,
1867                               int *rdata_len,int *rparam_len)
1868 {
1869         int i;
1870         int errflags=0;
1871         int resume_context, cli_buf_size;
1872         char *str1 = param+2;
1873         char *str2 = skip_string(str1,1);
1874         char *p = skip_string(str2,1);
1875
1876         struct pdb_search *search;
1877         struct samr_displayentry *entries;
1878
1879         int num_entries;
1880  
1881         if (strcmp(str1,"WrLeh") != 0) {
1882                 return False;
1883         }
1884
1885         /* parameters  
1886          * W-> resume context (number of users to skip)
1887          * r -> return parameter pointer to receive buffer 
1888          * L -> length of receive buffer
1889          * e -> return parameter number of entries
1890          * h -> return parameter total number of users
1891          */
1892
1893         if (strcmp("B21",str2) != 0) {
1894                 return False;
1895         }
1896
1897         /* get list of domain groups SID_DOMAIN_GRP=2 */
1898         become_root();
1899         search = pdb_search_groups();
1900         unbecome_root();
1901
1902         if (search == NULL) {
1903                 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1904                 return False;
1905         }
1906
1907         resume_context = SVAL(p,0); 
1908         cli_buf_size=SVAL(p+2,0);
1909         DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1910                   "%d\n", resume_context, cli_buf_size));
1911
1912         become_root();
1913         num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1914                                          &entries);
1915         unbecome_root();
1916
1917         *rdata_len = cli_buf_size;
1918         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1919         if (!*rdata) {
1920                 return False;
1921         }
1922
1923         p = *rdata;
1924
1925         for(i=0; i<num_entries; i++) {
1926                 fstring name;
1927                 fstrcpy(name, entries[i].account_name);
1928                 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
1929                         /* truncate the name at 21 chars. */
1930                         memcpy(p, name, 21); 
1931                         DEBUG(10,("adding entry %d group %s\n", i, p));
1932                         p += 21;
1933                         p += 5; /* Both NT4 and W2k3SP1 do padding here.
1934                                    No idea why... */
1935                 } else {
1936                         /* set overflow error */
1937                         DEBUG(3,("overflow on entry %d group %s\n", i, name));
1938                         errflags=234;
1939                         break;
1940                 }
1941         }
1942
1943         pdb_search_destroy(search);
1944
1945         *rdata_len = PTR_DIFF(p,*rdata);
1946
1947         *rparam_len = 8;
1948         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1949         if (!*rparam) {
1950                 return False;
1951         }
1952         SSVAL(*rparam, 0, errflags);
1953         SSVAL(*rparam, 2, 0);           /* converter word */
1954         SSVAL(*rparam, 4, i);   /* is this right?? */
1955         SSVAL(*rparam, 6, resume_context+num_entries);  /* is this right?? */
1956
1957         return(True);
1958 }
1959
1960 /*******************************************************************
1961  Get groups that a user is a member of.
1962 ******************************************************************/
1963
1964 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
1965                               int mdrcnt,int mprcnt,
1966                               char **rdata,char **rparam,
1967                               int *rdata_len,int *rparam_len)
1968 {
1969         char *str1 = param+2;
1970         char *str2 = skip_string(str1,1);
1971         char *UserName = skip_string(str2,1);
1972         char *p = skip_string(UserName,1);
1973         int uLevel = SVAL(p,0);
1974         const char *level_string;
1975         int count=0;
1976         struct samu *sampw = NULL;
1977         BOOL ret = False;
1978         DOM_SID *sids;
1979         gid_t *gids;
1980         size_t num_groups;
1981         size_t i;
1982         NTSTATUS result;
1983         DOM_SID user_sid;
1984         enum SID_NAME_USE type;
1985         TALLOC_CTX *mem_ctx;
1986
1987         *rparam_len = 8;
1988         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1989         if (!*rparam) {
1990                 return False;
1991         }
1992   
1993         /* check it's a supported varient */
1994         
1995         if ( strcmp(str1,"zWrLeh") != 0 )
1996                 return False;
1997                 
1998         switch( uLevel ) {
1999                 case 0:
2000                         level_string = "B21";
2001                         break;
2002                 default:
2003                         return False;
2004         }
2005
2006         if (strcmp(level_string,str2) != 0)
2007                 return False;
2008
2009         *rdata_len = mdrcnt + 1024;
2010         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2011         if (!*rdata) {
2012                 return False;
2013         }
2014         SSVAL(*rparam,0,NERR_Success);
2015         SSVAL(*rparam,2,0);             /* converter word */
2016
2017         p = *rdata;
2018
2019         mem_ctx = talloc_new(NULL);
2020         if (mem_ctx == NULL) {
2021                 DEBUG(0, ("talloc_new failed\n"));
2022                 return False;
2023         }
2024
2025         if ( !(sampw = samu_new(mem_ctx)) ) {
2026                 DEBUG(0, ("samu_new() failed!\n"));
2027                 TALLOC_FREE(mem_ctx);
2028                 return False;
2029         }
2030
2031         /* Lookup the user information; This should only be one of 
2032            our accounts (not remote domains) */
2033
2034         become_root();                                  /* ROOT BLOCK */
2035
2036         if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2037                          NULL, NULL, &user_sid, &type)) {
2038                 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2039                 goto done;
2040         }
2041
2042         if (type != SID_NAME_USER) {
2043                 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2044                            sid_type_lookup(type)));
2045                 goto done;
2046         }
2047
2048         if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2049                 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2050                            sid_string_static(&user_sid), UserName));
2051                 goto done;
2052         }
2053
2054         gids = NULL;
2055         sids = NULL;
2056         num_groups = 0;
2057
2058         result = pdb_enum_group_memberships(mem_ctx, sampw,
2059                                             &sids, &gids, &num_groups);
2060
2061         if (!NT_STATUS_IS_OK(result)) {
2062                 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2063                            UserName));
2064                 goto done;
2065         }
2066
2067         for (i=0; i<num_groups; i++) {
2068
2069                 const char *grp_name;
2070         
2071                 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2072                         pstrcpy(p, grp_name);
2073                         p += 21; 
2074                         count++;
2075                 }
2076         }
2077
2078         *rdata_len = PTR_DIFF(p,*rdata);
2079
2080         SSVAL(*rparam,4,count); /* is this right?? */
2081         SSVAL(*rparam,6,count); /* is this right?? */
2082
2083         ret = True;
2084
2085 done:
2086         unbecome_root();                                /* END ROOT BLOCK */
2087
2088         TALLOC_FREE(mem_ctx);
2089
2090         return ret;
2091 }
2092
2093 /*******************************************************************
2094  Get all users.
2095 ******************************************************************/
2096
2097 static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2098                                  int mdrcnt,int mprcnt,
2099                                  char **rdata,char **rparam,
2100                                  int *rdata_len,int *rparam_len)
2101 {
2102         int count_sent=0;
2103         int num_users=0;
2104         int errflags=0;
2105         int i, resume_context, cli_buf_size;
2106         struct pdb_search *search;
2107         struct samr_displayentry *users;
2108
2109         char *str1 = param+2;
2110         char *str2 = skip_string(str1,1);
2111         char *p = skip_string(str2,1);
2112
2113         if (strcmp(str1,"WrLeh") != 0)
2114                 return False;
2115         /* parameters
2116           * W-> resume context (number of users to skip)
2117           * r -> return parameter pointer to receive buffer
2118           * L -> length of receive buffer
2119           * e -> return parameter number of entries
2120           * h -> return parameter total number of users
2121           */
2122   
2123         resume_context = SVAL(p,0);
2124         cli_buf_size=SVAL(p+2,0);
2125         DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2126                         resume_context, cli_buf_size));
2127
2128         *rparam_len = 8;
2129         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2130         if (!*rparam) {
2131                 return False;
2132         }
2133
2134         /* check it's a supported varient */
2135         if (strcmp("B21",str2) != 0)
2136                 return False;
2137
2138         *rdata_len = cli_buf_size;
2139         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2140         if (!*rdata) {
2141                 return False;
2142         }
2143
2144         p = *rdata;
2145
2146         become_root();
2147         search = pdb_search_users(ACB_NORMAL);
2148         unbecome_root();
2149         if (search == NULL) {
2150                 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2151                 return False;
2152         }
2153
2154         become_root();
2155         num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2156                                        &users);
2157         unbecome_root();
2158
2159         errflags=NERR_Success;
2160
2161         for (i=0; i<num_users; i++) {
2162                 const char *name = users[i].account_name;
2163                 
2164                 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2165                         pstrcpy(p,name); 
2166                         DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2167                                   "%s\n",count_sent,p));
2168                         p += 21; 
2169                         count_sent++; 
2170                 } else {
2171                         /* set overflow error */
2172                         DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2173                                   "username %s\n",count_sent,name));
2174                         errflags=234;
2175                         break;
2176                 }
2177         }
2178
2179         pdb_search_destroy(search);
2180
2181         *rdata_len = PTR_DIFF(p,*rdata);
2182
2183         SSVAL(*rparam,0,errflags);
2184         SSVAL(*rparam,2,0);           /* converter word */
2185         SSVAL(*rparam,4,count_sent);  /* is this right?? */
2186         SSVAL(*rparam,6,num_users); /* is this right?? */
2187
2188         return True;
2189 }
2190
2191 /****************************************************************************
2192  Get the time of day info.
2193 ****************************************************************************/
2194
2195 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
2196                              int mdrcnt,int mprcnt,
2197                              char **rdata,char **rparam,
2198                              int *rdata_len,int *rparam_len)
2199 {
2200         struct tm *t;
2201         time_t unixdate = time(NULL);
2202         char *p;
2203
2204         *rparam_len = 4;
2205         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2206         if (!*rparam) {
2207                 return False;
2208         }
2209
2210         *rdata_len = 21;
2211         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2212         if (!*rdata) {
2213                 return False;
2214         }
2215
2216         SSVAL(*rparam,0,NERR_Success);
2217         SSVAL(*rparam,2,0);             /* converter word */
2218
2219         p = *rdata;
2220
2221         srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2222                                             by NT in a "net time" operation,
2223                                             it seems to ignore the one below */
2224
2225         /* the client expects to get localtime, not GMT, in this bit 
2226                 (I think, this needs testing) */
2227         t = localtime(&unixdate);
2228         if (!t) {
2229                 return False;
2230         }
2231
2232         SIVAL(p,4,0);           /* msecs ? */
2233         SCVAL(p,8,t->tm_hour);
2234         SCVAL(p,9,t->tm_min);
2235         SCVAL(p,10,t->tm_sec);
2236         SCVAL(p,11,0);          /* hundredths of seconds */
2237         SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2238         SSVAL(p,14,10000);              /* timer interval in 0.0001 of sec */
2239         SCVAL(p,16,t->tm_mday);
2240         SCVAL(p,17,t->tm_mon + 1);
2241         SSVAL(p,18,1900+t->tm_year);
2242         SCVAL(p,20,t->tm_wday);
2243
2244         return True;
2245 }
2246
2247 /****************************************************************************
2248  Set the user password.
2249 *****************************************************************************/
2250
2251 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
2252                                 int mdrcnt,int mprcnt,
2253                                 char **rdata,char **rparam,
2254                                 int *rdata_len,int *rparam_len)
2255 {
2256         char *p = skip_string(param+2,2);
2257         fstring user;
2258         fstring pass1,pass2;
2259
2260         pull_ascii_fstring(user,p);
2261
2262         p = skip_string(p,1);
2263
2264         memset(pass1,'\0',sizeof(pass1));
2265         memset(pass2,'\0',sizeof(pass2));
2266         memcpy(pass1,p,16);
2267         memcpy(pass2,p+16,16);
2268
2269         *rparam_len = 4;
2270         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2271         if (!*rparam) {
2272                 return False;
2273         }
2274
2275         *rdata_len = 0;
2276
2277         SSVAL(*rparam,0,NERR_badpass);
2278         SSVAL(*rparam,2,0);             /* converter word */
2279
2280         DEBUG(3,("Set password for <%s>\n",user));
2281
2282         /*
2283          * Attempt to verify the old password against smbpasswd entries
2284          * Win98 clients send old and new password in plaintext for this call.
2285          */
2286
2287         {
2288                 auth_serversupplied_info *server_info = NULL;
2289                 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2290
2291                 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2292
2293                         become_root();
2294                         if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2295                                 SSVAL(*rparam,0,NERR_Success);
2296                         }
2297                         unbecome_root();
2298
2299                         TALLOC_FREE(server_info);
2300                 }
2301                 data_blob_clear_free(&password);
2302         }
2303
2304         /*
2305          * If the plaintext change failed, attempt
2306          * the old encrypted method. NT will generate this
2307          * after trying the samr method. Note that this
2308          * method is done as a last resort as this
2309          * password change method loses the NT password hash
2310          * and cannot change the UNIX password as no plaintext
2311          * is received.
2312          */
2313
2314         if(SVAL(*rparam,0) != NERR_Success) {
2315                 struct samu *hnd = NULL;
2316
2317                 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2318                         become_root();
2319                         if (change_lanman_password(hnd,(uchar *)pass2)) {
2320                                 SSVAL(*rparam,0,NERR_Success);
2321                         }
2322                         unbecome_root();
2323                         TALLOC_FREE(hnd);
2324                 }
2325         }
2326
2327         memset((char *)pass1,'\0',sizeof(fstring));
2328         memset((char *)pass2,'\0',sizeof(fstring));      
2329          
2330         return(True);
2331 }
2332
2333 /****************************************************************************
2334   Set the user password (SamOEM version - gets plaintext).
2335 ****************************************************************************/
2336
2337 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
2338                                 int mdrcnt,int mprcnt,
2339                                 char **rdata,char **rparam,
2340                                 int *rdata_len,int *rparam_len)
2341 {
2342         fstring user;
2343         char *p = param + 2;
2344         *rparam_len = 2;
2345         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2346         if (!*rparam) {
2347                 return False;
2348         }
2349
2350         *rdata_len = 0;
2351
2352         SSVAL(*rparam,0,NERR_badpass);
2353
2354         /*
2355          * Check the parameter definition is correct.
2356          */
2357
2358         if(!strequal(param + 2, "zsT")) {
2359                 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
2360                 return False;
2361         }
2362         p = skip_string(p, 1);
2363
2364         if(!strequal(p, "B516B16")) {
2365                 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2366                 return False;
2367         }
2368         p = skip_string(p,1);
2369         p += pull_ascii_fstring(user,p);
2370
2371         DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2372
2373         /*
2374          * Pass the user through the NT -> unix user mapping
2375          * function.
2376          */
2377
2378         (void)map_username(user);
2379
2380         if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2381                 SSVAL(*rparam,0,NERR_Success);
2382         }
2383
2384         return(True);
2385 }
2386
2387 /****************************************************************************
2388   delete a print job
2389   Form: <W> <> 
2390   ****************************************************************************/
2391
2392 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
2393                                 int mdrcnt,int mprcnt,
2394                                 char **rdata,char **rparam,
2395                                 int *rdata_len,int *rparam_len)
2396 {
2397         int function = SVAL(param,0);
2398         char *str1 = param+2;
2399         char *str2 = skip_string(str1,1);
2400         char *p = skip_string(str2,1);
2401         uint32 jobid;
2402         int snum;
2403         fstring sharename;
2404         int errcode;
2405         WERROR werr = WERR_OK;
2406
2407         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2408                 return False;
2409
2410         /* check it's a supported varient */
2411         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2412                 return(False);
2413
2414         *rparam_len = 4;
2415         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);       
2416         if (!*rparam) {
2417                 return False;
2418         }
2419         *rdata_len = 0;
2420
2421         if (!print_job_exists(sharename, jobid)) {
2422                 errcode = NERR_JobNotFound;
2423                 goto out;
2424         }
2425
2426         snum = lp_servicenumber( sharename);
2427         if (snum == -1) {
2428                 errcode = NERR_DestNotFound;
2429                 goto out;
2430         }
2431
2432         errcode = NERR_notsupported;
2433         
2434         switch (function) {
2435         case 81:                /* delete */ 
2436                 if (print_job_delete(&current_user, snum, jobid, &werr)) 
2437                         errcode = NERR_Success;
2438                 break;
2439         case 82:                /* pause */
2440                 if (print_job_pause(&current_user, snum, jobid, &werr)) 
2441                         errcode = NERR_Success;
2442                 break;
2443         case 83:                /* resume */
2444                 if (print_job_resume(&current_user, snum, jobid, &werr)) 
2445                         errcode = NERR_Success;
2446                 break;
2447         }
2448
2449         if (!W_ERROR_IS_OK(werr))
2450                 errcode = W_ERROR_V(werr);
2451         
2452  out:
2453         SSVAL(*rparam,0,errcode);       
2454         SSVAL(*rparam,2,0);             /* converter word */
2455
2456         return(True);
2457 }
2458
2459 /****************************************************************************
2460   Purge a print queue - or pause or resume it.
2461   ****************************************************************************/
2462
2463 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
2464                                  int mdrcnt,int mprcnt,
2465                                  char **rdata,char **rparam,
2466                                  int *rdata_len,int *rparam_len)
2467 {
2468         int function = SVAL(param,0);
2469         char *str1 = param+2;
2470         char *str2 = skip_string(str1,1);
2471         char *QueueName = skip_string(str2,1);
2472         int errcode = NERR_notsupported;
2473         int snum;
2474         WERROR werr = WERR_OK;
2475
2476         /* check it's a supported varient */
2477         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2478                 return(False);
2479
2480         *rparam_len = 4;
2481         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2482         if (!*rparam) {
2483                 return False;
2484         }
2485         *rdata_len = 0;
2486
2487         snum = print_queue_snum(QueueName);
2488
2489         if (snum == -1) {
2490                 errcode = NERR_JobNotFound;
2491                 goto out;
2492         }
2493
2494         switch (function) {
2495         case 74: /* Pause queue */
2496                 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2497                 break;
2498         case 75: /* Resume queue */
2499                 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2500                 break;
2501         case 103: /* Purge */
2502                 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2503                 break;
2504         }
2505
2506         if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2507
2508  out:
2509         SSVAL(*rparam,0,errcode);
2510         SSVAL(*rparam,2,0);             /* converter word */
2511
2512         return(True);
2513 }
2514
2515 /****************************************************************************
2516   set the property of a print job (undocumented?)
2517   ? function = 0xb -> set name of print job
2518   ? function = 0x6 -> move print job up/down
2519   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2520   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2521 ****************************************************************************/
2522
2523 static int check_printjob_info(struct pack_desc* desc,
2524                                int uLevel, char* id)
2525 {
2526         desc->subformat = NULL;
2527         switch( uLevel ) {
2528         case 0: desc->format = "W"; break;
2529         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2530         case 2: desc->format = "WWzWWDDzz"; break;
2531         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2532         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2533         default: return False;
2534         }
2535         if (strcmp(desc->format,id) != 0) return False;
2536         return True;
2537 }
2538
2539 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2540                              int mdrcnt,int mprcnt,
2541                              char **rdata,char **rparam,
2542                              int *rdata_len,int *rparam_len)
2543 {
2544         struct pack_desc desc;
2545         char *str1 = param+2;
2546         char *str2 = skip_string(str1,1);
2547         char *p = skip_string(str2,1);
2548         uint32 jobid;
2549         fstring sharename;
2550         int uLevel = SVAL(p,2);
2551         int function = SVAL(p,4);
2552         int place, errcode;
2553
2554         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2555                 return False;
2556         *rparam_len = 4;
2557         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2558         if (!*rparam) {
2559                 return False;
2560         }
2561
2562         if (!share_defined(sharename)) {
2563                 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2564                          sharename));
2565                 return False;
2566         }
2567   
2568         *rdata_len = 0;
2569         
2570         /* check it's a supported varient */
2571         if ((strcmp(str1,"WWsTP")) || 
2572             (!check_printjob_info(&desc,uLevel,str2)))
2573                 return(False);
2574
2575         if (!print_job_exists(sharename, jobid)) {
2576                 errcode=NERR_JobNotFound;
2577                 goto out;
2578         }
2579
2580         errcode = NERR_notsupported;
2581
2582         switch (function) {
2583         case 0x6:
2584                 /* change job place in the queue, 
2585                    data gives the new place */
2586                 place = SVAL(data,0);
2587                 if (print_job_set_place(sharename, jobid, place)) {
2588                         errcode=NERR_Success;
2589                 }
2590                 break;
2591
2592         case 0xb:   
2593                 /* change print job name, data gives the name */
2594                 if (print_job_set_name(sharename, jobid, data)) {
2595                         errcode=NERR_Success;
2596                 }
2597                 break;
2598
2599         default:
2600                 return False;
2601         }
2602
2603  out:
2604         SSVALS(*rparam,0,errcode);
2605         SSVAL(*rparam,2,0);             /* converter word */
2606         
2607         return(True);
2608 }
2609
2610
2611 /****************************************************************************
2612  Get info about the server.
2613 ****************************************************************************/
2614
2615 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2616                                   int mdrcnt,int mprcnt,
2617                                   char **rdata,char **rparam,
2618                                   int *rdata_len,int *rparam_len)
2619 {
2620         char *str1 = param+2;
2621         char *str2 = skip_string(str1,1);
2622         char *p = skip_string(str2,1);
2623         int uLevel = SVAL(p,0);
2624         char *p2;
2625         int struct_len;
2626
2627         DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2628
2629         /* check it's a supported varient */
2630         if (!prefix_ok(str1,"WrLh")) {
2631                 return False;
2632         }
2633
2634         switch( uLevel ) {
2635                 case 0:
2636                         if (strcmp(str2,"B16") != 0) {
2637                                 return False;
2638                         }
2639                         struct_len = 16;
2640                         break;
2641                 case 1:
2642                         if (strcmp(str2,"B16BBDz") != 0) {
2643                                 return False;
2644                         }
2645                         struct_len = 26;
2646                         break;
2647                 case 2:
2648                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2649                                 return False;
2650                         }
2651                         struct_len = 134;
2652                         break;
2653                 case 3:
2654                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2655                                 return False;
2656                         }
2657                         struct_len = 144;
2658                         break;
2659                 case 20:
2660                         if (strcmp(str2,"DN") != 0) {
2661                                 return False;
2662                         }
2663                         struct_len = 6;
2664                         break;
2665                 case 50:
2666                         if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2667                                 return False;
2668                         }
2669                         struct_len = 42;
2670                         break;
2671                 default:
2672                         return False;
2673         }
2674
2675         *rdata_len = mdrcnt;
2676         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2677         if (!*rdata) {
2678                 return False;
2679         }
2680
2681         p = *rdata;
2682         p2 = p + struct_len;
2683         if (uLevel != 20) {
2684                 srvstr_push(NULL, p,get_local_machine_name(),16, 
2685                         STR_ASCII|STR_UPPER|STR_TERMINATE);
2686         }
2687         p += 16;
2688         if (uLevel > 0) {
2689                 struct srv_info_struct *servers=NULL;
2690                 int i,count;
2691                 pstring comment;
2692                 uint32 servertype= lp_default_server_announce();
2693
2694                 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2695
2696                 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2697                         for (i=0;i<count;i++) {
2698                                 if (strequal(servers[i].name,get_local_machine_name())) {
2699                                         servertype = servers[i].type;
2700                                         push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2701                                 }
2702                         }
2703                 }
2704
2705                 SAFE_FREE(servers);
2706
2707                 SCVAL(p,0,lp_major_announce_version());
2708                 SCVAL(p,1,lp_minor_announce_version());
2709                 SIVAL(p,2,servertype);
2710
2711                 if (mdrcnt == struct_len) {
2712                         SIVAL(p,6,0);
2713                 } else {
2714                         SIVAL(p,6,PTR_DIFF(p2,*rdata));
2715                         standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2716                                               conn->connectpath, conn->gid,
2717                                               get_current_username(),
2718                                               current_user_info.domain,
2719                                               comment, sizeof(comment));
2720                         StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2721                         p2 = skip_string(p2,1);
2722                 }
2723         }
2724
2725         if (uLevel > 1) {
2726                 return False;           /* not yet implemented */
2727         }
2728
2729         *rdata_len = PTR_DIFF(p2,*rdata);
2730
2731         *rparam_len = 6;
2732         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2733         if (!*rparam) {
2734                 return False;
2735         }
2736         SSVAL(*rparam,0,NERR_Success);
2737         SSVAL(*rparam,2,0);             /* converter word */
2738         SSVAL(*rparam,4,*rdata_len);
2739
2740         return True;
2741 }
2742
2743 /****************************************************************************
2744  Get info about the server.
2745 ****************************************************************************/
2746
2747 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2748                                 int mdrcnt,int mprcnt,
2749                                 char **rdata,char **rparam,
2750                                 int *rdata_len,int *rparam_len)
2751 {
2752         char *str1 = param+2;
2753         char *str2 = skip_string(str1,1);
2754         char *p = skip_string(str2,1);
2755         char *p2;
2756         int level = SVAL(p,0);
2757
2758         DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2759
2760         *rparam_len = 6;
2761         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2762         if (!*rparam) {
2763                 return False;
2764         }
2765
2766         /* check it's a supported varient */
2767         if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2768                 return False;
2769         }
2770
2771         *rdata_len = mdrcnt + 1024;
2772         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2773         if (!*rdata) {
2774                 return False;
2775         }
2776
2777         SSVAL(*rparam,0,NERR_Success);
2778         SSVAL(*rparam,2,0);             /* converter word */
2779
2780         p = *rdata;
2781         p2 = p + 22;
2782
2783         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2784         pstrcpy(p2,get_local_machine_name());
2785         strupper_m(p2);
2786         p2 = skip_string(p2,1);
2787         p += 4;
2788
2789         SIVAL(p,0,PTR_DIFF(p2,*rdata));
2790         pstrcpy(p2,current_user_info.smb_name);
2791         p2 = skip_string(p2,1);
2792         p += 4;
2793
2794         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2795         pstrcpy(p2,lp_workgroup());
2796         strupper_m(p2);
2797         p2 = skip_string(p2,1);
2798         p += 4;
2799
2800         SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2801         SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2802         p += 2;
2803
2804         SIVAL(p,0,PTR_DIFF(p2,*rdata));
2805         pstrcpy(p2,lp_workgroup());     /* don't know.  login domain?? */
2806         p2 = skip_string(p2,1);
2807         p += 4;
2808
2809         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2810         pstrcpy(p2,"");
2811         p2 = skip_string(p2,1);
2812         p += 4;
2813
2814         *rdata_len = PTR_DIFF(p2,*rdata);
2815
2816         SSVAL(*rparam,4,*rdata_len);
2817
2818         return True;
2819 }
2820
2821 /****************************************************************************
2822   get info about a user
2823
2824     struct user_info_11 {
2825         char                usri11_name[21];  0-20 
2826         char                usri11_pad;       21 
2827         char                *usri11_comment;  22-25 
2828         char            *usri11_usr_comment;  26-29
2829         unsigned short      usri11_priv;      30-31
2830         unsigned long       usri11_auth_flags; 32-35
2831         long                usri11_password_age; 36-39
2832         char                *usri11_homedir; 40-43
2833         char            *usri11_parms; 44-47
2834         long                usri11_last_logon; 48-51
2835         long                usri11_last_logoff; 52-55
2836         unsigned short      usri11_bad_pw_count; 56-57
2837         unsigned short      usri11_num_logons; 58-59
2838         char                *usri11_logon_server; 60-63
2839         unsigned short      usri11_country_code; 64-65
2840         char            *usri11_workstations; 66-69
2841         unsigned long       usri11_max_storage; 70-73
2842         unsigned short      usri11_units_per_week; 74-75
2843         unsigned char       *usri11_logon_hours; 76-79
2844         unsigned short      usri11_code_page; 80-81
2845     };
2846
2847 where:
2848
2849   usri11_name specifies the user name for which information is retireved
2850
2851   usri11_pad aligns the next data structure element to a word boundary
2852
2853   usri11_comment is a null terminated ASCII comment
2854
2855   usri11_user_comment is a null terminated ASCII comment about the user
2856
2857   usri11_priv specifies the level of the privilege assigned to the user.
2858        The possible values are:
2859
2860 Name             Value  Description
2861 USER_PRIV_GUEST  0      Guest privilege
2862 USER_PRIV_USER   1      User privilege
2863 USER_PRV_ADMIN   2      Administrator privilege
2864
2865   usri11_auth_flags specifies the account operator privileges. The
2866        possible values are:
2867
2868 Name            Value   Description
2869 AF_OP_PRINT     0       Print operator
2870
2871
2872 Leach, Naik                                        [Page 28]
2873 \f
2874
2875
2876 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2877
2878
2879 AF_OP_COMM      1       Communications operator
2880 AF_OP_SERVER    2       Server operator
2881 AF_OP_ACCOUNTS  3       Accounts operator
2882
2883
2884   usri11_password_age specifies how many seconds have elapsed since the
2885        password was last changed.
2886
2887   usri11_home_dir points to a null terminated ASCII string that contains
2888        the path name of the user's home directory.
2889
2890   usri11_parms points to a null terminated ASCII string that is set
2891        aside for use by applications.
2892
2893   usri11_last_logon specifies the time when the user last logged on.
2894        This value is stored as the number of seconds elapsed since
2895        00:00:00, January 1, 1970.
2896
2897   usri11_last_logoff specifies the time when the user last logged off.
2898        This value is stored as the number of seconds elapsed since
2899        00:00:00, January 1, 1970. A value of 0 means the last logoff
2900        time is unknown.
2901
2902   usri11_bad_pw_count specifies the number of incorrect passwords
2903        entered since the last successful logon.
2904
2905   usri11_log1_num_logons specifies the number of times this user has
2906        logged on. A value of -1 means the number of logons is unknown.
2907
2908   usri11_logon_server points to a null terminated ASCII string that
2909        contains the name of the server to which logon requests are sent.
2910        A null string indicates logon requests should be sent to the
2911        domain controller.
2912
2913   usri11_country_code specifies the country code for the user's language
2914        of choice.
2915
2916   usri11_workstations points to a null terminated ASCII string that
2917        contains the names of workstations the user may log on from.
2918        There may be up to 8 workstations, with the names separated by
2919        commas. A null strings indicates there are no restrictions.
2920
2921   usri11_max_storage specifies the maximum amount of disk space the user
2922        can occupy. A value of 0xffffffff indicates there are no
2923        restrictions.
2924
2925   usri11_units_per_week specifies the equal number of time units into
2926        which a week is divided. This value must be equal to 168.
2927
2928   usri11_logon_hours points to a 21 byte (168 bits) string that
2929        specifies the time during which the user can log on. Each bit
2930        represents one unique hour in a week. The first bit (bit 0, word
2931        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2932
2933
2934
2935 Leach, Naik                                        [Page 29]
2936 \f
2937
2938
2939 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
2940
2941
2942        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2943        are no restrictions.
2944
2945   usri11_code_page specifies the code page for the user's language of
2946        choice
2947
2948 All of the pointers in this data structure need to be treated
2949 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
2950 to be ignored. The converter word returned in the parameters section
2951 needs to be subtracted from the lower 16 bits to calculate an offset
2952 into the return buffer where this ASCII string resides.
2953
2954 There is no auxiliary data in the response.
2955
2956   ****************************************************************************/
2957
2958 #define usri11_name           0 
2959 #define usri11_pad            21
2960 #define usri11_comment        22
2961 #define usri11_usr_comment    26
2962 #define usri11_full_name      30
2963 #define usri11_priv           34
2964 #define usri11_auth_flags     36
2965 #define usri11_password_age   40
2966 #define usri11_homedir        44
2967 #define usri11_parms          48
2968 #define usri11_last_logon     52
2969 #define usri11_last_logoff    56
2970 #define usri11_bad_pw_count   60
2971 #define usri11_num_logons     62
2972 #define usri11_logon_server   64
2973 #define usri11_country_code   68
2974 #define usri11_workstations   70
2975 #define usri11_max_storage    74
2976 #define usri11_units_per_week 78
2977 #define usri11_logon_hours    80
2978 #define usri11_code_page      84
2979 #define usri11_end            86
2980
2981 #define USER_PRIV_GUEST 0
2982 #define USER_PRIV_USER 1
2983 #define USER_PRIV_ADMIN 2
2984
2985 #define AF_OP_PRINT     0 
2986 #define AF_OP_COMM      1
2987 #define AF_OP_SERVER    2
2988 #define AF_OP_ACCOUNTS  3
2989
2990
2991 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2992                                 int mdrcnt,int mprcnt,
2993                                 char **rdata,char **rparam,
2994                                 int *rdata_len,int *rparam_len)
2995 {
2996         char *str1 = param+2;
2997         char *str2 = skip_string(str1,1);
2998         char *UserName = skip_string(str2,1);
2999         char *p = skip_string(UserName,1);
3000         int uLevel = SVAL(p,0);
3001         char *p2;
3002         const char *level_string;
3003
3004         /* get NIS home of a previously validated user - simeon */
3005         /* With share level security vuid will always be zero.
3006            Don't depend on vuser being non-null !!. JRA */
3007         user_struct *vuser = get_valid_user_struct(vuid);
3008         if(vuser != NULL) {
3009                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
3010                         vuser->user.unix_name));
3011         }
3012
3013         *rparam_len = 6;
3014         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3015         if (!*rparam) {
3016                 return False;
3017         }
3018
3019         DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3020   
3021         /* check it's a supported variant */
3022         if (strcmp(str1,"zWrLh") != 0) {
3023                 return False;
3024         }
3025         switch( uLevel ) {
3026                 case 0: level_string = "B21"; break;
3027                 case 1: level_string = "B21BB16DWzzWz"; break;
3028                 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3029                 case 10: level_string = "B21Bzzz"; break;
3030                 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3031                 default: return False;
3032         }
3033
3034         if (strcmp(level_string,str2) != 0) {
3035                 return False;
3036         }
3037
3038         *rdata_len = mdrcnt + 1024;
3039         *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
3040         if (!*rdata) {
3041                 return False;
3042         }
3043
3044         SSVAL(*rparam,0,NERR_Success);
3045         SSVAL(*rparam,2,0);             /* converter word */
3046
3047         p = *rdata;
3048         p2 = p + usri11_end;
3049
3050         memset(p,0,21); 
3051         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3052
3053         if (uLevel > 0) {
3054                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3055                 *p2 = 0;
3056         }
3057
3058         if (uLevel >= 10) {
3059                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3060                 pstrcpy(p2,"Comment");
3061                 p2 = skip_string(p2,1);
3062
3063                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3064                 pstrcpy(p2,"UserComment");
3065                 p2 = skip_string(p2,1);
3066
3067                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3068                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3069                 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3070                 p2 = skip_string(p2,1);
3071         }
3072
3073         if (uLevel == 11) {
3074                 /* modelled after NTAS 3.51 reply */
3075                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
3076                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
3077                 SIVALS(p,usri11_password_age,-1);               /* password age */
3078                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3079                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3080                 p2 = skip_string(p2,1);
3081                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3082                 pstrcpy(p2,"");
3083                 p2 = skip_string(p2,1);
3084                 SIVAL(p,usri11_last_logon,0);           /* last logon */
3085                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
3086                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
3087                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
3088                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3089                 pstrcpy(p2,"\\\\*");
3090                 p2 = skip_string(p2,1);
3091                 SSVAL(p,usri11_country_code,0);         /* country code */
3092
3093                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3094                 pstrcpy(p2,"");
3095                 p2 = skip_string(p2,1);
3096
3097                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
3098                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
3099                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3100
3101                 /* a simple way to get logon hours at all times. */
3102                 memset(p2,0xff,21);
3103                 SCVAL(p2,21,0);           /* fix zero termination */
3104                 p2 = skip_string(p2,1);
3105
3106                 SSVAL(p,usri11_code_page,0);            /* code page */
3107         }
3108
3109         if (uLevel == 1 || uLevel == 2) {
3110                 memset(p+22,' ',16);    /* password */
3111                 SIVALS(p,38,-1);                /* password age */
3112                 SSVAL(p,42,
3113                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3114                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3115                 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3116                 p2 = skip_string(p2,1);
3117                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3118                 *p2++ = 0;
3119                 SSVAL(p,52,0);          /* flags */
3120                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
3121                 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3122                 p2 = skip_string(p2,1);
3123                 if (uLevel == 2) {
3124                         SIVAL(p,60,0);          /* auth_flags */
3125                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3126                         pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3127                         p2 = skip_string(p2,1);
3128                         SIVAL(p,68,0);          /* urs_comment */
3129                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3130                         pstrcpy(p2,"");
3131                         p2 = skip_string(p2,1);
3132                         SIVAL(p,76,0);          /* workstations */
3133                         SIVAL(p,80,0);          /* last_logon */
3134                         SIVAL(p,84,0);          /* last_logoff */
3135                         SIVALS(p,88,-1);                /* acct_expires */
3136                         SIVALS(p,92,-1);                /* max_storage */
3137                         SSVAL(p,96,168);        /* units_per_week */
3138                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3139                         memset(p2,-1,21);
3140                         p2 += 21;
3141                         SSVALS(p,102,-1);       /* bad_pw_count */
3142                         SSVALS(p,104,-1);       /* num_logons */
3143                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3144                         {
3145                                 pstring tmp;
3146                                 pstrcpy(tmp, "\\\\%L");
3147                                 standard_sub_basic("", "", tmp, sizeof(tmp));
3148                                 pstrcpy(p2, tmp);
3149                         }
3150                         p2 = skip_string(p2,1);
3151                         SSVAL(p,110,49);        /* country_code */
3152                         SSVAL(p,112,860);       /* code page */
3153                 }
3154         }
3155
3156         *rdata_len = PTR_DIFF(p2,*rdata);
3157
3158         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
3159
3160         return(True);
3161 }
3162
3163 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
3164                                 int mdrcnt,int mprcnt,
3165                                 char **rdata,char **rparam,
3166                                 int *rdata_len,int *rparam_len)
3167 {
3168         char *str1 = param+2;
3169         char *str2 = skip_string(str1,1);
3170         char *p = skip_string(str2,1);
3171         int uLevel;
3172         struct pack_desc desc;
3173         char* name;
3174                 /* With share level security vuid will always be zero.
3175                    Don't depend on vuser being non-null !!. JRA */
3176         user_struct *vuser = get_valid_user_struct(vuid);
3177
3178         if(vuser != NULL) {
3179                 DEBUG(3,("  Username of UID %d is %s\n", (int)vuser->uid, 
3180                         vuser->user.unix_name));
3181         }
3182
3183         uLevel = SVAL(p,0);
3184         name = p + 2;
3185
3186         memset((char *)&desc,'\0',sizeof(desc));
3187
3188         DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3189
3190         /* check it's a supported varient */
3191         if (strcmp(str1,"OOWb54WrLh") != 0) {
3192                 return False;
3193         }
3194         if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3195                 return False;
3196         }
3197         if (mdrcnt > 0) {
3198                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3199                 if (!*rdata) {
3200                         return False;
3201                 }
3202         }
3203
3204         desc.base = *rdata;
3205         desc.buflen = mdrcnt;
3206         desc.subformat = NULL;
3207         desc.format = str2;
3208   
3209         if (init_package(&desc,1,0)) {
3210                 PACKI(&desc,"W",0);             /* code */
3211                 PACKS(&desc,"B21",name);        /* eff. name */
3212                 PACKS(&desc,"B","");            /* pad */
3213                 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3214                 PACKI(&desc,"D",0);             /* auth flags XXX */
3215                 PACKI(&desc,"W",0);             /* num logons */
3216                 PACKI(&desc,"W",0);             /* bad pw count */
3217                 PACKI(&desc,"D",0);             /* last logon */
3218                 PACKI(&desc,"D",-1);            /* last logoff */
3219                 PACKI(&desc,"D",-1);            /* logoff time */
3220                 PACKI(&desc,"D",-1);            /* kickoff time */
3221                 PACKI(&desc,"D",0);             /* password age */
3222                 PACKI(&desc,"D",0);             /* password can change */
3223                 PACKI(&desc,"D",-1);            /* password must change */
3224
3225                 {
3226                         fstring mypath;
3227                         fstrcpy(mypath,"\\\\");
3228                         fstrcat(mypath,get_local_machine_name());
3229                         strupper_m(mypath);
3230                         PACKS(&desc,"z",mypath); /* computer */
3231                 }
3232
3233                 PACKS(&desc,"z",lp_workgroup());/* domain */
3234                 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3235                 PACKI(&desc,"D",0x00000000);            /* reserved */
3236         }
3237
3238         *rdata_len = desc.usedlen;
3239         *rparam_len = 6;
3240         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3241         if (!*rparam) {
3242                 return False;
3243         }
3244         SSVALS(*rparam,0,desc.errcode);
3245         SSVAL(*rparam,2,0);
3246         SSVAL(*rparam,4,desc.neededlen);
3247
3248         DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3249
3250         return True;
3251 }
3252
3253 /****************************************************************************
3254  api_WAccessGetUserPerms
3255 ****************************************************************************/
3256
3257 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
3258                                     int mdrcnt,int mprcnt,
3259                                     char **rdata,char **rparam,
3260                                     int *rdata_len,int *rparam_len)
3261 {
3262         char *str1 = param+2;
3263         char *str2 = skip_string(str1,1);
3264         char *user = skip_string(str2,1);
3265         char *resource = skip_string(user,1);
3266
3267         DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3268
3269         /* check it's a supported varient */
3270         if (strcmp(str1,"zzh") != 0) {
3271                 return False;
3272         }
3273         if (strcmp(str2,"") != 0) {
3274                 return False;
3275         }
3276
3277         *rparam_len = 6;
3278         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3279         if (!*rparam) {
3280                 return False;
3281         }
3282         SSVALS(*rparam,0,0);            /* errorcode */
3283         SSVAL(*rparam,2,0);             /* converter word */
3284         SSVAL(*rparam,4,0x7f);  /* permission flags */
3285
3286         return True;
3287 }
3288
3289 /****************************************************************************
3290   api_WPrintJobEnumerate
3291   ****************************************************************************/
3292
3293 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
3294                                  int mdrcnt,int mprcnt,
3295                                  char **rdata,char **rparam,
3296                                  int *rdata_len,int *rparam_len)
3297 {
3298         char *str1 = param+2;
3299         char *str2 = skip_string(str1,1);
3300         char *p = skip_string(str2,1);
3301         int uLevel;
3302         int count;
3303         int i;
3304         int snum;
3305         fstring sharename;
3306         uint32 jobid;
3307         struct pack_desc desc;
3308         print_queue_struct *queue=NULL;
3309         print_status_struct status;
3310         char *tmpdata=NULL;
3311
3312         uLevel = SVAL(p,2);
3313
3314         memset((char *)&desc,'\0',sizeof(desc));
3315         memset((char *)&status,'\0',sizeof(status));
3316
3317         DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3318
3319         /* check it's a supported varient */
3320         if (strcmp(str1,"WWrLh") != 0) {
3321                 return False;
3322         }
3323         if (!check_printjob_info(&desc,uLevel,str2)) {
3324                 return False;
3325         }
3326
3327         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3328                 return False;
3329         }
3330
3331         snum = lp_servicenumber( sharename);
3332         if (snum < 0 || !VALID_SNUM(snum)) {
3333                 return(False);
3334         }
3335
3336         count = print_queue_status(snum,&queue,&status);
3337         for (i = 0; i < count; i++) {
3338                 if (queue[i].job == jobid) {
3339                         break;
3340                 }
3341         }
3342
3343         if (mdrcnt > 0) {
3344                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3345                 if (!*rdata) {
3346                         return False;
3347                 }
3348                 desc.base = *rdata;
3349                 desc.buflen = mdrcnt;
3350         } else {
3351                 /*
3352                  * Don't return data but need to get correct length
3353                  *  init_package will return wrong size if buflen=0
3354                  */
3355                 desc.buflen = getlen(desc.format);
3356                 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3357         }
3358
3359         if (init_package(&desc,1,0)) {
3360                 if (i < count) {
3361                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3362                         *rdata_len = desc.usedlen;
3363                 } else {
3364                         desc.errcode = NERR_JobNotFound;
3365                         *rdata_len = 0;
3366                 }
3367         }
3368
3369         *rparam_len = 6;
3370         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3371         if (!*rparam) {
3372                 return False;
3373         }
3374         SSVALS(*rparam,0,desc.errcode);
3375         SSVAL(*rparam,2,0);
3376         SSVAL(*rparam,4,desc.neededlen);
3377
3378         SAFE_FREE(queue);
3379         SAFE_FREE(tmpdata);
3380
3381         DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3382
3383         return True;
3384 }
3385
3386 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
3387                                    int mdrcnt,int mprcnt,
3388                                    char **rdata,char **rparam,
3389                                    int *rdata_len,int *rparam_len)
3390 {
3391         char *str1 = param+2;
3392         char *str2 = skip_string(str1,1);
3393         char *p = skip_string(str2,1);
3394         char* name = p;
3395         int uLevel;
3396         int count;
3397         int i, succnt=0;
3398         int snum;
3399         struct pack_desc desc;
3400         print_queue_struct *queue=NULL;
3401         print_status_struct status;
3402
3403         memset((char *)&desc,'\0',sizeof(desc));
3404         memset((char *)&status,'\0',sizeof(status));
3405
3406         p = skip_string(p,1);
3407         uLevel = SVAL(p,0);
3408
3409         DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3410
3411         /* check it's a supported variant */
3412         if (strcmp(str1,"zWrLeh") != 0) {
3413                 return False;
3414         }
3415     
3416         if (uLevel > 2) {
3417                 return False;   /* defined only for uLevel 0,1,2 */
3418         }
3419     
3420         if (!check_printjob_info(&desc,uLevel,str2)) { 
3421                 return False;
3422         }
3423
3424         snum = find_service(name);
3425         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3426                 return False;
3427         }
3428
3429         count = print_queue_status(snum,&queue,&status);
3430         if (mdrcnt > 0) {
3431                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3432                 if (!*rdata) {
3433                         return False;
3434                 }
3435         }
3436         desc.base = *rdata;
3437         desc.buflen = mdrcnt;
3438
3439         if (init_package(&desc,count,0)) {
3440                 succnt = 0;
3441                 for (i = 0; i < count; i++) {
3442                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3443                         if (desc.errcode == NERR_Success) {
3444                                 succnt = i+1;
3445                         }
3446                 }
3447         }
3448
3449         *rdata_len = desc.usedlen;
3450
3451         *rparam_len = 8;
3452         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3453         if (!*rparam) {
3454                 return False;
3455         }
3456         SSVALS(*rparam,0,desc.errcode);
3457         SSVAL(*rparam,2,0);
3458         SSVAL(*rparam,4,succnt);
3459         SSVAL(*rparam,6,count);
3460
3461         SAFE_FREE(queue);
3462
3463         DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3464
3465         return True;
3466 }
3467
3468 static int check_printdest_info(struct pack_desc* desc,
3469                                 int uLevel, char* id)
3470 {
3471         desc->subformat = NULL;
3472         switch( uLevel ) {
3473                 case 0:
3474                         desc->format = "B9";
3475                         break;
3476                 case 1:
3477                         desc->format = "B9B21WWzW";
3478                         break;
3479                 case 2:
3480                         desc->format = "z";
3481                         break;
3482                 case 3:
3483                         desc->format = "zzzWWzzzWW";
3484                         break;
3485                 default:
3486                         return False;
3487         }
3488         if (strcmp(desc->format,id) != 0) {
3489                 return False;
3490         }
3491         return True;
3492 }
3493
3494 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3495                                 struct pack_desc* desc)
3496 {
3497         char buf[100];
3498
3499         strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3500         buf[sizeof(buf)-1] = 0;
3501         strupper_m(buf);
3502
3503         if (uLevel <= 1) {
3504                 PACKS(desc,"B9",buf);   /* szName */
3505                 if (uLevel == 1) {
3506                         PACKS(desc,"B21","");   /* szUserName */
3507                         PACKI(desc,"W",0);              /* uJobId */
3508                         PACKI(desc,"W",0);              /* fsStatus */
3509                         PACKS(desc,"z","");     /* pszStatus */
3510                         PACKI(desc,"W",0);              /* time */
3511                 }
3512         }
3513
3514         if (uLevel == 2 || uLevel == 3) {
3515                 PACKS(desc,"z",buf);            /* pszPrinterName */
3516                 if (uLevel == 3) {
3517                         PACKS(desc,"z","");     /* pszUserName */
3518                         PACKS(desc,"z","");     /* pszLogAddr */
3519                         PACKI(desc,"W",0);              /* uJobId */
3520                         PACKI(desc,"W",0);              /* fsStatus */
3521                         PACKS(desc,"z","");     /* pszStatus */
3522                         PACKS(desc,"z","");     /* pszComment */
3523                         PACKS(desc,"z","NULL"); /* pszDrivers */
3524                         PACKI(desc,"W",0);              /* time */
3525                         PACKI(desc,"W",0);              /* pad1 */
3526                 }
3527         }
3528 }
3529
3530 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
3531                                   int mdrcnt,int mprcnt,
3532                                   char **rdata,char **rparam,
3533                                   int *rdata_len,int *rparam_len)
3534 {
3535         char *str1 = param+2;
3536         char *str2 = skip_string(str1,1);
3537         char *p = skip_string(str2,1);
3538         char* PrinterName = p;
3539         int uLevel;
3540         struct pack_desc desc;
3541         int snum;
3542         char *tmpdata=NULL;
3543
3544         memset((char *)&desc,'\0',sizeof(desc));
3545
3546         p = skip_string(p,1);
3547         uLevel = SVAL(p,0);
3548
3549         DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3550
3551         /* check it's a supported varient */
3552         if (strcmp(str1,"zWrLh") != 0) {
3553                 return False;
3554         }
3555         if (!check_printdest_info(&desc,uLevel,str2)) {
3556                 return False;
3557         }
3558
3559         snum = find_service(PrinterName);
3560         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3561                 *rdata_len = 0;
3562                 desc.errcode = NERR_DestNotFound;
3563                 desc.neededlen = 0;
3564         } else {
3565                 if (mdrcnt > 0) {
3566                         *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3567                         if (!*rdata) {
3568                                 return False;
3569                         }
3570                         desc.base = *rdata;
3571                         desc.buflen = mdrcnt;
3572                 } else {
3573                         /*
3574                          * Don't return data but need to get correct length
3575                          * init_package will return wrong size if buflen=0
3576                          */
3577                         desc.buflen = getlen(desc.format);
3578                         desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3579                 }
3580                 if (init_package(&desc,1,0)) {
3581                         fill_printdest_info(conn,snum,uLevel,&desc);
3582                 }
3583                 *rdata_len = desc.usedlen;
3584         }
3585
3586         *rparam_len = 6;
3587         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3588         if (!*rparam) {
3589                 return False;
3590         }
3591         SSVALS(*rparam,0,desc.errcode);
3592         SSVAL(*rparam,2,0);
3593         SSVAL(*rparam,4,desc.neededlen);
3594
3595         DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3596         SAFE_FREE(tmpdata);
3597
3598         return True;
3599 }
3600
3601 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3602                                int mdrcnt,int mprcnt,
3603                                char **rdata,char **rparam,
3604                                int *rdata_len,int *rparam_len)
3605 {
3606         char *str1 = param+2;
3607         char *str2 = skip_string(str1,1);
3608         char *p = skip_string(str2,1);
3609         int uLevel;
3610         int queuecnt;
3611         int i, n, succnt=0;
3612         struct pack_desc desc;
3613         int services = lp_numservices();
3614
3615         memset((char *)&desc,'\0',sizeof(desc));
3616
3617         uLevel = SVAL(p,0);
3618
3619         DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3620
3621         /* check it's a supported varient */
3622         if (strcmp(str1,"WrLeh") != 0) {
3623                 return False;
3624         }
3625         if (!check_printdest_info(&desc,uLevel,str2)) {
3626                 return False;
3627         }
3628
3629         queuecnt = 0;
3630         for (i = 0; i < services; i++) {
3631                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3632                         queuecnt++;
3633                 }
3634         }
3635
3636         if (mdrcnt > 0) {
3637                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3638                 if (!*rdata) {
3639                         return False;
3640                 }
3641         }
3642
3643         desc.base = *rdata;
3644         desc.buflen = mdrcnt;
3645         if (init_package(&desc,queuecnt,0)) {    
3646                 succnt = 0;
3647                 n = 0;
3648                 for (i = 0; i < services; i++) {
3649                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3650                                 fill_printdest_info(conn,i,uLevel,&desc);
3651                                 n++;
3652                                 if (desc.errcode == NERR_Success) {
3653                                         succnt = n;
3654                                 }
3655                         }
3656                 }
3657         }
3658
3659         *rdata_len = desc.usedlen;
3660
3661         *rparam_len = 8;
3662         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3663         if (!*rparam) {
3664                 return False;
3665         }
3666         SSVALS(*rparam,0,desc.errcode);
3667         SSVAL(*rparam,2,0);
3668         SSVAL(*rparam,4,succnt);
3669         SSVAL(*rparam,6,queuecnt);
3670
3671         DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3672
3673         return True;
3674 }
3675
3676 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3677                                  int mdrcnt,int mprcnt,
3678                                  char **rdata,char **rparam,
3679                                  int *rdata_len,int *rparam_len)
3680 {
3681         char *str1 = param+2;
3682         char *str2 = skip_string(str1,1);
3683         char *p = skip_string(str2,1);
3684         int uLevel;
3685         int succnt;
3686         struct pack_desc desc;
3687
3688         memset((char *)&desc,'\0',sizeof(desc));
3689
3690         uLevel = SVAL(p,0);
3691
3692         DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3693
3694         /* check it's a supported varient */
3695         if (strcmp(str1,"WrLeh") != 0) {
3696                 return False;
3697         }
3698         if (uLevel != 0 || strcmp(str2,"B41") != 0) {
3699                 return False;
3700         }
3701
3702         if (mdrcnt > 0) {
3703                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3704                 if (!*rdata) {
3705                         return False;
3706                 }
3707         }
3708         desc.base = *rdata;
3709         desc.buflen = mdrcnt;
3710         if (init_package(&desc,1,0)) {
3711                 PACKS(&desc,"B41","NULL");
3712         }
3713
3714         succnt = (desc.errcode == NERR_Success ? 1 : 0);
3715
3716         *rdata_len = desc.usedlen;
3717
3718         *rparam_len = 8;
3719         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3720         if (!*rparam) {
3721                 return False;
3722         }
3723         SSVALS(*rparam,0,desc.errcode);
3724         SSVAL(*rparam,2,0);
3725         SSVAL(*rparam,4,succnt);
3726         SSVAL(*rparam,6,1);
3727
3728         DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3729
3730         return True;
3731 }
3732
3733 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3734                                 int mdrcnt,int mprcnt,
3735                                 char **rdata,char **rparam,
3736                                 int *rdata_len,int *rparam_len)
3737 {
3738         char *str1 = param+2;
3739         char *str2 = skip_string(str1,1);
3740         char *p = skip_string(str2,1);
3741         int uLevel;
3742         int succnt;
3743         struct pack_desc desc;
3744
3745         memset((char *)&desc,'\0',sizeof(desc));
3746
3747         uLevel = SVAL(p,0);
3748
3749         DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3750
3751         /* check it's a supported varient */
3752         if (strcmp(str1,"WrLeh") != 0) {
3753                 return False;
3754         }
3755         if (uLevel != 0 || strcmp(str2,"B13") != 0) {
3756                 return False;
3757         }
3758
3759         if (mdrcnt > 0) {
3760                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3761                 if (!*rdata) {
3762                         return False;
3763                 }
3764         }
3765         desc.base = *rdata;
3766         desc.buflen = mdrcnt;
3767         desc.format = str2;
3768         if (init_package(&desc,1,0)) {
3769                 PACKS(&desc,"B13","lpd");
3770         }
3771
3772         succnt = (desc.errcode == NERR_Success ? 1 : 0);
3773
3774         *rdata_len = desc.usedlen;
3775
3776         *rparam_len = 8;
3777         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3778         if (!*rparam) {
3779                 return False;
3780         }
3781         SSVALS(*rparam,0,desc.errcode);
3782         SSVAL(*rparam,2,0);
3783         SSVAL(*rparam,4,succnt);
3784         SSVAL(*rparam,6,1);
3785
3786         DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3787
3788         return True;
3789 }
3790
3791 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3792                                int mdrcnt,int mprcnt,
3793                                char **rdata,char **rparam,
3794                                int *rdata_len,int *rparam_len)
3795 {
3796         char *str1 = param+2;
3797         char *str2 = skip_string(str1,1);
3798         char *p = skip_string(str2,1);
3799         int uLevel;
3800         int succnt;
3801         struct pack_desc desc;
3802
3803         memset((char *)&desc,'\0',sizeof(desc));
3804
3805         uLevel = SVAL(p,0);
3806
3807         DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3808
3809         /* check it's a supported varient */
3810         if (strcmp(str1,"WrLeh") != 0) {
3811                 return False;
3812         }
3813         if (uLevel != 0 || strcmp(str2,"B9") != 0) {
3814                 return False;
3815         }
3816
3817         if (mdrcnt > 0) {
3818                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3819                 if (!*rdata) {
3820                         return False;
3821                 }
3822         }
3823         memset((char *)&desc,'\0',sizeof(desc));
3824         desc.base = *rdata;
3825         desc.buflen = mdrcnt;
3826         desc.format = str2;
3827         if (init_package(&desc,1,0)) {
3828                 PACKS(&desc,"B13","lp0");
3829         }
3830
3831         succnt = (desc.errcode == NERR_Success ? 1 : 0);
3832
3833         *rdata_len = desc.usedlen;
3834
3835         *rparam_len = 8;
3836         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3837         if (!*rparam) {
3838                 return False;
3839         }
3840         SSVALS(*rparam,0,desc.errcode);
3841         SSVAL(*rparam,2,0);
3842         SSVAL(*rparam,4,succnt);
3843         SSVAL(*rparam,6,1);
3844
3845         DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3846
3847         return True;
3848 }
3849
3850
3851 /****************************************************************************
3852  List open sessions
3853  ****************************************************************************/
3854 static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param, char *data,
3855                                int mdrcnt,int mprcnt,
3856                                char **rdata,char **rparam,
3857                                int *rdata_len,int *rparam_len)
3858
3859 {
3860         char *str1 = param+2;
3861         char *str2 = skip_string(str1,1);
3862         char *p = skip_string(str2,1);
3863         int uLevel;
3864         struct pack_desc desc;
3865         struct sessionid *session_list;
3866         int i, num_sessions;
3867
3868         memset((char *)&desc,'\0',sizeof(desc));
3869
3870         uLevel = SVAL(p,0);
3871
3872         DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
3873         DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
3874         DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
3875
3876         /* check it's a supported varient */
3877         if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
3878                 return False;
3879         }
3880         if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
3881                 return False;
3882         }
3883
3884         num_sessions = list_sessions(&session_list);
3885
3886         if (mdrcnt > 0) {
3887                 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3888                 if (!*rdata) {
3889                         return False;
3890                 }
3891         }
3892         memset((char *)&desc,'\0',sizeof(desc));
3893         desc.base = *rdata;
3894         desc.buflen = mdrcnt;
3895         desc.format = str2;
3896         if (!init_package(&desc,num_sessions,0)) {
3897                 return False;
3898         }
3899
3900         for(i=0; i<num_sessions; i++) {
3901                 PACKS(&desc, "z", session_list[i].remote_machine);
3902                 PACKS(&desc, "z", session_list[i].username);
3903                 PACKI(&desc, "W", 1); /* num conns */
3904                 PACKI(&desc, "W", 0); /* num opens */
3905                 PACKI(&desc, "W", 1); /* num users */
3906                 PACKI(&desc, "D", 0); /* session time */
3907                 PACKI(&desc, "D", 0); /* idle time */
3908                 PACKI(&desc, "D", 0); /* flags */
3909                 PACKS(&desc, "z", "Unknown Client"); /* client type string */
3910         }
3911
3912         *rdata_len = desc.usedlen;
3913
3914         *rparam_len = 8;
3915         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3916         if (!*rparam) {
3917                 return False;
3918         }
3919         SSVALS(*rparam,0,desc.errcode);
3920         SSVAL(*rparam,2,0); /* converter */
3921         SSVAL(*rparam,4,num_sessions); /* count */
3922
3923         DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
3924
3925         return True;
3926 }
3927
3928
3929 /****************************************************************************
3930  The buffer was too small.
3931  ****************************************************************************/
3932
3933 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
3934                          int mdrcnt, int mprcnt,
3935                          char **rdata, char **rparam,
3936                          int *rdata_len, int *rparam_len)
3937 {
3938         *rparam_len = MIN(*rparam_len,mprcnt);
3939         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3940         if (!*rparam) {
3941                 return False;
3942         }
3943
3944         *rdata_len = 0;
3945
3946         SSVAL(*rparam,0,NERR_BufTooSmall);
3947
3948         DEBUG(3,("Supplied buffer too small in API command\n"));
3949
3950         return True;
3951 }
3952
3953 /****************************************************************************
3954  The request is not supported.
3955  ****************************************************************************/
3956
3957 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid, char *param, char *data,
3958                             int mdrcnt, int mprcnt,
3959                             char **rdata, char **rparam,
3960                             int *rdata_len, int *rparam_len)
3961 {
3962         *rparam_len = 4;
3963         *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3964         if (!*rparam) {
3965                 return False;
3966         }
3967
3968         *rdata_len = 0;
3969
3970         SSVAL(*rparam,0,NERR_notsupported);
3971         SSVAL(*rparam,2,0);             /* converter word */
3972
3973         DEBUG(3,("Unsupported API command\n"));
3974
3975         return True;
3976 }
3977
3978 static const struct {
3979         const char *name;
3980         int id;
3981         BOOL (*fn)(connection_struct *,uint16,char *,char *,
3982                         int,int,char **,char **,int *,int *);
3983         BOOL auth_user;         /* Deny anonymous access? */
3984 } api_commands[] = {
3985         {"RNetShareEnum",       RAP_WshareEnum,         api_RNetShareEnum, True},
3986         {"RNetShareGetInfo",    RAP_WshareGetInfo,      api_RNetShareGetInfo},
3987         {"RNetShareAdd",        RAP_WshareAdd,          api_RNetShareAdd},
3988         {"RNetSessionEnum",     RAP_WsessionEnum,       api_RNetSessionEnum, True},
3989         {"RNetServerGetInfo",   RAP_WserverGetInfo,     api_RNetServerGetInfo},
3990         {"RNetGroupEnum",       RAP_WGroupEnum,         api_RNetGroupEnum, True},
3991         {"RNetGroupGetUsers", RAP_WGroupGetUsers,       api_RNetGroupGetUsers, True},
3992         {"RNetUserEnum",        RAP_WUserEnum,          api_RNetUserEnum, True},
3993         {"RNetUserGetInfo",     RAP_WUserGetInfo,       api_RNetUserGetInfo},
3994         {"NetUserGetGroups",    RAP_WUserGetGroups,     api_NetUserGetGroups},
3995         {"NetWkstaGetInfo",     RAP_WWkstaGetInfo,      api_NetWkstaGetInfo},
3996         {"DosPrintQEnum",       RAP_WPrintQEnum,        api_DosPrintQEnum, True},
3997         {"DosPrintQGetInfo",    RAP_WPrintQGetInfo,     api_DosPrintQGetInfo},
3998         {"WPrintQueuePause",  RAP_WPrintQPause, api_WPrintQueueCtrl},
3999         {"WPrintQueueResume", RAP_WPrintQContinue,      api_WPrintQueueCtrl},
4000         {"WPrintJobEnumerate",RAP_WPrintJobEnum,        api_WPrintJobEnumerate},
4001         {"WPrintJobGetInfo",    RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo},
4002         {"RDosPrintJobDel",     RAP_WPrintJobDel,       api_RDosPrintJobDel},
4003         {"RDosPrintJobPause",   RAP_WPrintJobPause,     api_RDosPrintJobDel},
4004         {"RDosPrintJobResume",RAP_WPrintJobContinue,    api_RDosPrintJobDel},
4005         {"WPrintDestEnum",      RAP_WPrintDestEnum,     api_WPrintDestEnum},
4006         {"WPrintDestGetInfo",   RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo},
4007         {"NetRemoteTOD",        RAP_NetRemoteTOD,       api_NetRemoteTOD},
4008         {"WPrintQueuePurge",    RAP_WPrintQPurge,       api_WPrintQueueCtrl},
4009         {"NetServerEnum",       RAP_NetServerEnum2,     api_RNetServerEnum}, /* anon OK */
4010         {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4011         {"SetUserPassword",     RAP_WUserPasswordSet2,  api_SetUserPassword},
4012         {"WWkstaUserLogon",     RAP_WWkstaUserLogon,    api_WWkstaUserLogon},
4013         {"PrintJobInfo",        RAP_WPrintJobSetInfo,   api_PrintJobInfo},
4014         {"WPrintDriverEnum",    RAP_WPrintDriverEnum,   api_WPrintDriverEnum},
4015         {"WPrintQProcEnum",     RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4016         {"WPrintPortEnum",      RAP_WPrintPortEnum,     api_WPrintPortEnum},
4017         {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4018         {NULL,          -1,     api_Unsupported}
4019         /*  The following RAP calls are not implemented by Samba:
4020
4021         RAP_WFileEnum2 - anon not OK 
4022         */
4023 };
4024
4025
4026 /****************************************************************************
4027  Handle remote api calls
4028  ****************************************************************************/
4029
4030 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
4031                      int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
4032 {
4033         int api_command;
4034         char *rdata = NULL;
4035         char *rparam = NULL;
4036         int rdata_len = 0;
4037         int rparam_len = 0;
4038         BOOL reply=False;
4039         int i;
4040
4041         if (!params) {
4042                 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4043                 return 0;
4044         }
4045
4046         api_command = SVAL(params,0);
4047
4048         DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4049                 api_command,
4050                 params+2,
4051                 skip_string(params+2,1),
4052                 tdscnt,tpscnt,mdrcnt,mprcnt));
4053
4054         for (i=0;api_commands[i].name;i++) {
4055                 if (api_commands[i].id == api_command && api_commands[i].fn) {
4056                         DEBUG(3,("Doing %s\n",api_commands[i].name));
4057                         break;
4058                 }
4059         }
4060
4061         /* Check whether this api call can be done anonymously */
4062
4063         if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4064                 user_struct *user = get_valid_user_struct(vuid);
4065
4066                 if (!user || user->guest) {
4067                         return ERROR_NT(NT_STATUS_ACCESS_DENIED);
4068                 }
4069         }
4070
4071         rdata = (char *)SMB_MALLOC(1024);
4072         if (rdata) {
4073                 memset(rdata,'\0',1024);
4074         }
4075
4076         rparam = (char *)SMB_MALLOC(1024);
4077         if (rparam) {
4078                 memset(rparam,'\0',1024);
4079         }
4080
4081         if(!rdata || !rparam) {
4082                 DEBUG(0,("api_reply: malloc fail !\n"));
4083                 SAFE_FREE(rdata);
4084                 SAFE_FREE(rparam);
4085                 return -1;
4086         }
4087
4088         reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
4089                                 &rdata,&rparam,&rdata_len,&rparam_len);
4090
4091
4092         if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4093                 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4094                                         &rdata,&rparam,&rdata_len,&rparam_len);
4095         }
4096
4097         /* if we get False back then it's actually unsupported */
4098         if (!reply) {
4099                 reply = api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
4100                         &rdata,&rparam,&rdata_len,&rparam_len);
4101         }
4102
4103         /* If api_Unsupported returns false we can't return anything. */
4104         if (reply) {
4105                 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
4106         }
4107
4108         SAFE_FREE(rdata);
4109         SAFE_FREE(rparam);
4110         return -1;
4111 }