libcli/security Provide a common, top level libcli/security/security.h
[kai/samba.git] / source3 / smbd / lanman.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Inter-process communication and named pipe handling
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison 2007.
6
7    SMB Version handling
8    Copyright (C) John H Terpstra 1995-1998
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22    */
23 /*
24    This file handles the named pipe and mailslot calls
25    in the SMBtrans protocol
26    */
27
28 #include "includes.h"
29 #include "smbd/globals.h"
30 #include "../librpc/gen_ndr/cli_samr.h"
31 #include "../librpc/gen_ndr/cli_spoolss.h"
32 #include "rpc_client/cli_spoolss.h"
33 #include "rpc_client/init_spoolss.h"
34 #include "../librpc/gen_ndr/cli_srvsvc.h"
35 #include "../librpc/gen_ndr/srv_samr.h"
36 #include "../librpc/gen_ndr/srv_srvsvc.h"
37 #include "../librpc/gen_ndr/rap.h"
38 #include "../lib/util/binsearch.h"
39 #include "../libcli/auth/libcli_auth.h"
40 #include "rpc_client/init_lsa.h"
41 #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<