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