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