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