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