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