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