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