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