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