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