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