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