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