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