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