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