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