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