Wrap the unix token info in a unix_user_token in auth_serversupplied_info
[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
30 extern struct current_user current_user;
31
32 #ifdef CHECK_TYPES
33 #undef CHECK_TYPES
34 #endif
35 #define CHECK_TYPES 0
36
37 #define NERR_Success 0
38 #define NERR_badpass 86
39 #define NERR_notsupported 50
40
41 #define NERR_BASE (2100)
42 #define NERR_BufTooSmall (NERR_BASE+23)
43 #define NERR_JobNotFound (NERR_BASE+51)
44 #define NERR_DestNotFound (NERR_BASE+52)
45
46 #define ACCESS_READ 0x01
47 #define ACCESS_WRITE 0x02
48 #define ACCESS_CREATE 0x04
49
50 #define SHPWLEN 8               /* share password length */
51
52 /* Limit size of ipc replies */
53
54 static char *smb_realloc_limit(void *ptr, size_t size)
55 {
56         char *val;
57
58         size = MAX((size),4*1024);
59         val = (char *)SMB_REALLOC(ptr,size);
60         if (val) {
61                 memset(val,'\0',size);
62         }
63         return val;
64 }
65
66 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
67                                 char *param, int tpscnt,
68                                 char *data, int tdscnt,
69                                 int mdrcnt, int mprcnt,
70                                 char **rdata, char **rparam,
71                                 int *rdata_len, int *rparam_len);
72
73 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
74                          int mdrcnt, int mprcnt,
75                          char **rdata, char **rparam,
76                          int *rdata_len, int *rparam_len);
77
78
79 static int CopyExpanded(connection_struct *conn,
80                         int snum, char **dst, char *src, int *p_space_remaining)
81 {
82         TALLOC_CTX *ctx = talloc_tos();
83         char *buf = NULL;
84         int l;
85
86         if (!src || !dst || !p_space_remaining || !(*dst) ||
87                         *p_space_remaining <= 0) {
88                 return 0;
89         }
90
91         buf = talloc_strdup(ctx, src);
92         if (!buf) {
93                 *p_space_remaining = 0;
94                 return 0;
95         }
96         buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
97         if (!buf) {
98                 *p_space_remaining = 0;
99                 return 0;
100         }
101         buf = talloc_sub_advanced(ctx,
102                                 lp_servicename(SNUM(conn)),
103                                 conn->server_info->unix_name,
104                                 conn->connectpath,
105                                 conn->server_info->utok.gid,
106                                 conn->server_info->sanitized_username,
107                                 pdb_get_domain(conn->server_info->sam_account),
108                                 buf);
109         if (!buf) {
110                 *p_space_remaining = 0;
111                 return 0;
112         }
113         l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
114         if (l == -1) {
115                 return 0;
116         }
117         (*dst) += l;
118         (*p_space_remaining) -= l;
119         return l;
120 }
121
122 static int CopyAndAdvance(char **dst, char *src, int *n)
123 {
124         int l;
125         if (!src || !dst || !n || !(*dst)) {
126                 return 0;
127         }
128         l = push_ascii(*dst,src,*n, STR_TERMINATE);
129         if (l == -1) {
130                 return 0;
131         }
132         (*dst) += l;
133         (*n) -= l;
134         return l;
135 }
136
137 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
138 {
139         TALLOC_CTX *ctx = talloc_tos();
140         char *buf = NULL;
141         if (!s) {
142                 return 0;
143         }
144         buf = talloc_strdup(ctx,s);
145         if (!buf) {
146                 return 0;
147         }
148         buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
149         if (!buf) {
150                 return 0;
151         }
152         buf = talloc_sub_advanced(ctx,
153                                 lp_servicename(SNUM(conn)),
154                                 conn->server_info->unix_name,
155                                 conn->connectpath,
156                                 conn->server_info->utok.gid,
157                                 conn->server_info->sanitized_username,
158                                 pdb_get_domain(conn->server_info->sam_account),
159                                 buf);
160         if (!buf) {
161                 return 0;
162         }
163         return strlen(buf) + 1;
164 }
165
166 static char *Expand(connection_struct *conn, int snum, char *s)
167 {
168         TALLOC_CTX *ctx = talloc_tos();
169         char *buf = NULL;
170
171         if (!s) {
172                 return NULL;
173         }
174         buf = talloc_strdup(ctx,s);
175         if (!buf) {
176                 return 0;
177         }
178         buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
179         if (!buf) {
180                 return 0;
181         }
182         return talloc_sub_advanced(ctx,
183                                 lp_servicename(SNUM(conn)),
184                                 conn->server_info->unix_name,
185                                 conn->connectpath,
186                                 conn->server_info->utok.gid,
187                                 conn->server_info->sanitized_username,
188                                 pdb_get_domain(conn->server_info->sam_account),
189                                 buf);
190 }
191
192 /*******************************************************************
193  Check a API string for validity when we only need to check the prefix.
194 ******************************************************************/
195
196 static bool prefix_ok(const char *str, const char *prefix)
197 {
198         return(strncmp(str,prefix,strlen(prefix)) == 0);
199 }
200
201 struct pack_desc {
202         const char *format;         /* formatstring for structure */
203         const char *subformat;  /* subformat for structure */
204         char *base;         /* baseaddress of buffer */
205         int buflen;        /* remaining size for fixed part; on init: length of base */
206         int subcount;       /* count of substructures */
207         char *structbuf;  /* pointer into buffer for remaining fixed part */
208         int stringlen;    /* remaining size for variable part */                
209         char *stringbuf;  /* pointer into buffer for remaining variable part */
210         int neededlen;    /* total needed size */
211         int usedlen;        /* total used size (usedlen <= neededlen and usedlen <= buflen) */
212         const char *curpos;         /* current position; pointer into format or subformat */
213         int errcode;
214 };
215
216 static int get_counter(const char **p)
217 {
218         int i, n;
219         if (!p || !(*p)) {
220                 return 1;
221         }
222         if (!isdigit((int)**p)) {
223                 return 1;
224         }
225         for (n = 0;;) {
226                 i = **p;
227                 if (isdigit(i)) {
228                         n = 10 * n + (i - '0');
229                 } else {
230                         return n;
231                 }
232                 (*p)++;
233         }
234 }
235
236 static int getlen(const char *p)
237 {
238         int n = 0;
239         if (!p) {
240                 return 0;
241         }
242
243         while (*p) {
244                 switch( *p++ ) {
245                 case 'W':                       /* word (2 byte) */
246                         n += 2;
247                         break;
248                 case 'K':                       /* status word? (2 byte) */
249                         n += 2;
250                         break;
251                 case 'N':                       /* count of substructures (word) at end */
252                         n += 2;
253                         break;
254                 case 'D':                       /* double word (4 byte) */
255                 case 'z':                       /* offset to zero terminated string (4 byte) */
256                 case 'l':                       /* offset to user data (4 byte) */
257                         n += 4;
258                         break;
259                 case 'b':                       /* offset to data (with counter) (4 byte) */
260                         n += 4;
261                         get_counter(&p);
262                         break;
263                 case 'B':                       /* byte (with optional counter) */
264                         n += get_counter(&p);
265                         break;
266                 }
267         }
268         return n;
269 }
270
271 static bool init_package(struct pack_desc *p, int count, int subcount)
272 {
273         int n = p->buflen;
274         int i;
275
276         if (!p->format || !p->base) {
277                 return False;
278         }
279
280         i = count * getlen(p->format);
281         if (p->subformat) {
282                 i += subcount * getlen(p->subformat);
283         }
284         p->structbuf = p->base;
285         p->neededlen = 0;
286         p->usedlen = 0;
287         p->subcount = 0;
288         p->curpos = p->format;
289         if (i > n) {
290                 p->neededlen = i;
291                 i = n = 0;
292 #if 0
293                 /*
294                  * This is the old error code we used. Aparently
295                  * WinNT/2k systems return ERRbuftoosmall (2123) and
296                  * OS/2 needs this. I'm leaving this here so we can revert
297                  * if needed. JRA.
298                  */
299                 p->errcode = ERRmoredata;
300 #else
301                 p->errcode = ERRbuftoosmall;
302 #endif
303         } else {
304                 p->errcode = NERR_Success;
305         }
306         p->buflen = i;
307         n -= i;
308         p->stringbuf = p->base + i;
309         p->stringlen = n;
310         return (p->errcode == NERR_Success);
311 }
312
313 static int package(struct pack_desc *p, ...)
314 {
315         va_list args;
316         int needed=0, stringneeded;
317         const char *str=NULL;
318         int is_string=0, stringused;
319         int32 temp;
320
321         va_start(args,p);
322
323         if (!*p->curpos) {
324                 if (!p->subcount) {
325                         p->curpos = p->format;
326                 } else {
327                         p->curpos = p->subformat;
328                         p->subcount--;
329                 }
330         }
331 #if CHECK_TYPES
332         str = va_arg(args,char*);
333         SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
334 #endif
335         stringneeded = -1;
336
337         if (!p->curpos) {
338                 va_end(args);
339                 return 0;
340         }
341
342         switch( *p->curpos++ ) {
343                 case 'W':                       /* word (2 byte) */
344                         needed = 2;
345                         temp = va_arg(args,int);
346                         if (p->buflen >= needed) {
347                                 SSVAL(p->structbuf,0,temp);
348                         }
349                         break;
350                 case 'K':                       /* status word? (2 byte) */
351                         needed = 2;
352                         temp = va_arg(args,int);
353                         if (p->buflen >= needed) {
354                                 SSVAL(p->structbuf,0,temp);
355                         }
356                         break;
357                 case 'N':                       /* count of substructures (word) at end */
358                         needed = 2;
359                         p->subcount = va_arg(args,int);
360                         if (p->buflen >= needed) {
361                                 SSVAL(p->structbuf,0,p->subcount);
362                         }
363                         break;
364                 case 'D':                       /* double word (4 byte) */
365                         needed = 4;
366                         temp = va_arg(args,int);
367                         if (p->buflen >= needed) {
368                                 SIVAL(p->structbuf,0,temp);
369                         }
370                         break;
371                 case 'B':                       /* byte (with optional counter) */
372                         needed = get_counter(&p->curpos);
373                         {
374                                 char *s = va_arg(args,char*);
375                                 if (p->buflen >= needed) {
376                                         StrnCpy(p->structbuf,s?s:"",needed-1);
377                                 }
378                         }
379                         break;
380                 case 'z':                       /* offset to zero terminated string (4 byte) */
381                         str = va_arg(args,char*);
382                         stringneeded = (str ? strlen(str)+1 : 0);
383                         is_string = 1;
384                         break;
385                 case 'l':                       /* offset to user data (4 byte) */
386                         str = va_arg(args,char*);
387                         stringneeded = va_arg(args,int);
388                         is_string = 0;
389                         break;
390                 case 'b':                       /* offset to data (with counter) (4 byte) */
391                         str = va_arg(args,char*);
392                         stringneeded = get_counter(&p->curpos);
393                         is_string = 0;
394                         break;
395         }
396
397         va_end(args);
398         if (stringneeded >= 0) {
399                 needed = 4;
400                 if (p->buflen >= needed) {
401                         stringused = stringneeded;
402                         if (stringused > p->stringlen) {
403                                 stringused = (is_string ? p->stringlen : 0);
404                                 if (p->errcode == NERR_Success) {
405                                         p->errcode = ERRmoredata;
406                                 }
407                         }
408                         if (!stringused) {
409                                 SIVAL(p->structbuf,0,0);
410                         } else {
411                                 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
412                                 memcpy(p->stringbuf,str?str:"",stringused);
413                                 if (is_string) {
414                                         p->stringbuf[stringused-1] = '\0';
415                                 }
416                                 p->stringbuf += stringused;
417                                 p->stringlen -= stringused;
418                                 p->usedlen += stringused;
419                         }
420                 }
421                 p->neededlen += stringneeded;
422         }
423
424         p->neededlen += needed;
425         if (p->buflen >= needed) {
426                 p->structbuf += needed;
427                 p->buflen -= needed;
428                 p->usedlen += needed;
429         } else {
430                 if (p->errcode == NERR_Success) {
431                         p->errcode = ERRmoredata;
432                 }
433         }
434         return 1;
435 }
436
437 #if CHECK_TYPES
438 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
439 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
440 #else
441 #define PACK(desc,t,v) package(desc,v)
442 #define PACKl(desc,t,v,l) package(desc,v,l)
443 #endif
444
445 static void PACKI(struct pack_desc* desc, const char *t,int v)
446 {
447         PACK(desc,t,v);
448 }
449
450 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
451 {
452         PACK(desc,t,v);
453 }
454
455 /****************************************************************************
456  Get a print queue.
457 ****************************************************************************/
458
459 static void PackDriverData(struct pack_desc* desc)
460 {
461         char drivdata[4+4+32];
462         SIVAL(drivdata,0,sizeof drivdata); /* cb */
463         SIVAL(drivdata,4,1000); /* lVersion */
464         memset(drivdata+8,0,32);        /* szDeviceName */
465         push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
466         PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
467 }
468
469 static int check_printq_info(struct pack_desc* desc,
470                                 unsigned int uLevel, char *id1, char *id2)
471 {
472         desc->subformat = NULL;
473         switch( uLevel ) {
474                 case 0:
475                         desc->format = "B13";
476                         break;
477                 case 1:
478                         desc->format = "B13BWWWzzzzzWW";
479                         break;
480                 case 2:
481                         desc->format = "B13BWWWzzzzzWN";
482                         desc->subformat = "WB21BB16B10zWWzDDz";
483                         break;
484                 case 3:
485                         desc->format = "zWWWWzzzzWWzzl";
486                         break;
487                 case 4:
488                         desc->format = "zWWWWzzzzWNzzl";
489                         desc->subformat = "WWzWWDDzz";
490                         break;
491                 case 5:
492                         desc->format = "z";
493                         break;
494                 case 51:
495                         desc->format = "K";
496                         break;
497                 case 52:
498                         desc->format = "WzzzzzzzzN";
499                         desc->subformat = "z";
500                         break;
501                 default:
502                         DEBUG(0,("check_printq_info: invalid level %d\n",
503                                 uLevel ));
504                         return False;
505         }
506         if (id1 == NULL || strcmp(desc->format,id1) != 0) {
507                 DEBUG(0,("check_printq_info: invalid format %s\n",
508                         id1 ? id1 : "<NULL>" ));
509                 return False;
510         }
511         if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
512                 DEBUG(0,("check_printq_info: invalid subformat %s\n",
513                         id2 ? id2 : "<NULL>" ));
514                 return False;
515         }
516         return True;
517 }
518
519
520 #define RAP_JOB_STATUS_QUEUED 0
521 #define RAP_JOB_STATUS_PAUSED 1
522 #define RAP_JOB_STATUS_SPOOLING 2
523 #define RAP_JOB_STATUS_PRINTING 3
524 #define RAP_JOB_STATUS_PRINTED 4
525
526 #define RAP_QUEUE_STATUS_PAUSED 1
527 #define RAP_QUEUE_STATUS_ERROR 2
528
529 /* turn a print job status into a on the wire status 
530 */
531 static int printj_status(int v)
532 {
533         switch (v) {
534         case LPQ_QUEUED:
535                 return RAP_JOB_STATUS_QUEUED;
536         case LPQ_PAUSED:
537                 return RAP_JOB_STATUS_PAUSED;
538         case LPQ_SPOOLING:
539                 return RAP_JOB_STATUS_SPOOLING;
540         case LPQ_PRINTING:
541                 return RAP_JOB_STATUS_PRINTING;
542         }
543         return 0;
544 }
545
546 /* turn a print queue status into a on the wire status 
547 */
548 static int printq_status(int v)
549 {
550         switch (v) {
551         case LPQ_QUEUED:
552                 return 0;
553         case LPQ_PAUSED:
554                 return RAP_QUEUE_STATUS_PAUSED;
555         }
556         return RAP_QUEUE_STATUS_ERROR;
557 }
558
559 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
560                                struct pack_desc *desc,
561                                print_queue_struct *queue, int n)
562 {
563         time_t t = queue->time;
564
565         /* the client expects localtime */
566         t -= get_time_zone(t);
567
568         PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
569         if (uLevel == 1) {
570                 PACKS(desc,"B21",queue->fs_user); /* szUserName */
571                 PACKS(desc,"B","");             /* pad */
572                 PACKS(desc,"B16","");   /* szNotifyName */
573                 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
574                 PACKS(desc,"z","");             /* pszParms */
575                 PACKI(desc,"W",n+1);            /* uPosition */
576                 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
577                 PACKS(desc,"z","");             /* pszStatus */
578                 PACKI(desc,"D",t); /* ulSubmitted */
579                 PACKI(desc,"D",queue->size); /* ulSize */
580                 PACKS(desc,"z",queue->fs_file); /* pszComment */
581         }
582         if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
583                 PACKI(desc,"W",queue->priority);                /* uPriority */
584                 PACKS(desc,"z",queue->fs_user); /* pszUserName */
585                 PACKI(desc,"W",n+1);            /* uPosition */
586                 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
587                 PACKI(desc,"D",t); /* ulSubmitted */
588                 PACKI(desc,"D",queue->size); /* ulSize */
589                 PACKS(desc,"z","Samba");        /* pszComment */
590                 PACKS(desc,"z",queue->fs_file); /* pszDocument */
591                 if (uLevel == 3) {
592                         PACKS(desc,"z","");     /* pszNotifyName */
593                         PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
594                         PACKS(desc,"z","");     /* pszParms */
595                         PACKS(desc,"z","");     /* pszStatus */
596                         PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
597                         PACKS(desc,"z","lpd");  /* pszQProcName */
598                         PACKS(desc,"z","");     /* pszQProcParms */
599                         PACKS(desc,"z","NULL"); /* pszDriverName */
600                         PackDriverData(desc);   /* pDriverData */
601                         PACKS(desc,"z","");     /* pszPrinterName */
602                 } else if (uLevel == 4) {   /* OS2 */
603                         PACKS(desc,"z","");       /* pszSpoolFileName  */
604                         PACKS(desc,"z","");       /* pszPortName       */
605                         PACKS(desc,"z","");       /* pszStatus         */
606                         PACKI(desc,"D",0);        /* ulPagesSpooled    */
607                         PACKI(desc,"D",0);        /* ulPagesSent       */
608                         PACKI(desc,"D",0);        /* ulPagesPrinted    */
609                         PACKI(desc,"D",0);        /* ulTimePrinted     */
610                         PACKI(desc,"D",0);        /* ulExtendJobStatus */
611                         PACKI(desc,"D",0);        /* ulStartPage       */
612                         PACKI(desc,"D",0);        /* ulEndPage         */
613                 }
614         }
615 }
616
617 /********************************************************************
618  Return a driver name given an snum.
619  Returns True if from tdb, False otherwise.
620  ********************************************************************/
621
622 static bool get_driver_name(int snum, char **pp_drivername)
623 {
624         NT_PRINTER_INFO_LEVEL *info = NULL;
625         bool in_tdb = false;
626
627         get_a_printer (NULL, &info, 2, lp_servicename(snum));
628         if (info != NULL) {
629                 *pp_drivername = talloc_strdup(talloc_tos(),
630                                         info->info_2->drivername);
631                 in_tdb = true;
632                 free_a_printer(&info, 2);
633                 if (!*pp_drivername) {
634                         return false;
635                 }
636         }
637
638         return in_tdb;
639 }
640
641 /********************************************************************
642  Respond to the DosPrintQInfo command with a level of 52
643  This is used to get printer driver information for Win9x clients
644  ********************************************************************/
645 static void fill_printq_info_52(connection_struct *conn, int snum, 
646                                 struct pack_desc* desc, int count )
647 {
648         int                             i;
649         fstring                         location;
650         NT_PRINTER_DRIVER_INFO_LEVEL    driver;
651         NT_PRINTER_INFO_LEVEL           *printer = NULL;
652
653         ZERO_STRUCT(driver);
654
655         if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
656                 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n", 
657                         lp_servicename(snum)));
658                 goto err;
659         }
660
661         if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, 
662                 "Windows 4.0", 0)) )
663         {
664                 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n", 
665                         printer->info_2->drivername));
666                 goto err;
667         }
668
669         trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
670         trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
671         trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
672
673         PACKI(desc, "W", 0x0400);                     /* don't know */
674         PACKS(desc, "z", driver.info_3->name);        /* long printer name */
675         PACKS(desc, "z", driver.info_3->driverpath);  /* Driverfile Name */
676         PACKS(desc, "z", driver.info_3->datafile);    /* Datafile name */
677         PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
678
679         fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
680         standard_sub_basic( "", "", location, sizeof(location)-1 );
681         PACKS(desc,"z", location);                          /* share to retrieve files */
682
683         PACKS(desc,"z", driver.info_3->defaultdatatype);    /* default data type */
684         PACKS(desc,"z", driver.info_3->helpfile);           /* helpfile name */
685         PACKS(desc,"z", driver.info_3->driverpath);               /* driver name */
686
687         DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
688         DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
689         DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
690         DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
691         DEBUG(3,("Driver Location: %s:\n",location));
692         DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
693         DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
694         PACKI(desc,"N",count);                     /* number of files to copy */
695
696         for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++) 
697         {
698                 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
699                 PACKS(desc,"z",driver.info_3->dependentfiles[i]);         /* driver files to copy */
700                 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
701         }
702
703         /* sanity check */
704         if ( i != count )
705                 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
706                         count, i));
707
708         DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
709
710         desc->errcode=NERR_Success;
711         goto done;
712
713 err:
714         DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
715         desc->errcode=NERR_notsupported;
716
717 done:
718         if ( printer )
719                 free_a_printer( &printer, 2 );
720
721         if ( driver.info_3 )
722                 free_a_printer_driver( driver, 3 );
723 }
724
725
726 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
727                              struct pack_desc* desc,
728                              int count, print_queue_struct* queue,
729                              print_status_struct* status)
730 {
731         switch (uLevel) {
732         case 1:
733         case 2:
734                 PACKS(desc,"B13",SERVICE(snum));
735                 break;
736         case 3:
737         case 4:
738         case 5:
739                 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
740                 break;
741         case 51:
742                 PACKI(desc,"K",printq_status(status->status));
743                 break;
744         }
745
746         if (uLevel == 1 || uLevel == 2) {
747                 PACKS(desc,"B","");             /* alignment */
748                 PACKI(desc,"W",5);              /* priority */
749                 PACKI(desc,"W",0);              /* start time */
750                 PACKI(desc,"W",0);              /* until time */
751                 PACKS(desc,"z","");             /* pSepFile */
752                 PACKS(desc,"z","lpd");  /* pPrProc */
753                 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
754                 PACKS(desc,"z","");             /* pParms */
755                 if (snum < 0) {
756                         PACKS(desc,"z","UNKNOWN PRINTER");
757                         PACKI(desc,"W",LPSTAT_ERROR);
758                 }
759                 else if (!status || !status->message[0]) {
760                         PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
761                         PACKI(desc,"W",LPSTAT_OK); /* status */
762                 } else {
763                         PACKS(desc,"z",status->message);
764                         PACKI(desc,"W",printq_status(status->status)); /* status */
765                 }
766                 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
767         }
768
769         if (uLevel == 3 || uLevel == 4) {
770                 char *drivername = NULL;
771
772                 PACKI(desc,"W",5);              /* uPriority */
773                 PACKI(desc,"W",0);              /* uStarttime */
774                 PACKI(desc,"W",0);              /* uUntiltime */
775                 PACKI(desc,"W",5);              /* pad1 */
776                 PACKS(desc,"z","");             /* pszSepFile */
777                 PACKS(desc,"z","WinPrint");     /* pszPrProc */
778                 PACKS(desc,"z",NULL);           /* pszParms */
779                 PACKS(desc,"z",NULL);           /* pszComment - don't ask.... JRA */
780                 /* "don't ask" that it's done this way to fix corrupted
781                    Win9X/ME printer comments. */
782                 if (!status) {
783                         PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
784                 } else {
785                         PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
786                 }
787                 PACKI(desc,(uLevel == 3 ? "W" : "N"),count);    /* cJobs */
788                 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
789                 get_driver_name(snum,&drivername);
790                 if (!drivername) {
791                         return;
792                 }
793                 PACKS(desc,"z",drivername);             /* pszDriverName */
794                 PackDriverData(desc);   /* pDriverData */
795         }
796
797         if (uLevel == 2 || uLevel == 4) {
798                 int i;
799                 for (i=0;i<count;i++)
800                         fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
801         }
802
803         if (uLevel==52)
804                 fill_printq_info_52( conn, snum, desc, count );
805 }
806
807 /* This function returns the number of files for a given driver */
808 static int get_printerdrivernumber(int snum)
809 {
810         int                             result = 0;
811         NT_PRINTER_DRIVER_INFO_LEVEL    driver;
812         NT_PRINTER_INFO_LEVEL           *printer = NULL;
813
814         ZERO_STRUCT(driver);
815
816         if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
817                 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n", 
818                         lp_servicename(snum)));
819                 goto done;
820         }
821
822         if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, 
823                 "Windows 4.0", 0)) )
824         {
825                 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n", 
826                         printer->info_2->drivername));
827                 goto done;
828         }
829
830         /* count the number of files */
831         while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
832                         result++;
833                         \
834  done:
835         if ( printer )
836                 free_a_printer( &printer, 2 );
837
838         if ( driver.info_3 )
839                 free_a_printer_driver( driver, 3 );
840
841         return result;
842 }
843
844 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
845                                 char *param, int tpscnt,
846                                 char *data, int tdscnt,
847                                 int mdrcnt,int mprcnt,
848                                 char **rdata,char **rparam,
849                                 int *rdata_len,int *rparam_len)
850 {
851         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
852         char *str2 = skip_string(param,tpscnt,str1);
853         char *p = skip_string(param,tpscnt,str2);
854         char *QueueName = p;
855         unsigned int uLevel;
856         int count=0;
857         int snum;
858         char *str3;
859         struct pack_desc desc;
860         print_queue_struct *queue=NULL;
861         print_status_struct status;
862         char* tmpdata=NULL;
863
864         if (!str1 || !str2 || !p) {
865                 return False;
866         }
867         memset((char *)&status,'\0',sizeof(status));
868         memset((char *)&desc,'\0',sizeof(desc));
869
870         p = skip_string(param,tpscnt,p);
871         if (!p) {
872                 return False;
873         }
874         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
875         str3 = get_safe_str_ptr(param,tpscnt,p,4);
876         /* str3 may be null here and is checked in check_printq_info(). */
877
878         /* remove any trailing username */
879         if ((p = strchr_m(QueueName,'%')))
880                 *p = 0;
881  
882         DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
883  
884         /* check it's a supported varient */
885         if (!prefix_ok(str1,"zWrLh"))
886                 return False;
887         if (!check_printq_info(&desc,uLevel,str2,str3)) {
888                 /*
889                  * Patch from Scott Moomaw <scott@bridgewater.edu>
890                  * to return the 'invalid info level' error if an
891                  * unknown level was requested.
892                  */
893                 *rdata_len = 0;
894                 *rparam_len = 6;
895                 *rparam = smb_realloc_limit(*rparam,*rparam_len);
896                 if (!*rparam) {
897                         return False;
898                 }
899                 SSVALS(*rparam,0,ERRunknownlevel);
900                 SSVAL(*rparam,2,0);
901                 SSVAL(*rparam,4,0);
902                 return(True);
903         }
904  
905         snum = find_service(QueueName);
906         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
907                 return False;
908                 
909         if (uLevel==52) {
910                 count = get_printerdrivernumber(snum);
911                 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
912         } else {
913                 count = print_queue_status(snum, &queue,&status);
914         }
915
916         if (mdrcnt > 0) {
917                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
918                 if (!*rdata) {
919                         SAFE_FREE(queue);
920                         return False;
921                 }
922                 desc.base = *rdata;
923                 desc.buflen = mdrcnt;
924         } else {
925                 /*
926                  * Don't return data but need to get correct length
927                  * init_package will return wrong size if buflen=0
928                  */
929                 desc.buflen = getlen(desc.format);
930                 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
931         }
932
933         if (init_package(&desc,1,count)) {
934                 desc.subcount = count;
935                 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
936         }
937
938         *rdata_len = desc.usedlen;
939   
940         /*
941          * We must set the return code to ERRbuftoosmall
942          * in order to support lanman style printing with Win NT/2k
943          * clients       --jerry
944          */
945         if (!mdrcnt && lp_disable_spoolss())
946                 desc.errcode = ERRbuftoosmall;
947  
948         *rdata_len = desc.usedlen;
949         *rparam_len = 6;
950         *rparam = smb_realloc_limit(*rparam,*rparam_len);
951         if (!*rparam) {
952                 SAFE_FREE(queue);
953                 SAFE_FREE(tmpdata);
954                 return False;
955         }
956         SSVALS(*rparam,0,desc.errcode);
957         SSVAL(*rparam,2,0);
958         SSVAL(*rparam,4,desc.neededlen);
959   
960         DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
961
962         SAFE_FREE(queue);
963         SAFE_FREE(tmpdata);
964
965         return(True);
966 }
967
968 /****************************************************************************
969  View list of all print jobs on all queues.
970 ****************************************************************************/
971
972 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
973                                 char *param, int tpscnt,
974                                 char *data, int tdscnt,
975                                 int mdrcnt, int mprcnt,
976                                 char **rdata, char** rparam,
977                                 int *rdata_len, int *rparam_len)
978 {
979         char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
980         char *output_format1 = skip_string(param,tpscnt,param_format);
981         char *p = skip_string(param,tpscnt,output_format1);
982         unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
983         char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
984         int services = lp_numservices();
985         int i, n;
986         struct pack_desc desc;
987         print_queue_struct **queue = NULL;
988         print_status_struct *status = NULL;
989         int *subcntarr = NULL;
990         int queuecnt = 0, subcnt = 0, succnt = 0;
991  
992         if (!param_format || !output_format1 || !p) {
993                 return False;
994         }
995
996         memset((char *)&desc,'\0',sizeof(desc));
997
998         DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
999  
1000         if (!prefix_ok(param_format,"WrLeh")) {
1001                 return False;
1002         }
1003         if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1004                 /*
1005                  * Patch from Scott Moomaw <scott@bridgewater.edu>
1006                  * to return the 'invalid info level' error if an
1007                  * unknown level was requested.
1008                  */
1009                 *rdata_len = 0;
1010                 *rparam_len = 6;
1011                 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1012                 if (!*rparam) {
1013                         return False;
1014                 }
1015                 SSVALS(*rparam,0,ERRunknownlevel);
1016                 SSVAL(*rparam,2,0);
1017                 SSVAL(*rparam,4,0);
1018                 return(True);
1019         }
1020
1021         for (i = 0; i < services; i++) {
1022                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1023                         queuecnt++;
1024                 }
1025         }
1026
1027         if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1028                 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1029                 goto err;
1030         }
1031         memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1032         if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1033                 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1034                 goto err;
1035         }
1036         memset(status,0,queuecnt*sizeof(print_status_struct));
1037         if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1038                 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1039                 goto err;
1040         }
1041
1042         subcnt = 0;
1043         n = 0;
1044         for (i = 0; i < services; i++) {
1045                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1046                         subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1047                         subcnt += subcntarr[n];
1048                         n++;
1049                 }
1050         }
1051
1052         if (mdrcnt > 0) {
1053                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1054                 if (!*rdata) {
1055                         goto err;
1056                 }
1057         }
1058         desc.base = *rdata;
1059         desc.buflen = mdrcnt;
1060
1061         if (init_package(&desc,queuecnt,subcnt)) {
1062                 n = 0;
1063                 succnt = 0;
1064                 for (i = 0; i < services; i++) {
1065                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1066                                 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1067                                 n++;
1068                                 if (desc.errcode == NERR_Success) {
1069                                         succnt = n;
1070                                 }
1071                         }
1072                 }
1073         }
1074
1075         SAFE_FREE(subcntarr);
1076  
1077         *rdata_len = desc.usedlen;
1078         *rparam_len = 8;
1079         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1080         if (!*rparam) {
1081                 goto err;
1082         }
1083         SSVALS(*rparam,0,desc.errcode);
1084         SSVAL(*rparam,2,0);
1085         SSVAL(*rparam,4,succnt);
1086         SSVAL(*rparam,6,queuecnt);
1087   
1088         for (i = 0; i < queuecnt; i++) {
1089                 if (queue) {
1090                         SAFE_FREE(queue[i]);
1091                 }
1092         }
1093
1094         SAFE_FREE(queue);
1095         SAFE_FREE(status);
1096   
1097         return True;
1098
1099   err:
1100
1101         SAFE_FREE(subcntarr);
1102         for (i = 0; i < queuecnt; i++) {
1103                 if (queue) {
1104                         SAFE_FREE(queue[i]);
1105                 }
1106         }
1107         SAFE_FREE(queue);
1108         SAFE_FREE(status);
1109
1110         return False;
1111 }
1112
1113 /****************************************************************************
1114  Get info level for a server list query.
1115 ****************************************************************************/
1116
1117 static bool check_server_info(int uLevel, char* id)
1118 {
1119         switch( uLevel ) {
1120                 case 0:
1121                         if (strcmp(id,"B16") != 0) {
1122                                 return False;
1123                         }
1124                         break;
1125                 case 1:
1126                         if (strcmp(id,"B16BBDz") != 0) {
1127                                 return False;
1128                         }
1129                         break;
1130                 default: 
1131                         return False;
1132         }
1133         return True;
1134 }
1135
1136 struct srv_info_struct {
1137         fstring name;
1138         uint32 type;
1139         fstring comment;
1140         fstring domain;
1141         bool server_added;
1142 };
1143
1144 /*******************************************************************
1145  Get server info lists from the files saved by nmbd. Return the
1146  number of entries.
1147 ******************************************************************/
1148
1149 static int get_server_info(uint32 servertype, 
1150                            struct srv_info_struct **servers,
1151                            const char *domain)
1152 {
1153         int count=0;
1154         int alloced=0;
1155         char **lines;
1156         bool local_list_only;
1157         int i;
1158
1159         lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1160         if (!lines) {
1161                 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1162                 return 0;
1163         }
1164
1165         /* request for everything is code for request all servers */
1166         if (servertype == SV_TYPE_ALL) {
1167                 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1168         }
1169
1170         local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1171
1172         DEBUG(4,("Servertype search: %8x\n",servertype));
1173
1174         for (i=0;lines[i];i++) {
1175                 fstring stype;
1176                 struct srv_info_struct *s;
1177                 const char *ptr = lines[i];
1178                 bool ok = True;
1179                 TALLOC_CTX *frame = NULL;
1180                 char *p;
1181
1182                 if (!*ptr) {
1183                         continue;
1184                 }
1185
1186                 if (count == alloced) {
1187                         alloced += 10;
1188                         *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1189                         if (!*servers) {
1190                                 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1191                                 file_lines_free(lines);
1192                                 return 0;
1193                         }
1194                         memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1195                 }
1196                 s = &(*servers)[count];
1197
1198                 frame = talloc_stackframe();
1199                 s->name[0] = '\0';
1200                 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1201                         TALLOC_FREE(frame);
1202                         continue;
1203                 }
1204                 fstrcpy(s->name, p);
1205
1206                 stype[0] = '\0';
1207                 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1208                         TALLOC_FREE(frame);
1209                         continue;
1210                 }
1211                 fstrcpy(stype, p);
1212
1213                 s->comment[0] = '\0';
1214                 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1215                         TALLOC_FREE(frame);
1216                         continue;
1217                 }
1218                 fstrcpy(s->comment, p);
1219
1220                 s->domain[0] = '\0';
1221                 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1222                         /* this allows us to cope with an old nmbd */
1223                         fstrcpy(s->domain,lp_workgroup());
1224                 } else {
1225                         fstrcpy(s->domain, p);
1226                 }
1227                 TALLOC_FREE(frame);
1228
1229                 if (sscanf(stype,"%X",&s->type) != 1) {
1230                         DEBUG(4,("r:host file "));
1231                         ok = False;
1232                 }
1233
1234                 /* Filter the servers/domains we return based on what was asked for. */
1235
1236                 /* Check to see if we are being asked for a local list only. */
1237                 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1238                         DEBUG(4,("r: local list only"));
1239                         ok = False;
1240                 }
1241
1242                 /* doesn't match up: don't want it */
1243                 if (!(servertype & s->type)) {
1244                         DEBUG(4,("r:serv type "));
1245                         ok = False;
1246                 }
1247
1248                 if ((servertype & SV_TYPE_DOMAIN_ENUM) != 
1249                                 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1250                         DEBUG(4,("s: dom mismatch "));
1251                         ok = False;
1252                 }
1253     
1254                 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1255                         ok = False;
1256                 }
1257     
1258                 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1259                 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1260
1261                 if (ok) {
1262                         DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1263                                 s->name, s->type, s->comment, s->domain));
1264                         s->server_added = True;
1265                         count++;
1266                 } else {
1267                         DEBUG(4,("%20s %8x %25s %15s\n",
1268                                 s->name, s->type, s->comment, s->domain));
1269                 }
1270         }
1271   
1272         file_lines_free(lines);
1273         return count;
1274 }
1275
1276 /*******************************************************************
1277  Fill in a server info structure.
1278 ******************************************************************/
1279
1280 static int fill_srv_info(struct srv_info_struct *service, 
1281                          int uLevel, char **buf, int *buflen, 
1282                          char **stringbuf, int *stringspace, char *baseaddr)
1283 {
1284         int struct_len;
1285         char* p;
1286         char* p2;
1287         int l2;
1288         int len;
1289  
1290         switch (uLevel) {
1291                 case 0:
1292                         struct_len = 16;
1293                         break;
1294                 case 1:
1295                         struct_len = 26;
1296                         break;
1297                 default:
1298                         return -1;
1299         }
1300  
1301         if (!buf) {
1302                 len = 0;
1303                 switch (uLevel) {
1304                         case 1:
1305                                 len = strlen(service->comment)+1;
1306                                 break;
1307                 }
1308
1309                 *buflen = struct_len;
1310                 *stringspace = len;
1311                 return struct_len + len;
1312         }
1313   
1314         len = struct_len;
1315         p = *buf;
1316         if (*buflen < struct_len) {
1317                 return -1;
1318         }
1319         if (stringbuf) {
1320                 p2 = *stringbuf;
1321                 l2 = *stringspace;
1322         } else {
1323                 p2 = p + struct_len;
1324                 l2 = *buflen - struct_len;
1325         }
1326         if (!baseaddr) {
1327                 baseaddr = p;
1328         }
1329   
1330         switch (uLevel) {
1331                 case 0:
1332                         push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1333                         break;
1334
1335                 case 1:
1336                         push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1337                         SIVAL(p,18,service->type);
1338                         SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1339                         len += CopyAndAdvance(&p2,service->comment,&l2);
1340                         break;
1341         }
1342
1343         if (stringbuf) {
1344                 *buf = p + struct_len;
1345                 *buflen -= struct_len;
1346                 *stringbuf = p2;
1347                 *stringspace = l2;
1348         } else {
1349                 *buf = p2;
1350                 *buflen -= len;
1351         }
1352         return len;
1353 }
1354
1355
1356 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1357 {
1358         return(strcmp(s1->name,s2->name));
1359 }
1360
1361 /****************************************************************************
1362  View list of servers available (or possibly domains). The info is
1363  extracted from lists saved by nmbd on the local host.
1364 ****************************************************************************/
1365
1366 static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1367                                 char *param, int tpscnt,
1368                                 char *data, int tdscnt,
1369                                 int mdrcnt, int mprcnt, char **rdata, 
1370                                 char **rparam, int *rdata_len, int *rparam_len)
1371 {
1372         char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1373         char *str2 = skip_string(param,tpscnt,str1);
1374         char *p = skip_string(param,tpscnt,str2);
1375         int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1376         int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1377         uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1378         char *p2;
1379         int data_len, fixed_len, string_len;
1380         int f_len = 0, s_len = 0;
1381         struct srv_info_struct *servers=NULL;
1382         int counted=0,total=0;
1383         int i,missed;
1384         fstring domain;
1385         bool domain_request;
1386         bool local_request;
1387
1388         if (!str1 || !str2 || !p) {
1389                 return False;
1390         }
1391
1392         /* If someone sets all the bits they don't really mean to set
1393            DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1394            known servers. */
1395
1396         if (servertype == SV_TYPE_ALL) {
1397                 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1398         }
1399
1400         /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1401            any other bit (they may just set this bit on its own) they 
1402            want all the locally seen servers. However this bit can be 
1403            set on its own so set the requested servers to be 
1404            ALL - DOMAIN_ENUM. */
1405
1406         if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1407                 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1408         }
1409
1410         domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1411         local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1412
1413         p += 8;
1414
1415         if (!prefix_ok(str1,"WrLehD")) {
1416                 return False;
1417         }
1418         if (!check_server_info(uLevel,str2)) {
1419                 return False;
1420         }
1421   
1422         DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1423         DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1424         DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1425
1426         if (strcmp(str1, "WrLehDz") == 0) {
1427                 if (skip_string(param,tpscnt,p) == NULL) {
1428                         return False;
1429                 }
1430                 pull_ascii_fstring(domain, p);
1431         } else {
1432                 fstrcpy(domain, lp_workgroup());
1433         }
1434
1435         if (lp_browse_list()) {
1436                 total = get_server_info(servertype,&servers,domain);
1437         }
1438
1439         data_len = fixed_len = string_len = 0;
1440         missed = 0;
1441
1442         if (total > 0) {
1443                 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1444         }
1445
1446         {
1447                 char *lastname=NULL;
1448
1449                 for (i=0;i<total;i++) {
1450                         struct srv_info_struct *s = &servers[i];
1451
1452                         if (lastname && strequal(lastname,s->name)) {
1453                                 continue;
1454                         }
1455                         lastname = s->name;
1456                         data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1457                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1458                                 s->name, s->type, s->comment, s->domain));
1459       
1460                         if (data_len <= buf_len) {
1461                                 counted++;
1462                                 fixed_len += f_len;
1463                                 string_len += s_len;
1464                         } else {
1465                                 missed++;
1466                         }
1467                 }
1468         }
1469
1470         *rdata_len = fixed_len + string_len;
1471         *rdata = smb_realloc_limit(*rdata,*rdata_len);
1472         if (!*rdata) {
1473                 return False;
1474         }
1475   
1476         p2 = (*rdata) + fixed_len;      /* auxilliary data (strings) will go here */
1477         p = *rdata;
1478         f_len = fixed_len;
1479         s_len = string_len;
1480
1481         {
1482                 char *lastname=NULL;
1483                 int count2 = counted;
1484
1485                 for (i = 0; i < total && count2;i++) {
1486                         struct srv_info_struct *s = &servers[i];
1487
1488                         if (lastname && strequal(lastname,s->name)) {
1489                                 continue;
1490                         }
1491                         lastname = s->name;
1492                         fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1493                         DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1494                                 s->name, s->type, s->comment, s->domain));
1495                         count2--;
1496                 }
1497         }
1498   
1499         *rparam_len = 8;
1500         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1501         if (!*rparam) {
1502                 return False;
1503         }
1504         SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1505         SSVAL(*rparam,2,0);
1506         SSVAL(*rparam,4,counted);
1507         SSVAL(*rparam,6,counted+missed);
1508
1509         SAFE_FREE(servers);
1510
1511         DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1512                 domain,uLevel,counted,counted+missed));
1513
1514         return True;
1515 }
1516
1517 /****************************************************************************
1518   command 0x34 - suspected of being a "Lookup Names" stub api
1519   ****************************************************************************/
1520
1521 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1522                                 char *param, int tpscnt,
1523                                 char *data, int tdscnt,
1524                                 int mdrcnt, int mprcnt, char **rdata, 
1525                                 char **rparam, int *rdata_len, int *rparam_len)
1526 {
1527         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1528         char *str2 = skip_string(param,tpscnt,str1);
1529         char *p = skip_string(param,tpscnt,str2);
1530         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1531         int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1532         int counted=0;
1533         int missed=0;
1534
1535         if (!str1 || !str2 || !p) {
1536                 return False;
1537         }
1538
1539         DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1540                 str1, str2, p, uLevel, buf_len));
1541
1542         if (!prefix_ok(str1,"zWrLeh")) {
1543                 return False;
1544         }
1545   
1546         *rdata_len = 0;
1547   
1548         *rparam_len = 8;
1549         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1550         if (!*rparam) {
1551                 return False;
1552         }
1553
1554         SSVAL(*rparam,0,0x08AC); /* informational warning message */
1555         SSVAL(*rparam,2,0);
1556         SSVAL(*rparam,4,counted);
1557         SSVAL(*rparam,6,counted+missed);
1558
1559         return True;
1560 }
1561
1562 /****************************************************************************
1563   get info about a share
1564   ****************************************************************************/
1565
1566 static bool check_share_info(int uLevel, char* id)
1567 {
1568         switch( uLevel ) {
1569                 case 0:
1570                         if (strcmp(id,"B13") != 0) {
1571                                 return False;
1572                         }
1573                         break;
1574                 case 1:
1575                         if (strcmp(id,"B13BWz") != 0) {
1576                                 return False;
1577                         }
1578                         break;
1579                 case 2:
1580                         if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1581                                 return False;
1582                         }
1583                         break;
1584                 case 91:
1585                         if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1586                                 return False;
1587                         }
1588                         break;
1589                 default:
1590                         return False;
1591         }
1592         return True;
1593 }
1594
1595 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1596                            char** buf, int* buflen,
1597                            char** stringbuf, int* stringspace, char* baseaddr)
1598 {
1599         int struct_len;
1600         char* p;
1601         char* p2;
1602         int l2;
1603         int len;
1604  
1605         switch( uLevel ) {
1606                 case 0:
1607                         struct_len = 13;
1608                         break;
1609                 case 1:
1610                         struct_len = 20;
1611                         break;
1612                 case 2:
1613                         struct_len = 40;
1614                         break;
1615                 case 91:
1616                         struct_len = 68;
1617                         break;
1618                 default:
1619                         return -1;
1620         }
1621   
1622  
1623         if (!buf) {
1624                 len = 0;
1625
1626                 if (uLevel > 0) {
1627                         len += StrlenExpanded(conn,snum,lp_comment(snum));
1628                 }
1629                 if (uLevel > 1) {
1630                         len += strlen(lp_pathname(snum)) + 1;
1631                 }
1632                 if (buflen) {
1633                         *buflen = struct_len;
1634                 }
1635                 if (stringspace) {
1636                         *stringspace = len;
1637                 }
1638                 return struct_len + len;
1639         }
1640   
1641         len = struct_len;
1642         p = *buf;
1643         if ((*buflen) < struct_len) {
1644                 return -1;
1645         }
1646
1647         if (stringbuf) {
1648                 p2 = *stringbuf;
1649                 l2 = *stringspace;
1650         } else {
1651                 p2 = p + struct_len;
1652                 l2 = (*buflen) - struct_len;
1653         }
1654
1655         if (!baseaddr) {
1656                 baseaddr = p;
1657         }
1658   
1659         push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1660   
1661         if (uLevel > 0) {
1662                 int type;
1663
1664                 SCVAL(p,13,0);
1665                 type = STYPE_DISKTREE;
1666                 if (lp_print_ok(snum)) {
1667                         type = STYPE_PRINTQ;
1668                 }
1669                 if (strequal("IPC",lp_fstype(snum))) {
1670                         type = STYPE_IPC;
1671                 }
1672                 SSVAL(p,14,type);               /* device type */
1673                 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1674                 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1675         }
1676   
1677         if (uLevel > 1) {
1678                 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1679                 SSVALS(p,22,-1);                /* max uses */
1680                 SSVAL(p,24,1); /* current uses */
1681                 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1682                 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1683                 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1684         }
1685   
1686         if (uLevel > 2) {
1687                 memset(p+40,0,SHPWLEN+2);
1688                 SSVAL(p,50,0);
1689                 SIVAL(p,52,0);
1690                 SSVAL(p,56,0);
1691                 SSVAL(p,58,0);
1692                 SIVAL(p,60,0);
1693                 SSVAL(p,64,0);
1694                 SSVAL(p,66,0);
1695         }
1696        
1697         if (stringbuf) {
1698                 (*buf) = p + struct_len;
1699                 (*buflen) -= struct_len;
1700                 (*stringbuf) = p2;
1701                 (*stringspace) = l2;
1702         } else {
1703                 (*buf) = p2;
1704                 (*buflen) -= len;
1705         }
1706
1707         return len;
1708 }
1709
1710 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1711                                 char *param, int tpscnt,
1712                                 char *data, int tdscnt,
1713                                 int mdrcnt,int mprcnt,
1714                                 char **rdata,char **rparam,
1715                                 int *rdata_len,int *rparam_len)
1716 {
1717         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1718         char *str2 = skip_string(param,tpscnt,str1);
1719         char *netname = skip_string(param,tpscnt,str2);
1720         char *p = skip_string(param,tpscnt,netname);
1721         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1722         int snum;
1723   
1724         if (!str1 || !str2 || !netname || !p) {
1725                 return False;
1726         }
1727
1728         snum = find_service(netname);
1729         if (snum < 0) {
1730                 return False;
1731         }
1732   
1733         /* check it's a supported varient */
1734         if (!prefix_ok(str1,"zWrLh")) {
1735                 return False;
1736         }
1737         if (!check_share_info(uLevel,str2)) {
1738                 return False;
1739         }
1740  
1741         *rdata = smb_realloc_limit(*rdata,mdrcnt);
1742         if (!*rdata) {
1743                 return False;
1744         }
1745         p = *rdata;
1746         *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1747         if (*rdata_len < 0) {
1748                 return False;
1749         }
1750  
1751         *rparam_len = 6;
1752         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1753         if (!*rparam) {
1754                 return False;
1755         }
1756         SSVAL(*rparam,0,NERR_Success);
1757         SSVAL(*rparam,2,0);             /* converter word */
1758         SSVAL(*rparam,4,*rdata_len);
1759  
1760         return True;
1761 }
1762
1763 /****************************************************************************
1764   View the list of available shares.
1765
1766   This function is the server side of the NetShareEnum() RAP call.
1767   It fills the return buffer with share names and share comments.
1768   Note that the return buffer normally (in all known cases) allows only
1769   twelve byte strings for share names (plus one for a nul terminator).
1770   Share names longer than 12 bytes must be skipped.
1771  ****************************************************************************/
1772
1773 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1774                                 char *param, int tpscnt,
1775                                 char *data, int tdscnt,
1776                                 int                mdrcnt,
1777                                 int                mprcnt,
1778                                 char             **rdata,
1779                                 char             **rparam,
1780                                 int               *rdata_len,
1781                                 int               *rparam_len )
1782 {
1783         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1784         char *str2 = skip_string(param,tpscnt,str1);
1785         char *p = skip_string(param,tpscnt,str2);
1786         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1787         int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1788         char *p2;
1789         int count = 0;
1790         int total=0,counted=0;
1791         bool missed = False;
1792         int i;
1793         int data_len, fixed_len, string_len;
1794         int f_len = 0, s_len = 0;
1795  
1796         if (!str1 || !str2 || !p) {
1797                 return False;
1798         }
1799
1800         if (!prefix_ok(str1,"WrLeh")) {
1801                 return False;
1802         }
1803         if (!check_share_info(uLevel,str2)) {
1804                 return False;
1805         }
1806   
1807         /* Ensure all the usershares are loaded. */
1808         become_root();
1809         load_registry_shares();
1810         count = load_usershare_shares();
1811         unbecome_root();
1812
1813         data_len = fixed_len = string_len = 0;
1814         for (i=0;i<count;i++) {
1815                 fstring servicename_dos;
1816                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1817                         continue;
1818                 }
1819                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1820                 /* Maximum name length = 13. */
1821                 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1822                         total++;
1823                         data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1824                         if (data_len <= buf_len) {
1825                                 counted++;
1826                                 fixed_len += f_len;
1827                                 string_len += s_len;
1828                         } else {
1829                                 missed = True;
1830                         }
1831                 }
1832         }
1833
1834         *rdata_len = fixed_len + string_len;
1835         *rdata = smb_realloc_limit(*rdata,*rdata_len);
1836         if (!*rdata) {
1837                 return False;
1838         }
1839  
1840         p2 = (*rdata) + fixed_len;      /* auxiliary data (strings) will go here */
1841         p = *rdata;
1842         f_len = fixed_len;
1843         s_len = string_len;
1844
1845         for( i = 0; i < count; i++ ) {
1846                 fstring servicename_dos;
1847                 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1848                         continue;
1849                 }
1850
1851                 push_ascii_fstring(servicename_dos, lp_servicename(i));
1852                 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1853                         if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1854                                 break;
1855                         }
1856                 }
1857         }
1858   
1859         *rparam_len = 8;
1860         *rparam = smb_realloc_limit(*rparam,*rparam_len);
1861         if (!*rparam) {
1862                 return False;
1863         }
1864         SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1865         SSVAL(*rparam,2,0);
1866         SSVAL(*rparam,4,counted);
1867         SSVAL(*rparam,6,total);
1868   
1869         DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1870                 counted,total,uLevel,
1871                 buf_len,*rdata_len,mdrcnt));
1872
1873         return True;
1874 }
1875
1876 /****************************************************************************
1877   Add a share
1878   ****************************************************************************/
1879
1880 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1881                                 char *param, int tpscnt,
1882                                 char *data, int tdscnt,
1883                                 int mdrcnt,int mprcnt,
1884                                 char **rdata,char **rparam,
1885                                 int *rdata_len,int *rparam_len)
1886 {
1887         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1888         char *str2 = skip_string(param,tpscnt,str1);
1889         char *p = skip_string(param,tpscnt,str2);
1890         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1891         fstring sharename;
1892         fstring comment;
1893         char *pathname = NULL;
1894         char *command, *cmdname;
1895         unsigned int offset;
1896         int snum;
1897         int res = ERRunsup;
1898         size_t converted_size;
1899
1900         if (!str1 || !str2 || !p) {
1901                 return False;
1902         }
1903
1904         /* check it's a supported varient */
1905         if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1906                 return False;
1907         }
1908         if (!check_share_info(uLevel,str2)) {
1909                 return False;
1910         }
1911         if (uLevel != 2) {
1912                 return False;
1913         }
1914
1915         /* Do we have a string ? */
1916         if (skip_string(data,mdrcnt,data) == NULL) {
1917                 return False;
1918         }
1919         pull_ascii_fstring(sharename,data);
1920         snum = find_service(sharename);
1921         if (snum >= 0) { /* already exists */
1922                 res = ERRfilexists;
1923                 goto error_exit;
1924         }
1925
1926         if (mdrcnt < 28) {
1927                 return False;
1928         }
1929
1930         /* only support disk share adds */
1931         if (SVAL(data,14)!=STYPE_DISKTREE) {
1932                 return False;
1933         }
1934
1935         offset = IVAL(data, 16);
1936         if (offset >= mdrcnt) {
1937                 res = ERRinvalidparam;
1938                 goto error_exit;
1939         }
1940
1941         /* Do we have a string ? */
1942         if (skip_string(data,mdrcnt,data+offset) == NULL) {
1943                 return False;
1944         }
1945         pull_ascii_fstring(comment, offset? (data+offset) : "");
1946
1947         offset = IVAL(data, 26);
1948
1949         if (offset >= mdrcnt) {
1950                 res = ERRinvalidparam;
1951                 goto error_exit;
1952         }
1953
1954         /* Do we have a string ? */
1955         if (skip_string(data,mdrcnt,data+offset) == NULL) {
1956                 return False;
1957         }
1958
1959         if (!pull_ascii_talloc(talloc_tos(), &pathname,
1960                                offset ? (data+offset) : "", &converted_size))
1961         {
1962                 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
1963                          strerror(errno)));
1964         }
1965
1966         if (!pathname) {
1967                 return false;
1968         }
1969
1970         string_replace(sharename, '"', ' ');
1971         string_replace(pathname, '"', ' ');
1972         string_replace(comment, '"', ' ');
1973
1974         cmdname = lp_add_share_cmd();
1975
1976         if (!cmdname || *cmdname == '\0') {
1977                 return False;
1978         }
1979
1980         if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1981                      lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
1982                      pathname, comment) == -1) {
1983                 return false;
1984         }
1985
1986         DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1987
1988         if ((res = smbrun(command, NULL)) != 0) {
1989                 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
1990                          command, res ));
1991                 SAFE_FREE(command);
1992                 res = ERRnoaccess;
1993                 goto error_exit;
1994         } else {
1995                 SAFE_FREE(command);
1996                 message_send_all(smbd_messaging_context(),
1997                                  MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1998         }
1999
2000         *rparam_len = 6;
2001         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2002         if (!*rparam) {
2003                 return False;
2004         }
2005         SSVAL(*rparam,0,NERR_Success);
2006         SSVAL(*rparam,2,0);             /* converter word */
2007         SSVAL(*rparam,4,*rdata_len);
2008         *rdata_len = 0;
2009   
2010         return True;
2011
2012   error_exit:
2013
2014         *rparam_len = 4;
2015         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2016         if (!*rparam) {
2017                 return False;
2018         }
2019         *rdata_len = 0;
2020         SSVAL(*rparam,0,res);
2021         SSVAL(*rparam,2,0);
2022         return True;
2023 }
2024
2025 /****************************************************************************
2026   view list of groups available
2027   ****************************************************************************/
2028
2029 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2030                                 char *param, int tpscnt,
2031                                 char *data, int tdscnt,
2032                                 int mdrcnt,int mprcnt,
2033                                 char **rdata,char **rparam,
2034                                 int *rdata_len,int *rparam_len)
2035 {
2036         int i;
2037         int errflags=0;
2038         int resume_context, cli_buf_size;
2039         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2040         char *str2 = skip_string(param,tpscnt,str1);
2041         char *p = skip_string(param,tpscnt,str2);
2042
2043         struct pdb_search *search;
2044         struct samr_displayentry *entries;
2045
2046         int num_entries;
2047  
2048         if (!str1 || !str2 || !p) {
2049                 return False;
2050         }
2051
2052         if (strcmp(str1,"WrLeh") != 0) {
2053                 return False;
2054         }
2055
2056         /* parameters  
2057          * W-> resume context (number of users to skip)
2058          * r -> return parameter pointer to receive buffer 
2059          * L -> length of receive buffer
2060          * e -> return parameter number of entries
2061          * h -> return parameter total number of users
2062          */
2063
2064         if (strcmp("B21",str2) != 0) {
2065                 return False;
2066         }
2067
2068         /* get list of domain groups SID_DOMAIN_GRP=2 */
2069         become_root();
2070         search = pdb_search_groups();
2071         unbecome_root();
2072
2073         if (search == NULL) {
2074                 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
2075                 return False;
2076         }
2077
2078         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2079         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2080         DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2081                   "%d\n", resume_context, cli_buf_size));
2082
2083         become_root();
2084         num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
2085                                          &entries);
2086         unbecome_root();
2087
2088         *rdata_len = cli_buf_size;
2089         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2090         if (!*rdata) {
2091                 return False;
2092         }
2093
2094         p = *rdata;
2095
2096         for(i=0; i<num_entries; i++) {
2097                 fstring name;
2098                 fstrcpy(name, entries[i].account_name);
2099                 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2100                         /* truncate the name at 21 chars. */
2101                         memcpy(p, name, 21); 
2102                         DEBUG(10,("adding entry %d group %s\n", i, p));
2103                         p += 21;
2104                         p += 5; /* Both NT4 and W2k3SP1 do padding here.
2105                                    No idea why... */
2106                 } else {
2107                         /* set overflow error */
2108                         DEBUG(3,("overflow on entry %d group %s\n", i, name));
2109                         errflags=234;
2110                         break;
2111                 }
2112         }
2113
2114         pdb_search_destroy(search);
2115
2116         *rdata_len = PTR_DIFF(p,*rdata);
2117
2118         *rparam_len = 8;
2119         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2120         if (!*rparam) {
2121                 return False;
2122         }
2123         SSVAL(*rparam, 0, errflags);
2124         SSVAL(*rparam, 2, 0);           /* converter word */
2125         SSVAL(*rparam, 4, i);   /* is this right?? */
2126         SSVAL(*rparam, 6, resume_context+num_entries);  /* is this right?? */
2127
2128         return(True);
2129 }
2130
2131 /*******************************************************************
2132  Get groups that a user is a member of.
2133 ******************************************************************/
2134
2135 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2136                                 char *param, int tpscnt,
2137                                 char *data, int tdscnt,
2138                                 int mdrcnt,int mprcnt,
2139                                 char **rdata,char **rparam,
2140                                 int *rdata_len,int *rparam_len)
2141 {
2142         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2143         char *str2 = skip_string(param,tpscnt,str1);
2144         char *UserName = skip_string(param,tpscnt,str2);
2145         char *p = skip_string(param,tpscnt,UserName);
2146         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2147         const char *level_string;
2148         int count=0;
2149         struct samu *sampw = NULL;
2150         bool ret = False;
2151         DOM_SID *sids;
2152         gid_t *gids;
2153         size_t num_groups;
2154         size_t i;
2155         NTSTATUS result;
2156         DOM_SID user_sid;
2157         enum lsa_SidType type;
2158         char *endp = NULL;
2159         TALLOC_CTX *mem_ctx;
2160
2161         if (!str1 || !str2 || !UserName || !p) {
2162                 return False;
2163         }
2164
2165         *rparam_len = 8;
2166         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2167         if (!*rparam) {
2168                 return False;
2169         }
2170
2171         /* check it's a supported varient */
2172
2173         if ( strcmp(str1,"zWrLeh") != 0 )
2174                 return False;
2175
2176         switch( uLevel ) {
2177                 case 0:
2178                         level_string = "B21";
2179                         break;
2180                 default:
2181                         return False;
2182         }
2183
2184         if (strcmp(level_string,str2) != 0)
2185                 return False;
2186
2187         *rdata_len = mdrcnt + 1024;
2188         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2189         if (!*rdata) {
2190                 return False;
2191         }
2192
2193         SSVAL(*rparam,0,NERR_Success);
2194         SSVAL(*rparam,2,0);             /* converter word */
2195
2196         p = *rdata;
2197         endp = *rdata + *rdata_len;
2198
2199         mem_ctx = talloc_new(NULL);
2200         if (mem_ctx == NULL) {
2201                 DEBUG(0, ("talloc_new failed\n"));
2202                 return False;
2203         }
2204
2205         if ( !(sampw = samu_new(mem_ctx)) ) {
2206                 DEBUG(0, ("samu_new() failed!\n"));
2207                 TALLOC_FREE(mem_ctx);
2208                 return False;
2209         }
2210
2211         /* Lookup the user information; This should only be one of
2212            our accounts (not remote domains) */
2213
2214         become_root();                                  /* ROOT BLOCK */
2215
2216         if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2217                          NULL, NULL, &user_sid, &type)) {
2218                 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2219                 goto done;
2220         }
2221
2222         if (type != SID_NAME_USER) {
2223                 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2224                            sid_type_lookup(type)));
2225                 goto done;
2226         }
2227
2228         if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2229                 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2230                            sid_string_dbg(&user_sid), UserName));
2231                 goto done;
2232         }
2233
2234         gids = NULL;
2235         sids = NULL;
2236         num_groups = 0;
2237
2238         result = pdb_enum_group_memberships(mem_ctx, sampw,
2239                                             &sids, &gids, &num_groups);
2240
2241         if (!NT_STATUS_IS_OK(result)) {
2242                 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2243                            UserName));
2244                 goto done;
2245         }
2246
2247         for (i=0; i<num_groups; i++) {
2248                 const char *grp_name;
2249
2250                 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2251                         strlcpy(p, grp_name, PTR_DIFF(endp,p));
2252                         p += 21;
2253                         count++;
2254                 }
2255         }
2256
2257         *rdata_len = PTR_DIFF(p,*rdata);
2258
2259         SSVAL(*rparam,4,count); /* is this right?? */
2260         SSVAL(*rparam,6,count); /* is this right?? */
2261
2262         ret = True;
2263
2264 done:
2265         unbecome_root();                                /* END ROOT BLOCK */
2266
2267         TALLOC_FREE(mem_ctx);
2268
2269         return ret;
2270 }
2271
2272 /*******************************************************************
2273  Get all users.
2274 ******************************************************************/
2275
2276 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2277                                 char *param, int tpscnt,
2278                                 char *data, int tdscnt,
2279                                 int mdrcnt,int mprcnt,
2280                                 char **rdata,char **rparam,
2281                                 int *rdata_len,int *rparam_len)
2282 {
2283         int count_sent=0;
2284         int num_users=0;
2285         int errflags=0;
2286         int i, resume_context, cli_buf_size;
2287         struct pdb_search *search;
2288         struct samr_displayentry *users;
2289
2290         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2291         char *str2 = skip_string(param,tpscnt,str1);
2292         char *p = skip_string(param,tpscnt,str2);
2293         char *endp = NULL;
2294
2295         if (!str1 || !str2 || !p) {
2296                 return False;
2297         }
2298
2299         if (strcmp(str1,"WrLeh") != 0)
2300                 return False;
2301         /* parameters
2302           * W-> resume context (number of users to skip)
2303           * r -> return parameter pointer to receive buffer
2304           * L -> length of receive buffer
2305           * e -> return parameter number of entries
2306           * h -> return parameter total number of users
2307           */
2308
2309         resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2310         cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2311         DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2312                         resume_context, cli_buf_size));
2313
2314         *rparam_len = 8;
2315         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2316         if (!*rparam) {
2317                 return False;
2318         }
2319
2320         /* check it's a supported varient */
2321         if (strcmp("B21",str2) != 0)
2322                 return False;
2323
2324         *rdata_len = cli_buf_size;
2325         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2326         if (!*rdata) {
2327                 return False;
2328         }
2329
2330         p = *rdata;
2331         endp = *rdata + *rdata_len;
2332
2333         become_root();
2334         search = pdb_search_users(ACB_NORMAL);
2335         unbecome_root();
2336         if (search == NULL) {
2337                 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2338                 return False;
2339         }
2340
2341         become_root();
2342         num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2343                                        &users);
2344         unbecome_root();
2345
2346         errflags=NERR_Success;
2347
2348         for (i=0; i<num_users; i++) {
2349                 const char *name = users[i].account_name;
2350
2351                 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2352                         strlcpy(p,name,PTR_DIFF(endp,p));
2353                         DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2354                                   "%s\n",count_sent,p));
2355                         p += 21;
2356                         count_sent++;
2357                 } else {
2358                         /* set overflow error */
2359                         DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2360                                   "username %s\n",count_sent,name));
2361                         errflags=234;
2362                         break;
2363                 }
2364         }
2365
2366         pdb_search_destroy(search);
2367
2368         *rdata_len = PTR_DIFF(p,*rdata);
2369
2370         SSVAL(*rparam,0,errflags);
2371         SSVAL(*rparam,2,0);           /* converter word */
2372         SSVAL(*rparam,4,count_sent);  /* is this right?? */
2373         SSVAL(*rparam,6,num_users); /* is this right?? */
2374
2375         return True;
2376 }
2377
2378 /****************************************************************************
2379  Get the time of day info.
2380 ****************************************************************************/
2381
2382 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2383                                 char *param, int tpscnt,
2384                                 char *data, int tdscnt,
2385                                 int mdrcnt,int mprcnt,
2386                                 char **rdata,char **rparam,
2387                                 int *rdata_len,int *rparam_len)
2388 {
2389         struct tm *t;
2390         time_t unixdate = time(NULL);
2391         char *p;
2392
2393         *rparam_len = 4;
2394         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2395         if (!*rparam) {
2396                 return False;
2397         }
2398
2399         *rdata_len = 21;
2400         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2401         if (!*rdata) {
2402                 return False;
2403         }
2404
2405         SSVAL(*rparam,0,NERR_Success);
2406         SSVAL(*rparam,2,0);             /* converter word */
2407
2408         p = *rdata;
2409
2410         srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2411                                             by NT in a "net time" operation,
2412                                             it seems to ignore the one below */
2413
2414         /* the client expects to get localtime, not GMT, in this bit 
2415                 (I think, this needs testing) */
2416         t = localtime(&unixdate);
2417         if (!t) {
2418                 return False;
2419         }
2420
2421         SIVAL(p,4,0);           /* msecs ? */
2422         SCVAL(p,8,t->tm_hour);
2423         SCVAL(p,9,t->tm_min);
2424         SCVAL(p,10,t->tm_sec);
2425         SCVAL(p,11,0);          /* hundredths of seconds */
2426         SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2427         SSVAL(p,14,10000);              /* timer interval in 0.0001 of sec */
2428         SCVAL(p,16,t->tm_mday);
2429         SCVAL(p,17,t->tm_mon + 1);
2430         SSVAL(p,18,1900+t->tm_year);
2431         SCVAL(p,20,t->tm_wday);
2432
2433         return True;
2434 }
2435
2436 /****************************************************************************
2437  Set the user password.
2438 *****************************************************************************/
2439
2440 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2441                                 char *param, int tpscnt,
2442                                 char *data, int tdscnt,
2443                                 int mdrcnt,int mprcnt,
2444                                 char **rdata,char **rparam,
2445                                 int *rdata_len,int *rparam_len)
2446 {
2447         char *np = get_safe_str_ptr(param,tpscnt,param,2);
2448         char *p = NULL;
2449         fstring user;
2450         fstring pass1,pass2;
2451
2452         /* Skip 2 strings. */
2453         p = skip_string(param,tpscnt,np);
2454         p = skip_string(param,tpscnt,p);
2455
2456         if (!np || !p) {
2457                 return False;
2458         }
2459
2460         /* Do we have a string ? */
2461         if (skip_string(param,tpscnt,p) == NULL) {
2462                 return False;
2463         }
2464         pull_ascii_fstring(user,p);
2465
2466         p = skip_string(param,tpscnt,p);
2467         if (!p) {
2468                 return False;
2469         }
2470
2471         memset(pass1,'\0',sizeof(pass1));
2472         memset(pass2,'\0',sizeof(pass2));
2473         /*
2474          * We use 31 here not 32 as we're checking
2475          * the last byte we want to access is safe.
2476          */
2477         if (!is_offset_safe(param,tpscnt,p,31)) {
2478                 return False;
2479         }
2480         memcpy(pass1,p,16);
2481         memcpy(pass2,p+16,16);
2482
2483         *rparam_len = 4;
2484         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2485         if (!*rparam) {
2486                 return False;
2487         }
2488
2489         *rdata_len = 0;
2490
2491         SSVAL(*rparam,0,NERR_badpass);
2492         SSVAL(*rparam,2,0);             /* converter word */
2493
2494         DEBUG(3,("Set password for <%s>\n",user));
2495
2496         /*
2497          * Attempt to verify the old password against smbpasswd entries
2498          * Win98 clients send old and new password in plaintext for this call.
2499          */
2500
2501         {
2502                 auth_serversupplied_info *server_info = NULL;
2503                 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2504
2505                 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2506
2507                         become_root();
2508                         if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2509                                 SSVAL(*rparam,0,NERR_Success);
2510                         }
2511                         unbecome_root();
2512
2513                         TALLOC_FREE(server_info);
2514                 }
2515                 data_blob_clear_free(&password);
2516         }
2517
2518         /*
2519          * If the plaintext change failed, attempt
2520          * the old encrypted method. NT will generate this
2521          * after trying the samr method. Note that this
2522          * method is done as a last resort as this
2523          * password change method loses the NT password hash
2524          * and cannot change the UNIX password as no plaintext
2525          * is received.
2526          */
2527
2528         if(SVAL(*rparam,0) != NERR_Success) {
2529                 struct samu *hnd = NULL;
2530
2531                 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2532                         become_root();
2533                         if (change_lanman_password(hnd,(uchar *)pass2)) {
2534                                 SSVAL(*rparam,0,NERR_Success);
2535                         }
2536                         unbecome_root();
2537                         TALLOC_FREE(hnd);
2538                 }
2539         }
2540
2541         memset((char *)pass1,'\0',sizeof(fstring));
2542         memset((char *)pass2,'\0',sizeof(fstring));      
2543          
2544         return(True);
2545 }
2546
2547 /****************************************************************************
2548   Set the user password (SamOEM version - gets plaintext).
2549 ****************************************************************************/
2550
2551 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2552                                 char *param, int tpscnt,
2553                                 char *data, int tdscnt,
2554                                 int mdrcnt,int mprcnt,
2555                                 char **rdata,char **rparam,
2556                                 int *rdata_len,int *rparam_len)
2557 {
2558         fstring user;
2559         char *p = get_safe_str_ptr(param,tpscnt,param,2);
2560         *rparam_len = 2;
2561         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2562         if (!*rparam) {
2563                 return False;
2564         }
2565
2566         if (!p) {
2567                 return False;
2568         }
2569         *rdata_len = 0;
2570
2571         SSVAL(*rparam,0,NERR_badpass);
2572
2573         /*
2574          * Check the parameter definition is correct.
2575          */
2576
2577         /* Do we have a string ? */
2578         if (skip_string(param,tpscnt,p) == 0) {
2579                 return False;
2580         }
2581         if(!strequal(p, "zsT")) {
2582                 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2583                 return False;
2584         }
2585         p = skip_string(param, tpscnt, p);
2586         if (!p) {
2587                 return False;
2588         }
2589
2590         /* Do we have a string ? */
2591         if (skip_string(param,tpscnt,p) == 0) {
2592                 return False;
2593         }
2594         if(!strequal(p, "B516B16")) {
2595                 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2596                 return False;
2597         }
2598         p = skip_string(param,tpscnt,p);
2599         if (!p) {
2600                 return False;
2601         }
2602         /* Do we have a string ? */
2603         if (skip_string(param,tpscnt,p) == 0) {
2604                 return False;
2605         }
2606         p += pull_ascii_fstring(user,p);
2607
2608         DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2609
2610         /*
2611          * Pass the user through the NT -> unix user mapping
2612          * function.
2613          */
2614
2615         (void)map_username(user);
2616
2617         if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2618                 SSVAL(*rparam,0,NERR_Success);
2619         }
2620
2621         return(True);
2622 }
2623
2624 /****************************************************************************
2625   delete a print job
2626   Form: <W> <> 
2627   ****************************************************************************/
2628
2629 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2630                                 char *param, int tpscnt,
2631                                 char *data, int tdscnt,
2632                                 int mdrcnt,int mprcnt,
2633                                 char **rdata,char **rparam,
2634                                 int *rdata_len,int *rparam_len)
2635 {
2636         int function = get_safe_SVAL(param,tpscnt,param,0,0);
2637         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2638         char *str2 = skip_string(param,tpscnt,str1);
2639         char *p = skip_string(param,tpscnt,str2);
2640         uint32 jobid;
2641         int snum;
2642         fstring sharename;
2643         int errcode;
2644         WERROR werr = WERR_OK;
2645
2646         if (!str1 || !str2 || !p) {
2647                 return False;
2648         }
2649         /*
2650          * We use 1 here not 2 as we're checking
2651          * the last byte we want to access is safe.
2652          */
2653         if (!is_offset_safe(param,tpscnt,p,1)) {
2654                 return False;
2655         }
2656         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2657                 return False;
2658
2659         /* check it's a supported varient */
2660         if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2661                 return(False);
2662
2663         *rparam_len = 4;
2664         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2665         if (!*rparam) {
2666                 return False;
2667         }
2668         *rdata_len = 0;
2669
2670         if (!print_job_exists(sharename, jobid)) {
2671                 errcode = NERR_JobNotFound;
2672                 goto out;
2673         }
2674
2675         snum = lp_servicenumber( sharename);
2676         if (snum == -1) {
2677                 errcode = NERR_DestNotFound;
2678                 goto out;
2679         }
2680
2681         errcode = NERR_notsupported;
2682         
2683         switch (function) {
2684         case 81:                /* delete */ 
2685                 if (print_job_delete(&current_user, snum, jobid, &werr)) 
2686                         errcode = NERR_Success;
2687                 break;
2688         case 82:                /* pause */
2689                 if (print_job_pause(&current_user, snum, jobid, &werr)) 
2690                         errcode = NERR_Success;
2691                 break;
2692         case 83:                /* resume */
2693                 if (print_job_resume(&current_user, snum, jobid, &werr)) 
2694                         errcode = NERR_Success;
2695                 break;
2696         }
2697
2698         if (!W_ERROR_IS_OK(werr))
2699                 errcode = W_ERROR_V(werr);
2700         
2701  out:
2702         SSVAL(*rparam,0,errcode);       
2703         SSVAL(*rparam,2,0);             /* converter word */
2704
2705         return(True);
2706 }
2707
2708 /****************************************************************************
2709   Purge a print queue - or pause or resume it.
2710   ****************************************************************************/
2711
2712 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2713                                 char *param, int tpscnt,
2714                                 char *data, int tdscnt,
2715                                 int mdrcnt,int mprcnt,
2716                                 char **rdata,char **rparam,
2717                                 int *rdata_len,int *rparam_len)
2718 {
2719         int function = get_safe_SVAL(param,tpscnt,param,0,0);
2720         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2721         char *str2 = skip_string(param,tpscnt,str1);
2722         char *QueueName = skip_string(param,tpscnt,str2);
2723         int errcode = NERR_notsupported;
2724         int snum;
2725         WERROR werr = WERR_OK;
2726
2727         if (!str1 || !str2 || !QueueName) {
2728                 return False;
2729         }
2730
2731         /* check it's a supported varient */
2732         if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2733                 return(False);
2734
2735         *rparam_len = 4;
2736         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2737         if (!*rparam) {
2738                 return False;
2739         }
2740         *rdata_len = 0;
2741
2742         if (skip_string(param,tpscnt,QueueName) == NULL) {
2743                 return False;
2744         }
2745         snum = print_queue_snum(QueueName);
2746
2747         if (snum == -1) {
2748                 errcode = NERR_JobNotFound;
2749                 goto out;
2750         }
2751
2752         switch (function) {
2753         case 74: /* Pause queue */
2754                 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2755                 break;
2756         case 75: /* Resume queue */
2757                 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2758                 break;
2759         case 103: /* Purge */
2760                 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2761                 break;
2762         }
2763
2764         if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2765
2766  out:
2767         SSVAL(*rparam,0,errcode);
2768         SSVAL(*rparam,2,0);             /* converter word */
2769
2770         return(True);
2771 }
2772
2773 /****************************************************************************
2774   set the property of a print job (undocumented?)
2775   ? function = 0xb -> set name of print job
2776   ? function = 0x6 -> move print job up/down
2777   Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> 
2778   or   <WWsTP> <WB21BB16B10zWWzDDz> 
2779 ****************************************************************************/
2780
2781 static int check_printjob_info(struct pack_desc* desc,
2782                                int uLevel, char* id)
2783 {
2784         desc->subformat = NULL;
2785         switch( uLevel ) {
2786         case 0: desc->format = "W"; break;
2787         case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2788         case 2: desc->format = "WWzWWDDzz"; break;
2789         case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2790         case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2791         default:
2792                 DEBUG(0,("check_printjob_info: invalid level %d\n",
2793                         uLevel ));
2794                 return False;
2795         }
2796         if (id == NULL || strcmp(desc->format,id) != 0) {
2797                 DEBUG(0,("check_printjob_info: invalid format %s\n",
2798                         id ? id : "<NULL>" ));
2799                 return False;
2800         }
2801         return True;
2802 }
2803
2804 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2805                                 char *param, int tpscnt,
2806                                 char *data, int tdscnt,
2807                                 int mdrcnt,int mprcnt,
2808                                 char **rdata,char **rparam,
2809                                 int *rdata_len,int *rparam_len)
2810 {
2811         struct pack_desc desc;
2812         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2813         char *str2 = skip_string(param,tpscnt,str1);
2814         char *p = skip_string(param,tpscnt,str2);
2815         uint32 jobid;
2816         fstring sharename;
2817         int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2818         int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2819         int place, errcode;
2820
2821         if (!str1 || !str2 || !p) {
2822                 return False;
2823         }
2824         /*
2825          * We use 1 here not 2 as we're checking
2826          * the last byte we want to access is safe.
2827          */
2828         if (!is_offset_safe(param,tpscnt,p,1)) {
2829                 return False;
2830         }
2831         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2832                 return False;
2833         *rparam_len = 4;
2834         *rparam = smb_realloc_limit(*rparam,*rparam_len);
2835         if (!*rparam) {
2836                 return False;
2837         }
2838
2839         if (!share_defined(sharename)) {
2840                 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2841                          sharename));
2842                 return False;
2843         }
2844   
2845         *rdata_len = 0;
2846         
2847         /* check it's a supported varient */
2848         if ((strcmp(str1,"WWsTP")) || 
2849             (!check_printjob_info(&desc,uLevel,str2)))
2850                 return(False);
2851
2852         if (!print_job_exists(sharename, jobid)) {
2853                 errcode=NERR_JobNotFound;
2854                 goto out;
2855         }
2856
2857         errcode = NERR_notsupported;
2858
2859         switch (function) {
2860         case 0x6:
2861                 /* change job place in the queue, 
2862                    data gives the new place */
2863                 place = SVAL(data,0);
2864                 if (print_job_set_place(sharename, jobid, place)) {
2865                         errcode=NERR_Success;
2866                 }
2867                 break;
2868
2869         case 0xb:   
2870                 /* change print job name, data gives the name */
2871                 if (print_job_set_name(sharename, jobid, data)) {
2872                         errcode=NERR_Success;
2873                 }
2874                 break;
2875
2876         default:
2877                 return False;
2878         }
2879
2880  out:
2881         SSVALS(*rparam,0,errcode);
2882         SSVAL(*rparam,2,0);             /* converter word */
2883         
2884         return(True);
2885 }
2886
2887
2888 /****************************************************************************
2889  Get info about the server.
2890 ****************************************************************************/
2891
2892 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2893                                 char *param, int tpscnt,
2894                                 char *data, int tdscnt,
2895                                 int mdrcnt,int mprcnt,
2896                                 char **rdata,char **rparam,
2897                                 int *rdata_len,int *rparam_len)
2898 {
2899         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2900         char *str2 = skip_string(param,tpscnt,str1);
2901         char *p = skip_string(param,tpscnt,str2);
2902         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2903         char *p2;
2904         int struct_len;
2905
2906         if (!str1 || !str2 || !p) {
2907                 return False;
2908         }
2909
2910         DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2911
2912         /* check it's a supported varient */
2913         if (!prefix_ok(str1,"WrLh")) {
2914                 return False;
2915         }
2916
2917         switch( uLevel ) {
2918                 case 0:
2919                         if (strcmp(str2,"B16") != 0) {
2920                                 return False;
2921                         }
2922                         struct_len = 16;
2923                         break;
2924                 case 1:
2925                         if (strcmp(str2,"B16BBDz") != 0) {
2926                                 return False;
2927                         }
2928                         struct_len = 26;
2929                         break;
2930                 case 2:
2931                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2932                                 return False;
2933                         }
2934                         struct_len = 134;
2935                         break;
2936                 case 3:
2937                         if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2938                                 return False;
2939                         }
2940                         struct_len = 144;
2941                         break;
2942                 case 20:
2943                         if (strcmp(str2,"DN") != 0) {
2944                                 return False;
2945                         }
2946                         struct_len = 6;
2947                         break;
2948                 case 50:
2949                         if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2950                                 return False;
2951                         }
2952                         struct_len = 42;
2953                         break;
2954                 default:
2955                         return False;
2956         }
2957
2958         *rdata_len = mdrcnt;
2959         *rdata = smb_realloc_limit(*rdata,*rdata_len);
2960         if (!*rdata) {
2961                 return False;
2962         }
2963
2964         p = *rdata;
2965         p2 = p + struct_len;
2966         if (uLevel != 20) {
2967                 srvstr_push(NULL, 0, p,global_myname(),16,
2968                         STR_ASCII|STR_UPPER|STR_TERMINATE);
2969         }
2970         p += 16;
2971         if (uLevel > 0) {
2972                 struct srv_info_struct *servers=NULL;
2973                 int i,count;
2974                 char *comment = NULL;
2975                 TALLOC_CTX *ctx = talloc_tos();
2976                 uint32 servertype= lp_default_server_announce();
2977
2978                 comment = talloc_strdup(ctx,lp_serverstring());
2979                 if (!comment) {
2980                         return false;
2981                 }
2982
2983                 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2984                         for (i=0;i<count;i++) {
2985                                 if (strequal(servers[i].name,global_myname())) {
2986                                         servertype = servers[i].type;
2987                                         TALLOC_FREE(comment);
2988                                         comment = talloc_strdup(ctx,
2989                                                         servers[i].comment);
2990                                         if (comment) {
2991                                                 return false;
2992                                         }
2993                                 }
2994                         }
2995                 }
2996
2997                 SAFE_FREE(servers);
2998
2999                 SCVAL(p,0,lp_major_announce_version());
3000                 SCVAL(p,1,lp_minor_announce_version());
3001                 SIVAL(p,2,servertype);
3002
3003                 if (mdrcnt == struct_len) {
3004                         SIVAL(p,6,0);
3005                 } else {
3006                         SIVAL(p,6,PTR_DIFF(p2,*rdata));
3007                         comment = talloc_sub_advanced(
3008                                 ctx,
3009                                 lp_servicename(SNUM(conn)),
3010                                 conn->server_info->unix_name,
3011                                 conn->connectpath,
3012                                 conn->server_info->utok.gid,
3013                                 conn->server_info->sanitized_username,
3014                                 pdb_get_domain(conn->server_info->sam_account),
3015                                 comment);
3016                         if (comment) {
3017                                 return false;
3018                         }
3019                         if (mdrcnt - struct_len <= 0) {
3020                                 return false;
3021                         }
3022                         push_ascii(p2,
3023                                 comment,
3024                                 MIN(mdrcnt - struct_len,
3025                                         MAX_SERVER_STRING_LENGTH),
3026                                 STR_TERMINATE);
3027                         p2 = skip_string(*rdata,*rdata_len,p2);
3028                         if (!p2) {
3029                                 return False;
3030                         }
3031                 }
3032         }
3033
3034         if (uLevel > 1) {
3035                 return False;           /* not yet implemented */
3036         }
3037
3038         *rdata_len = PTR_DIFF(p2,*rdata);
3039
3040         *rparam_len = 6;
3041         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3042         if (!*rparam) {
3043                 return False;
3044         }
3045         SSVAL(*rparam,0,NERR_Success);
3046         SSVAL(*rparam,2,0);             /* converter word */
3047         SSVAL(*rparam,4,*rdata_len);
3048
3049         return True;
3050 }
3051
3052 /****************************************************************************
3053  Get info about the server.
3054 ****************************************************************************/
3055
3056 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3057                                 char *param, int tpscnt,
3058                                 char *data, int tdscnt,
3059                                 int mdrcnt,int mprcnt,
3060                                 char **rdata,char **rparam,
3061                                 int *rdata_len,int *rparam_len)
3062 {
3063         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3064         char *str2 = skip_string(param,tpscnt,str1);
3065         char *p = skip_string(param,tpscnt,str2);
3066         char *p2;
3067         char *endp;
3068         int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3069
3070         if (!str1 || !str2 || !p) {
3071                 return False;
3072         }
3073
3074         DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3075
3076         *rparam_len = 6;
3077         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3078         if (!*rparam) {
3079                 return False;
3080         }
3081
3082         /* check it's a supported varient */
3083         if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3084                 return False;
3085         }
3086
3087         *rdata_len = mdrcnt + 1024;
3088         *rdata = smb_realloc_limit(*rdata,*rdata_len);
3089         if (!*rdata) {
3090                 return False;
3091         }
3092
3093         SSVAL(*rparam,0,NERR_Success);
3094         SSVAL(*rparam,2,0);             /* converter word */
3095
3096         p = *rdata;
3097         endp = *rdata + *rdata_len;
3098
3099         p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3100         if (!p2) {
3101                 return False;
3102         }
3103
3104         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3105         strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3106         strupper_m(p2);
3107         p2 = skip_string(*rdata,*rdata_len,p2);
3108         if (!p2) {
3109                 return False;
3110         }
3111         p += 4;
3112
3113         SIVAL(p,0,PTR_DIFF(p2,*rdata));
3114         strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3115         p2 = skip_string(*rdata,*rdata_len,p2);
3116         if (!p2) {
3117                 return False;
3118         }
3119         p += 4;
3120
3121         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3122         strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3123         strupper_m(p2);
3124         p2 = skip_string(*rdata,*rdata_len,p2);
3125         if (!p2) {
3126                 return False;
3127         }
3128         p += 4;
3129
3130         SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3131         SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3132         p += 2;
3133
3134         SIVAL(p,0,PTR_DIFF(p2,*rdata));
3135         strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));   /* don't know.  login domain?? */
3136         p2 = skip_string(*rdata,*rdata_len,p2);
3137         if (!p2) {
3138                 return False;
3139         }
3140         p += 4;
3141
3142         SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3143         strlcpy(p2,"",PTR_DIFF(endp,p2));
3144         p2 = skip_string(*rdata,*rdata_len,p2);
3145         if (!p2) {
3146                 return False;
3147         }
3148         p += 4;
3149
3150         *rdata_len = PTR_DIFF(p2,*rdata);
3151
3152         SSVAL(*rparam,4,*rdata_len);
3153
3154         return True;
3155 }
3156
3157 /****************************************************************************
3158   get info about a user
3159
3160     struct user_info_11 {
3161         char                usri11_name[21];  0-20 
3162         char                usri11_pad;       21 
3163         char                *usri11_comment;  22-25 
3164         char            *usri11_usr_comment;  26-29
3165         unsigned short      usri11_priv;      30-31
3166         unsigned long       usri11_auth_flags; 32-35
3167         long                usri11_password_age; 36-39
3168         char                *usri11_homedir; 40-43
3169         char            *usri11_parms; 44-47
3170         long                usri11_last_logon; 48-51
3171         long                usri11_last_logoff; 52-55
3172         unsigned short      usri11_bad_pw_count; 56-57
3173         unsigned short      usri11_num_logons; 58-59
3174         char                *usri11_logon_server; 60-63
3175         unsigned short      usri11_country_code; 64-65
3176         char            *usri11_workstations; 66-69
3177         unsigned long       usri11_max_storage; 70-73
3178         unsigned short      usri11_units_per_week; 74-75
3179         unsigned char       *usri11_logon_hours; 76-79
3180         unsigned short      usri11_code_page; 80-81
3181     };
3182
3183 where:
3184
3185   usri11_name specifies the user name for which information is retrieved
3186
3187   usri11_pad aligns the next data structure element to a word boundary
3188
3189   usri11_comment is a null terminated ASCII comment
3190
3191   usri11_user_comment is a null terminated ASCII comment about the user
3192
3193   usri11_priv specifies the level of the privilege assigned to the user.
3194        The possible values are:
3195
3196 Name             Value  Description
3197 USER_PRIV_GUEST  0      Guest privilege
3198 USER_PRIV_USER   1      User privilege
3199 USER_PRV_ADMIN   2      Administrator privilege
3200
3201   usri11_auth_flags specifies the account operator privileges. The
3202        possible values are:
3203
3204 Name            Value   Description
3205 AF_OP_PRINT     0       Print operator
3206
3207
3208 Leach, Naik                                        [Page 28]
3209 \f
3210
3211
3212 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3213
3214
3215 AF_OP_COMM      1       Communications operator
3216 AF_OP_SERVER    2       Server operator
3217 AF_OP_ACCOUNTS  3       Accounts operator
3218
3219
3220   usri11_password_age specifies how many seconds have elapsed since the
3221        password was last changed.
3222
3223   usri11_home_dir points to a null terminated ASCII string that contains
3224        the path name of the user's home directory.
3225
3226   usri11_parms points to a null terminated ASCII string that is set
3227        aside for use by applications.
3228
3229   usri11_last_logon specifies the time when the user last logged on.
3230        This value is stored as the number of seconds elapsed since
3231        00:00:00, January 1, 1970.
3232
3233   usri11_last_logoff specifies the time when the user last logged off.
3234        This value is stored as the number of seconds elapsed since
3235        00:00:00, January 1, 1970. A value of 0 means the last logoff
3236        time is unknown.
3237
3238   usri11_bad_pw_count specifies the number of incorrect passwords
3239        entered since the last successful logon.
3240
3241   usri11_log1_num_logons specifies the number of times this user has
3242        logged on. A value of -1 means the number of logons is unknown.
3243
3244   usri11_logon_server points to a null terminated ASCII string that
3245        contains the name of the server to which logon requests are sent.
3246        A null string indicates logon requests should be sent to the
3247        domain controller.
3248
3249   usri11_country_code specifies the country code for the user's language
3250        of choice.
3251
3252   usri11_workstations points to a null terminated ASCII string that
3253        contains the names of workstations the user may log on from.
3254        There may be up to 8 workstations, with the names separated by
3255        commas. A null strings indicates there are no restrictions.
3256
3257   usri11_max_storage specifies the maximum amount of disk space the user
3258        can occupy. A value of 0xffffffff indicates there are no
3259        restrictions.
3260
3261   usri11_units_per_week specifies the equal number of time units into
3262        which a week is divided. This value must be equal to 168.
3263
3264   usri11_logon_hours points to a 21 byte (168 bits) string that
3265        specifies the time during which the user can log on. Each bit
3266        represents one unique hour in a week. The first bit (bit 0, word
3267        0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3268
3269
3270
3271 Leach, Naik                                        [Page 29]
3272 \f
3273
3274
3275 INTERNET-DRAFT   CIFS Remote Admin Protocol     January 10, 1997
3276
3277
3278        Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3279        are no restrictions.
3280
3281   usri11_code_page specifies the code page for the user's language of
3282        choice
3283
3284 All of the pointers in this data structure need to be treated
3285 specially. The  pointer is a 32 bit pointer. The higher 16 bits need
3286 to be ignored. The converter word returned in the parameters section
3287 needs to be subtracted from the lower 16 bits to calculate an offset
3288 into the return buffer where this ASCII string resides.
3289
3290 There is no auxiliary data in the response.
3291
3292   ****************************************************************************/
3293
3294 #define usri11_name           0 
3295 #define usri11_pad            21
3296 #define usri11_comment        22
3297 #define usri11_usr_comment    26
3298 #define usri11_full_name      30
3299 #define usri11_priv           34
3300 #define usri11_auth_flags     36
3301 #define usri11_password_age   40
3302 #define usri11_homedir        44
3303 #define usri11_parms          48
3304 #define usri11_last_logon     52
3305 #define usri11_last_logoff    56
3306 #define usri11_bad_pw_count   60
3307 #define usri11_num_logons     62
3308 #define usri11_logon_server   64
3309 #define usri11_country_code   68
3310 #define usri11_workstations   70
3311 #define usri11_max_storage    74
3312 #define usri11_units_per_week 78
3313 #define usri11_logon_hours    80
3314 #define usri11_code_page      84
3315 #define usri11_end            86
3316
3317 #define USER_PRIV_GUEST 0
3318 #define USER_PRIV_USER 1
3319 #define USER_PRIV_ADMIN 2
3320
3321 #define AF_OP_PRINT     0 
3322 #define AF_OP_COMM      1
3323 #define AF_OP_SERVER    2
3324 #define AF_OP_ACCOUNTS  3
3325
3326
3327 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3328                                 char *param, int tpscnt,
3329                                 char *data, int tdscnt,
3330                                 int mdrcnt,int mprcnt,
3331                                 char **rdata,char **rparam,
3332                                 int *rdata_len,int *rparam_len)
3333 {
3334         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3335         char *str2 = skip_string(param,tpscnt,str1);
3336         char *UserName = skip_string(param,tpscnt,str2);
3337         char *p = skip_string(param,tpscnt,UserName);
3338         int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3339         char *p2;
3340         char *endp;
3341         const char *level_string;
3342
3343         /* get NIS home of a previously validated user - simeon */
3344         /* With share level security vuid will always be zero.
3345            Don't depend on vuser being non-null !!. JRA */
3346         user_struct *vuser = get_valid_user_struct(vuid);
3347         if(vuser != NULL) {
3348                 DEBUG(3,("  Username of UID %d is %s\n",
3349                          (int)vuser->server_info->utok.uid,
3350                          vuser->server_info->unix_name));
3351         }
3352
3353         if (!str1 || !str2 || !UserName || !p) {
3354                 return False;
3355         }
3356
3357         *rparam_len = 6;
3358         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3359         if (!*rparam) {
3360                 return False;
3361         }
3362
3363         DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3364
3365         /* check it's a supported variant */
3366         if (strcmp(str1,"zWrLh") != 0) {
3367                 return False;
3368         }
3369         switch( uLevel ) {
3370                 case 0: level_string = "B21"; break;
3371                 case 1: level_string = "B21BB16DWzzWz"; break;
3372                 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3373                 case 10: level_string = "B21Bzzz"; break;
3374                 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3375                 default: return False;
3376         }
3377
3378         if (strcmp(level_string,str2) != 0) {
3379                 return False;
3380         }
3381
3382         *rdata_len = mdrcnt + 1024;
3383         *rdata = smb_realloc_limit(*rdata,*rdata_len);
3384         if (!*rdata) {
3385                 return False;
3386         }
3387
3388         SSVAL(*rparam,0,NERR_Success);
3389         SSVAL(*rparam,2,0);             /* converter word */
3390
3391         p = *rdata;
3392         endp = *rdata + *rdata_len;
3393         p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3394         if (!p2) {
3395                 return False;
3396         }
3397
3398         memset(p,0,21);
3399         fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3400
3401         if (uLevel > 0) {
3402                 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3403                 *p2 = 0;
3404         }
3405
3406         if (uLevel >= 10) {
3407                 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3408                 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3409                 p2 = skip_string(*rdata,*rdata_len,p2);
3410                 if (!p2) {
3411                         return False;
3412                 }
3413
3414                 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3415                 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3416                 p2 = skip_string(*rdata,*rdata_len,p2);
3417                 if (!p2) {
3418                         return False;
3419                 }
3420
3421                 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3422                 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3423                 strlcpy(p2,((vuser != NULL)
3424                             ? pdb_get_fullname(vuser->server_info->sam_account)
3425                             : UserName),PTR_DIFF(endp,p2));
3426                 p2 = skip_string(*rdata,*rdata_len,p2);
3427                 if (!p2) {
3428                         return False;
3429                 }
3430         }
3431
3432         if (uLevel == 11) {
3433                 const char *homedir = "";
3434                 if (vuser != NULL) {
3435                         homedir = pdb_get_homedir(
3436                                 vuser->server_info->sam_account);
3437                 }
3438                 /* modelled after NTAS 3.51 reply */
3439                 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
3440                 SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
3441                 SIVALS(p,usri11_password_age,-1);               /* password age */
3442                 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3443                 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3444                 p2 = skip_string(*rdata,*rdata_len,p2);
3445                 if (!p2) {
3446                         return False;
3447                 }
3448                 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3449                 strlcpy(p2,"",PTR_DIFF(endp,p2));
3450                 p2 = skip_string(*rdata,*rdata_len,p2);
3451                 if (!p2) {
3452                         return False;
3453                 }
3454                 SIVAL(p,usri11_last_logon,0);           /* last logon */
3455                 SIVAL(p,usri11_last_logoff,0);          /* last logoff */
3456                 SSVALS(p,usri11_bad_pw_count,-1);       /* bad pw counts */
3457                 SSVALS(p,usri11_num_logons,-1);         /* num logons */
3458                 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3459                 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3460                 p2 = skip_string(*rdata,*rdata_len,p2);
3461                 if (!p2) {
3462                         return False;
3463                 }
3464                 SSVAL(p,usri11_country_code,0);         /* country code */
3465
3466                 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3467                 strlcpy(p2,"",PTR_DIFF(endp,p2));
3468                 p2 = skip_string(*rdata,*rdata_len,p2);
3469                 if (!p2) {
3470                         return False;
3471                 }
3472
3473                 SIVALS(p,usri11_max_storage,-1);                /* max storage */
3474                 SSVAL(p,usri11_units_per_week,168);             /* units per week */
3475                 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3476
3477                 /* a simple way to get logon hours at all times. */
3478                 memset(p2,0xff,21);
3479                 SCVAL(p2,21,0);           /* fix zero termination */
3480                 p2 = skip_string(*rdata,*rdata_len,p2);
3481                 if (!p2) {
3482                         return False;
3483                 }
3484
3485                 SSVAL(p,usri11_code_page,0);            /* code page */
3486         }
3487
3488         if (uLevel == 1 || uLevel == 2) {
3489                 memset(p+22,' ',16);    /* password */
3490                 SIVALS(p,38,-1);                /* password age */
3491                 SSVAL(p,42,
3492                 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3493                 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3494                 strlcpy(p2, vuser ? pdb_get_homedir(
3495                                 vuser->server_info->sam_account) : "",
3496                         PTR_DIFF(endp,p2));
3497                 p2 = skip_string(*rdata,*rdata_len,p2);
3498                 if (!p2) {
3499                         return False;
3500                 }
3501                 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3502                 *p2++ = 0;
3503                 SSVAL(p,52,0);          /* flags */
3504                 SIVAL(p,54,PTR_DIFF(p2,*rdata));                /* script_path */
3505                 strlcpy(p2, vuser ? pdb_get_logon_script(
3506                                 vuser->server_info->sam_account) : "",
3507                         PTR_DIFF(endp,p2));
3508                 p2 = skip_string(*rdata,*rdata_len,p2);
3509                 if (!p2) {
3510                         return False;
3511                 }
3512                 if (uLevel == 2) {
3513                         SIVAL(p,60,0);          /* auth_flags */
3514                         SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3515                         strlcpy(p2,((vuser != NULL)
3516                                     ? pdb_get_fullname(vuser->server_info->sam_account)
3517                                     : UserName),PTR_DIFF(endp,p2));
3518                         p2 = skip_string(*rdata,*rdata_len,p2);
3519                         if (!p2) {
3520                                 return False;
3521                         }
3522                         SIVAL(p,68,0);          /* urs_comment */
3523                         SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3524                         strlcpy(p2,"",PTR_DIFF(endp,p2));
3525                         p2 = skip_string(*rdata,*rdata_len,p2);
3526                         if (!p2) {
3527                                 return False;
3528                         }
3529                         SIVAL(p,76,0);          /* workstations */
3530                         SIVAL(p,80,0);          /* last_logon */
3531                         SIVAL(p,84,0);          /* last_logoff */
3532                         SIVALS(p,88,-1);                /* acct_expires */
3533                         SIVALS(p,92,-1);                /* max_storage */
3534                         SSVAL(p,96,168);        /* units_per_week */
3535                         SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3536                         memset(p2,-1,21);
3537                         p2 += 21;
3538                         SSVALS(p,102,-1);       /* bad_pw_count */
3539                         SSVALS(p,104,-1);       /* num_logons */
3540                         SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3541                         {
3542                                 TALLOC_CTX *ctx = talloc_tos();
3543                                 int space_rem = *rdata_len - (p2 - *rdata);
3544                                 char *tmp;
3545
3546                                 if (space_rem <= 0) {
3547                                         return false;
3548                                 }
3549                                 tmp = talloc_strdup(ctx, "\\\\%L");
3550                                 if (!tmp) {
3551                                         return false;
3552                                 }
3553                                 tmp = talloc_sub_basic(ctx,
3554                                                 "",
3555                                                 "",
3556                                                 tmp);
3557                                 if (!tmp) {
3558                                         return false;
3559                                 }
3560
3561                                 push_ascii(p2,
3562                                         tmp,
3563                                         space_rem,
3564                                         STR_TERMINATE);
3565                         }
3566                         p2 = skip_string(*rdata,*rdata_len,p2);
3567                         if (!p2) {
3568                                 return False;
3569                         }
3570                         SSVAL(p,110,49);        /* country_code */
3571                         SSVAL(p,112,860);       /* code page */
3572                 }
3573         }
3574
3575         *rdata_len = PTR_DIFF(p2,*rdata);
3576
3577         SSVAL(*rparam,4,*rdata_len);    /* is this right?? */
3578
3579         return(True);
3580 }
3581
3582 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3583                                 char *param, int tpscnt,
3584                                 char *data, int tdscnt,
3585                                 int mdrcnt,int mprcnt,
3586                                 char **rdata,char **rparam,
3587                                 int *rdata_len,int *rparam_len)
3588 {
3589         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3590         char *str2 = skip_string(param,tpscnt,str1);
3591         char *p = skip_string(param,tpscnt,str2);
3592         int uLevel;
3593         struct pack_desc desc;
3594         char* name;
3595                 /* With share level security vuid will always be zero.
3596                    Don't depend on vuser being non-null !!. JRA */
3597         user_struct *vuser = get_valid_user_struct(vuid);
3598
3599         if (!str1 || !str2 || !p) {
3600                 return False;
3601         }
3602
3603         if(vuser != NULL) {
3604                 DEBUG(3,("  Username of UID %d is %s\n",
3605                          (int)vuser->server_info->utok.uid,
3606                          vuser->server_info->unix_name));
3607         }
3608
3609         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3610         name = get_safe_str_ptr(param,tpscnt,p,2);
3611         if (!name) {
3612                 return False;
3613         }
3614
3615         memset((char *)&desc,'\0',sizeof(desc));
3616
3617         DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3618
3619         /* check it's a supported varient */
3620         if (strcmp(str1,"OOWb54WrLh") != 0) {
3621                 return False;
3622         }
3623         if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3624                 return False;
3625         }
3626         if (mdrcnt > 0) {
3627                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3628                 if (!*rdata) {
3629                         return False;
3630                 }
3631         }
3632
3633         desc.base = *rdata;
3634         desc.buflen = mdrcnt;
3635         desc.subformat = NULL;
3636         desc.format = str2;
3637   
3638         if (init_package(&desc,1,0)) {
3639                 PACKI(&desc,"W",0);             /* code */
3640                 PACKS(&desc,"B21",name);        /* eff. name */
3641                 PACKS(&desc,"B","");            /* pad */
3642                 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3643                 PACKI(&desc,"D",0);             /* auth flags XXX */
3644                 PACKI(&desc,"W",0);             /* num logons */
3645                 PACKI(&desc,"W",0);             /* bad pw count */
3646                 PACKI(&desc,"D",0);             /* last logon */
3647                 PACKI(&desc,"D",-1);            /* last logoff */
3648                 PACKI(&desc,"D",-1);            /* logoff time */
3649                 PACKI(&desc,"D",-1);            /* kickoff time */
3650                 PACKI(&desc,"D",0);             /* password age */
3651                 PACKI(&desc,"D",0);             /* password can change */
3652                 PACKI(&desc,"D",-1);            /* password must change */
3653
3654                 {
3655                         fstring mypath;
3656                         fstrcpy(mypath,"\\\\");
3657                         fstrcat(mypath,get_local_machine_name());
3658                         strupper_m(mypath);
3659                         PACKS(&desc,"z",mypath); /* computer */
3660                 }
3661
3662                 PACKS(&desc,"z",lp_workgroup());/* domain */
3663                 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3664                               vuser->server_info->sam_account) : ""); /* script path */
3665                 PACKI(&desc,"D",0x00000000);            /* reserved */
3666         }
3667
3668         *rdata_len = desc.usedlen;
3669         *rparam_len = 6;
3670         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3671         if (!*rparam) {
3672                 return False;
3673         }
3674         SSVALS(*rparam,0,desc.errcode);
3675         SSVAL(*rparam,2,0);
3676         SSVAL(*rparam,4,desc.neededlen);
3677
3678         DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3679
3680         return True;
3681 }
3682
3683 /****************************************************************************
3684  api_WAccessGetUserPerms
3685 ****************************************************************************/
3686
3687 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3688                                 char *param, int tpscnt,
3689                                 char *data, int tdscnt,
3690                                 int mdrcnt,int mprcnt,
3691                                 char **rdata,char **rparam,
3692                                 int *rdata_len,int *rparam_len)
3693 {
3694         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3695         char *str2 = skip_string(param,tpscnt,str1);
3696         char *user = skip_string(param,tpscnt,str2);
3697         char *resource = skip_string(param,tpscnt,user);
3698
3699         if (!str1 || !str2 || !user || !resource) {
3700                 return False;
3701         }
3702
3703         if (skip_string(param,tpscnt,resource) == NULL) {
3704                 return False;
3705         }
3706         DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3707
3708         /* check it's a supported varient */
3709         if (strcmp(str1,"zzh") != 0) {
3710                 return False;
3711         }
3712         if (strcmp(str2,"") != 0) {
3713                 return False;
3714         }
3715
3716         *rparam_len = 6;
3717         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3718         if (!*rparam) {
3719                 return False;
3720         }
3721         SSVALS(*rparam,0,0);            /* errorcode */
3722         SSVAL(*rparam,2,0);             /* converter word */
3723         SSVAL(*rparam,4,0x7f);  /* permission flags */
3724
3725         return True;
3726 }
3727
3728 /****************************************************************************
3729   api_WPrintJobEnumerate
3730   ****************************************************************************/
3731
3732 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3733                                 char *param, int tpscnt,
3734                                 char *data, int tdscnt,
3735                                 int mdrcnt,int mprcnt,
3736                                 char **rdata,char **rparam,
3737                                 int *rdata_len,int *rparam_len)
3738 {
3739         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3740         char *str2 = skip_string(param,tpscnt,str1);
3741         char *p = skip_string(param,tpscnt,str2);
3742         int uLevel;
3743         int count;
3744         int i;
3745         int snum;
3746         fstring sharename;
3747         uint32 jobid;
3748         struct pack_desc desc;
3749         print_queue_struct *queue=NULL;
3750         print_status_struct status;
3751         char *tmpdata=NULL;
3752
3753         if (!str1 || !str2 || !p) {
3754                 return False;
3755         }
3756
3757         uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3758
3759         memset((char *)&desc,'\0',sizeof(desc));
3760         memset((char *)&status,'\0',sizeof(status));
3761
3762         DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3763
3764         /* check it's a supported varient */
3765         if (strcmp(str1,"WWrLh") != 0) {
3766                 return False;
3767         }
3768         if (!check_printjob_info(&desc,uLevel,str2)) {
3769                 return False;
3770         }
3771
3772         if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3773                 return False;
3774         }
3775
3776         snum = lp_servicenumber( sharename);
3777         if (snum < 0 || !VALID_SNUM(snum)) {
3778                 return(False);
3779         }
3780
3781         count = print_queue_status(snum,&queue,&status);
3782         for (i = 0; i < count; i++) {
3783                 if (queue[i].job == jobid) {
3784                         break;
3785                 }
3786         }
3787
3788         if (mdrcnt > 0) {
3789                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3790                 if (!*rdata) {
3791                         return False;
3792                 }
3793                 desc.base = *rdata;
3794                 desc.buflen = mdrcnt;
3795         } else {
3796                 /*
3797                  * Don't return data but need to get correct length
3798                  *  init_package will return wrong size if buflen=0
3799                  */
3800                 desc.buflen = getlen(desc.format);
3801                 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3802         }
3803
3804         if (init_package(&desc,1,0)) {
3805                 if (i < count) {
3806                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3807                         *rdata_len = desc.usedlen;
3808                 } else {
3809                         desc.errcode = NERR_JobNotFound;
3810                         *rdata_len = 0;
3811                 }
3812         }
3813
3814         *rparam_len = 6;
3815         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3816         if (!*rparam) {
3817                 return False;
3818         }
3819         SSVALS(*rparam,0,desc.errcode);
3820         SSVAL(*rparam,2,0);
3821         SSVAL(*rparam,4,desc.neededlen);
3822
3823         SAFE_FREE(queue);
3824         SAFE_FREE(tmpdata);
3825
3826         DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3827
3828         return True;
3829 }
3830
3831 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3832                                 char *param, int tpscnt,
3833                                 char *data, int tdscnt,
3834                                 int mdrcnt,int mprcnt,
3835                                 char **rdata,char **rparam,
3836                                 int *rdata_len,int *rparam_len)
3837 {
3838         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3839         char *str2 = skip_string(param,tpscnt,str1);
3840         char *p = skip_string(param,tpscnt,str2);
3841         char *name = p;
3842         int uLevel;
3843         int count;
3844         int i, succnt=0;
3845         int snum;
3846         struct pack_desc desc;
3847         print_queue_struct *queue=NULL;
3848         print_status_struct status;
3849
3850         if (!str1 || !str2 || !p) {
3851                 return False;
3852         }
3853
3854         memset((char *)&desc,'\0',sizeof(desc));
3855         memset((char *)&status,'\0',sizeof(status));
3856
3857         p = skip_string(param,tpscnt,p);
3858         if (!p) {
3859                 return False;
3860         }
3861         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3862
3863         DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3864
3865         /* check it's a supported variant */
3866         if (strcmp(str1,"zWrLeh") != 0) {
3867                 return False;
3868         }
3869     
3870         if (uLevel > 2) {
3871                 return False;   /* defined only for uLevel 0,1,2 */
3872         }
3873     
3874         if (!check_printjob_info(&desc,uLevel,str2)) { 
3875                 return False;
3876         }
3877
3878         snum = find_service(name);
3879         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3880                 return False;
3881         }
3882
3883         count = print_queue_status(snum,&queue,&status);
3884         if (mdrcnt > 0) {
3885                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3886                 if (!*rdata) {
3887                         return False;
3888                 }
3889         }
3890         desc.base = *rdata;
3891         desc.buflen = mdrcnt;
3892
3893         if (init_package(&desc,count,0)) {
3894                 succnt = 0;
3895                 for (i = 0; i < count; i++) {
3896                         fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3897                         if (desc.errcode == NERR_Success) {
3898                                 succnt = i+1;
3899                         }
3900                 }
3901         }
3902
3903         *rdata_len = desc.usedlen;
3904
3905         *rparam_len = 8;
3906         *rparam = smb_realloc_limit(*rparam,*rparam_len);
3907         if (!*rparam) {
3908                 return False;
3909         }
3910         SSVALS(*rparam,0,desc.errcode);
3911         SSVAL(*rparam,2,0);
3912         SSVAL(*rparam,4,succnt);
3913         SSVAL(*rparam,6,count);
3914
3915         SAFE_FREE(queue);
3916
3917         DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3918
3919         return True;
3920 }
3921
3922 static int check_printdest_info(struct pack_desc* desc,
3923                                 int uLevel, char* id)
3924 {
3925         desc->subformat = NULL;
3926         switch( uLevel ) {
3927                 case 0:
3928                         desc->format = "B9";
3929                         break;
3930                 case 1:
3931                         desc->format = "B9B21WWzW";
3932                         break;
3933                 case 2:
3934                         desc->format = "z";
3935                         break;
3936                 case 3:
3937                         desc->format = "zzzWWzzzWW";
3938                         break;
3939                 default:
3940                         DEBUG(0,("check_printdest_info: invalid level %d\n",
3941                                 uLevel));
3942                         return False;
3943         }
3944         if (id == NULL || strcmp(desc->format,id) != 0) {
3945                 DEBUG(0,("check_printdest_info: invalid string %s\n", 
3946                         id ? id : "<NULL>" ));
3947                 return False;
3948         }
3949         return True;
3950 }
3951
3952 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3953                                 struct pack_desc* desc)
3954 {
3955         char buf[100];
3956
3957         strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3958         buf[sizeof(buf)-1] = 0;
3959         strupper_m(buf);
3960
3961         if (uLevel <= 1) {
3962                 PACKS(desc,"B9",buf);   /* szName */
3963                 if (uLevel == 1) {
3964                         PACKS(desc,"B21","");   /* szUserName */
3965                         PACKI(desc,"W",0);              /* uJobId */
3966                         PACKI(desc,"W",0);              /* fsStatus */
3967                         PACKS(desc,"z","");     /* pszStatus */
3968                         PACKI(desc,"W",0);              /* time */
3969                 }
3970         }
3971
3972         if (uLevel == 2 || uLevel == 3) {
3973                 PACKS(desc,"z",buf);            /* pszPrinterName */
3974                 if (uLevel == 3) {
3975                         PACKS(desc,"z","");     /* pszUserName */
3976                         PACKS(desc,"z","");     /* pszLogAddr */
3977                         PACKI(desc,"W",0);              /* uJobId */
3978                         PACKI(desc,"W",0);              /* fsStatus */
3979                         PACKS(desc,"z","");     /* pszStatus */
3980                         PACKS(desc,"z","");     /* pszComment */
3981                         PACKS(desc,"z","NULL"); /* pszDrivers */
3982                         PACKI(desc,"W",0);              /* time */
3983                         PACKI(desc,"W",0);              /* pad1 */
3984                 }
3985         }
3986 }
3987
3988 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3989                                 char *param, int tpscnt,
3990                                 char *data, int tdscnt,
3991                                 int mdrcnt,int mprcnt,
3992                                 char **rdata,char **rparam,
3993                                 int *rdata_len,int *rparam_len)
3994 {
3995         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3996         char *str2 = skip_string(param,tpscnt,str1);
3997         char *p = skip_string(param,tpscnt,str2);
3998         char* PrinterName = p;
3999         int uLevel;
4000         struct pack_desc desc;
4001         int snum;
4002         char *tmpdata=NULL;
4003
4004         if (!str1 || !str2 || !p) {
4005                 return False;
4006         }
4007
4008         memset((char *)&desc,'\0',sizeof(desc));
4009
4010         p = skip_string(param,tpscnt,p);
4011         if (!p) {
4012                 return False;
4013         }
4014         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4015
4016         DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4017
4018         /* check it's a supported varient */
4019         if (strcmp(str1,"zWrLh") != 0) {
4020                 return False;
4021         }
4022         if (!check_printdest_info(&desc,uLevel,str2)) {
4023                 return False;
4024         }
4025
4026         snum = find_service(PrinterName);
4027         if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4028                 *rdata_len = 0;
4029                 desc.errcode = NERR_DestNotFound;
4030                 desc.neededlen = 0;
4031         } else {
4032                 if (mdrcnt > 0) {
4033                         *rdata = smb_realloc_limit(*rdata,mdrcnt);
4034                         if (!*rdata) {
4035                                 return False;
4036                         }
4037                         desc.base = *rdata;
4038                         desc.buflen = mdrcnt;
4039                 } else {
4040                         /*
4041                          * Don't return data but need to get correct length
4042                          * init_package will return wrong size if buflen=0
4043                          */
4044                         desc.buflen = getlen(desc.format);
4045                         desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4046                 }
4047                 if (init_package(&desc,1,0)) {
4048                         fill_printdest_info(conn,snum,uLevel,&desc);
4049                 }
4050                 *rdata_len = desc.usedlen;
4051         }
4052
4053         *rparam_len = 6;
4054         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4055         if (!*rparam) {
4056                 return False;
4057         }
4058         SSVALS(*rparam,0,desc.errcode);
4059         SSVAL(*rparam,2,0);
4060         SSVAL(*rparam,4,desc.neededlen);
4061
4062         DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4063         SAFE_FREE(tmpdata);
4064
4065         return True;
4066 }
4067
4068 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4069                                 char *param, int tpscnt,
4070                                 char *data, int tdscnt,
4071                                 int mdrcnt,int mprcnt,
4072                                 char **rdata,char **rparam,
4073                                 int *rdata_len,int *rparam_len)
4074 {
4075         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4076         char *str2 = skip_string(param,tpscnt,str1);
4077         char *p = skip_string(param,tpscnt,str2);
4078         int uLevel;
4079         int queuecnt;
4080         int i, n, succnt=0;
4081         struct pack_desc desc;
4082         int services = lp_numservices();
4083
4084         if (!str1 || !str2 || !p) {
4085                 return False;
4086         }
4087
4088         memset((char *)&desc,'\0',sizeof(desc));
4089
4090         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4091
4092         DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4093
4094         /* check it's a supported varient */
4095         if (strcmp(str1,"WrLeh") != 0) {
4096                 return False;
4097         }
4098         if (!check_printdest_info(&desc,uLevel,str2)) {
4099                 return False;
4100         }
4101
4102         queuecnt = 0;
4103         for (i = 0; i < services; i++) {
4104                 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4105                         queuecnt++;
4106                 }
4107         }
4108
4109         if (mdrcnt > 0) {
4110                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4111                 if (!*rdata) {
4112                         return False;
4113                 }
4114         }
4115
4116         desc.base = *rdata;
4117         desc.buflen = mdrcnt;
4118         if (init_package(&desc,queuecnt,0)) {    
4119                 succnt = 0;
4120                 n = 0;
4121                 for (i = 0; i < services; i++) {
4122                         if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4123                                 fill_printdest_info(conn,i,uLevel,&desc);
4124                                 n++;
4125                                 if (desc.errcode == NERR_Success) {
4126                                         succnt = n;
4127                                 }
4128                         }
4129                 }
4130         }
4131
4132         *rdata_len = desc.usedlen;
4133
4134         *rparam_len = 8;
4135         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4136         if (!*rparam) {
4137                 return False;
4138         }
4139         SSVALS(*rparam,0,desc.errcode);
4140         SSVAL(*rparam,2,0);
4141         SSVAL(*rparam,4,succnt);
4142         SSVAL(*rparam,6,queuecnt);
4143
4144         DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4145
4146         return True;
4147 }
4148
4149 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4150                                 char *param, int tpscnt,
4151                                 char *data, int tdscnt,
4152                                 int mdrcnt,int mprcnt,
4153                                 char **rdata,char **rparam,
4154                                 int *rdata_len,int *rparam_len)
4155 {
4156         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4157         char *str2 = skip_string(param,tpscnt,str1);
4158         char *p = skip_string(param,tpscnt,str2);
4159         int uLevel;
4160         int succnt;
4161         struct pack_desc desc;
4162
4163         if (!str1 || !str2 || !p) {
4164                 return False;
4165         }
4166
4167         memset((char *)&desc,'\0',sizeof(desc));
4168
4169         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4170
4171         DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4172
4173         /* check it's a supported varient */
4174         if (strcmp(str1,"WrLeh") != 0) {
4175                 return False;
4176         }
4177         if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4178                 return False;
4179         }
4180
4181         if (mdrcnt > 0) {
4182                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4183                 if (!*rdata) {
4184                         return False;
4185                 }
4186         }
4187         desc.base = *rdata;
4188         desc.buflen = mdrcnt;
4189         if (init_package(&desc,1,0)) {
4190                 PACKS(&desc,"B41","NULL");
4191         }
4192
4193         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4194
4195         *rdata_len = desc.usedlen;
4196
4197         *rparam_len = 8;
4198         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4199         if (!*rparam) {
4200                 return False;
4201         }
4202         SSVALS(*rparam,0,desc.errcode);
4203         SSVAL(*rparam,2,0);
4204         SSVAL(*rparam,4,succnt);
4205         SSVAL(*rparam,6,1);
4206
4207         DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4208
4209         return True;
4210 }
4211
4212 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4213                                 char *param, int tpscnt,
4214                                 char *data, int tdscnt,
4215                                 int mdrcnt,int mprcnt,
4216                                 char **rdata,char **rparam,
4217                                 int *rdata_len,int *rparam_len)
4218 {
4219         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4220         char *str2 = skip_string(param,tpscnt,str1);
4221         char *p = skip_string(param,tpscnt,str2);
4222         int uLevel;
4223         int succnt;
4224         struct pack_desc desc;
4225
4226         if (!str1 || !str2 || !p) {
4227                 return False;
4228         }
4229         memset((char *)&desc,'\0',sizeof(desc));
4230
4231         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4232
4233         DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4234
4235         /* check it's a supported varient */
4236         if (strcmp(str1,"WrLeh") != 0) {
4237                 return False;
4238         }
4239         if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4240                 return False;
4241         }
4242
4243         if (mdrcnt > 0) {
4244                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4245                 if (!*rdata) {
4246                         return False;
4247                 }
4248         }
4249         desc.base = *rdata;
4250         desc.buflen = mdrcnt;
4251         desc.format = str2;
4252         if (init_package(&desc,1,0)) {
4253                 PACKS(&desc,"B13","lpd");
4254         }
4255
4256         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4257
4258         *rdata_len = desc.usedlen;
4259
4260         *rparam_len = 8;
4261         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4262         if (!*rparam) {
4263                 return False;
4264         }
4265         SSVALS(*rparam,0,desc.errcode);
4266         SSVAL(*rparam,2,0);
4267         SSVAL(*rparam,4,succnt);
4268         SSVAL(*rparam,6,1);
4269
4270         DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4271
4272         return True;
4273 }
4274
4275 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4276                                 char *param, int tpscnt,
4277                                 char *data, int tdscnt,
4278                                 int mdrcnt,int mprcnt,
4279                                 char **rdata,char **rparam,
4280                                 int *rdata_len,int *rparam_len)
4281 {
4282         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4283         char *str2 = skip_string(param,tpscnt,str1);
4284         char *p = skip_string(param,tpscnt,str2);
4285         int uLevel;
4286         int succnt;
4287         struct pack_desc desc;
4288
4289         if (!str1 || !str2 || !p) {
4290                 return False;
4291         }
4292
4293         memset((char *)&desc,'\0',sizeof(desc));
4294
4295         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4296
4297         DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4298
4299         /* check it's a supported varient */
4300         if (strcmp(str1,"WrLeh") != 0) {
4301                 return False;
4302         }
4303         if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4304                 return False;
4305         }
4306
4307         if (mdrcnt > 0) {
4308                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4309                 if (!*rdata) {
4310                         return False;
4311                 }
4312         }
4313         memset((char *)&desc,'\0',sizeof(desc));
4314         desc.base = *rdata;
4315         desc.buflen = mdrcnt;
4316         desc.format = str2;
4317         if (init_package(&desc,1,0)) {
4318                 PACKS(&desc,"B13","lp0");
4319         }
4320
4321         succnt = (desc.errcode == NERR_Success ? 1 : 0);
4322
4323         *rdata_len = desc.usedlen;
4324
4325         *rparam_len = 8;
4326         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4327         if (!*rparam) {
4328                 return False;
4329         }
4330         SSVALS(*rparam,0,desc.errcode);
4331         SSVAL(*rparam,2,0);
4332         SSVAL(*rparam,4,succnt);
4333         SSVAL(*rparam,6,1);
4334
4335         DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4336
4337         return True;
4338 }
4339
4340 /****************************************************************************
4341  List open sessions
4342  ****************************************************************************/
4343
4344 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4345                                 char *param, int tpscnt,
4346                                 char *data, int tdscnt,
4347                                 int mdrcnt,int mprcnt,
4348                                 char **rdata,char **rparam,
4349                                 int *rdata_len,int *rparam_len)
4350
4351 {
4352         char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4353         char *str2 = skip_string(param,tpscnt,str1);
4354         char *p = skip_string(param,tpscnt,str2);
4355         int uLevel;
4356         struct pack_desc desc;
4357         struct sessionid *session_list;
4358         int i, num_sessions;
4359
4360         if (!str1 || !str2 || !p) {
4361                 return False;
4362         }
4363
4364         memset((char *)&desc,'\0',sizeof(desc));
4365
4366         uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4367
4368         DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4369         DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4370         DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4371
4372         /* check it's a supported varient */
4373         if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4374                 return False;
4375         }
4376         if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4377                 return False;
4378         }
4379
4380         num_sessions = list_sessions(talloc_tos(), &session_list);
4381
4382         if (mdrcnt > 0) {
4383                 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4384                 if (!*rdata) {
4385                         return False;
4386                 }
4387         }
4388         memset((char *)&desc,'\0',sizeof(desc));
4389         desc.base = *rdata;
4390         desc.buflen = mdrcnt;
4391         desc.format = str2;
4392         if (!init_package(&desc,num_sessions,0)) {
4393                 return False;
4394         }
4395
4396         for(i=0; i<num_sessions; i++) {
4397                 PACKS(&desc, "z", session_list[i].remote_machine);
4398                 PACKS(&desc, "z", session_list[i].username);
4399                 PACKI(&desc, "W", 1); /* num conns */
4400                 PACKI(&desc, "W", 0); /* num opens */
4401                 PACKI(&desc, "W", 1); /* num users */
4402                 PACKI(&desc, "D", 0); /* session time */
4403                 PACKI(&desc, "D", 0); /* idle time */
4404                 PACKI(&desc, "D", 0); /* flags */
4405                 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4406         }
4407
4408         *rdata_len = desc.usedlen;
4409
4410         *rparam_len = 8;
4411         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4412         if (!*rparam) {
4413                 return False;
4414         }
4415         SSVALS(*rparam,0,desc.errcode);
4416         SSVAL(*rparam,2,0); /* converter */
4417         SSVAL(*rparam,4,num_sessions); /* count */
4418
4419         DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4420
4421         return True;
4422 }
4423
4424
4425 /****************************************************************************
4426  The buffer was too small.
4427  ****************************************************************************/
4428
4429 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4430                          int mdrcnt, int mprcnt,
4431                          char **rdata, char **rparam,
4432                          int *rdata_len, int *rparam_len)
4433 {
4434         *rparam_len = MIN(*rparam_len,mprcnt);
4435         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4436         if (!*rparam) {
4437                 return False;
4438         }
4439
4440         *rdata_len = 0;
4441
4442         SSVAL(*rparam,0,NERR_BufTooSmall);
4443
4444         DEBUG(3,("Supplied buffer too small in API command\n"));
4445
4446         return True;
4447 }
4448
4449 /****************************************************************************
4450  The request is not supported.
4451  ****************************************************************************/
4452
4453 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4454                                 char *param, int tpscnt,
4455                                 char *data, int tdscnt,
4456                                 int mdrcnt, int mprcnt,
4457                                 char **rdata, char **rparam,
4458                                 int *rdata_len, int *rparam_len)
4459 {
4460         *rparam_len = 4;
4461         *rparam = smb_realloc_limit(*rparam,*rparam_len);
4462         if (!*rparam) {
4463                 return False;
4464         }
4465
4466         *rdata_len = 0;
4467
4468         SSVAL(*rparam,0,NERR_notsupported);
4469         SSVAL(*rparam,2,0);             /* converter word */
4470
4471         DEBUG(3,("Unsupported API command\n"));
4472
4473         return True;
4474 }
4475
4476 static const struct {
4477         const char *name;
4478         int id;
4479         bool (*fn)(connection_struct *, uint16,
4480                         char *, int,
4481                         char *, int,
4482                         int,int,char **,char **,int *,int *);
4483         bool auth_user;         /* Deny anonymous access? */
4484 } api_commands[] = {
4485         {"RNetShareEnum",       RAP_WshareEnum,         api_RNetShareEnum, True},
4486         {"RNetShareGetInfo",    RAP_WshareGetInfo,      api_RNetShareGetInfo},
4487         {"RNetShareAdd",        RAP_WshareAdd,          api_RNetShareAdd},
4488         {"RNetSessionEnum",     RAP_WsessionEnum,       api_RNetSessionEnum, True},
4489         {"RNetServerGetInfo",   RAP_WserverGetInfo,     api_RNetServerGetInfo},
4490         {"RNetGroupEnum",       RAP_WGroupEnum,         api_RNetGroupEnum, True},
4491         {"RNetGroupGetUsers", RAP_WGroupGetUsers,       api_RNetGroupGetUsers, True},
4492         {"RNetUserEnum",        RAP_WUserEnum,          api_RNetUserEnum, True},
4493         {"RNetUserGetInfo",     RAP_WUserGetInfo,       api_RNetUserGetInfo},
4494         {"NetUserGetGroups",    RAP_WUserGetGroups,     api_NetUserGetGroups},
4495         {"NetWkstaGetInfo",     RAP_WWkstaGetInfo,      api_NetWkstaGetInfo},
4496         {"DosPrintQEnum",       RAP_WPrintQEnum,        api_DosPrintQEnum, True},
4497         {"DosPrintQGetInfo",    RAP_WPrintQGetInfo,     api_DosPrintQGetInfo},
4498         {"WPrintQueuePause",  RAP_WPrintQPause, api_WPrintQueueCtrl},
4499         {"WPrintQueueResume", RAP_WPrintQContinue,      api_WPrintQueueCtrl},
4500         {"WPrintJobEnumerate",RAP_WPrintJobEnum,        api_WPrintJobEnumerate},
4501         {"WPrintJobGetInfo",    RAP_WPrintJobGetInfo,   api_WPrintJobGetInfo},
4502         {"RDosPrintJobDel",     RAP_WPrintJobDel,       api_RDosPrintJobDel},
4503         {"RDosPrintJobPause",   RAP_WPrintJobPause,     api_RDosPrintJobDel},
4504         {"RDosPrintJobResume",RAP_WPrintJobContinue,    api_RDosPrintJobDel},
4505         {"WPrintDestEnum",      RAP_WPrintDestEnum,     api_WPrintDestEnum},
4506         {"WPrintDestGetInfo",   RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo},
4507         {"NetRemoteTOD",        RAP_NetRemoteTOD,       api_NetRemoteTOD},
4508         {"WPrintQueuePurge",    RAP_WPrintQPurge,       api_WPrintQueueCtrl},
4509         {"NetServerEnum",       RAP_NetServerEnum2,     api_RNetServerEnum}, /* anon OK */
4510         {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4511         {"SetUserPassword",     RAP_WUserPasswordSet2,  api_SetUserPassword},
4512         {"WWkstaUserLogon",     RAP_WWkstaUserLogon,    api_WWkstaUserLogon},
4513         {"PrintJobInfo",        RAP_WPrintJobSetInfo,   api_PrintJobInfo},
4514         {"WPrintDriverEnum",    RAP_WPrintDriverEnum,   api_WPrintDriverEnum},
4515         {"WPrintQProcEnum",     RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4516         {"WPrintPortEnum",      RAP_WPrintPortEnum,     api_WPrintPortEnum},
4517         {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4518         {NULL,          -1,     api_Unsupported}
4519         /*  The following RAP calls are not implemented by Samba:
4520
4521         RAP_WFileEnum2 - anon not OK 
4522         */
4523 };
4524
4525
4526 /****************************************************************************
4527  Handle remote api calls.
4528 ****************************************************************************/
4529
4530 void api_reply(connection_struct *conn, uint16 vuid,
4531                struct smb_request *req,
4532                char *data, char *params,
4533                int tdscnt, int tpscnt,
4534                int mdrcnt, int mprcnt)
4535 {
4536         int api_command;
4537         char *rdata = NULL;
4538         char *rparam = NULL;
4539         const char *name1 = NULL;
4540         const char *name2 = NULL;
4541         int rdata_len = 0;
4542         int rparam_len = 0;
4543         bool reply=False;
4544         int i;
4545
4546         if (!params) {
4547                 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4548                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4549                 return;
4550         }
4551
4552         if (tpscnt < 2) {
4553                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4554                 return;
4555         }
4556         api_command = SVAL(params,0);
4557         /* Is there a string at position params+2 ? */
4558         if (skip_string(params,tpscnt,params+2)) {
4559                 name1 = params + 2;
4560         } else {
4561                 name1 = "";
4562         }
4563         name2 = skip_string(params,tpscnt,params+2);
4564         if (!name2) {
4565                 name2 = "";
4566         }
4567
4568         DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4569                 api_command,
4570                 name1,
4571                 name2,
4572                 tdscnt,tpscnt,mdrcnt,mprcnt));
4573
4574         for (i=0;api_commands[i].name;i++) {
4575                 if (api_commands[i].id == api_command && api_commands[i].fn) {
4576                         DEBUG(3,("Doing %s\n",api_commands[i].name));
4577                         break;
4578                 }
4579         }
4580
4581         /* Check whether this api call can be done anonymously */
4582
4583         if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4584                 user_struct *user = get_valid_user_struct(vuid);
4585
4586                 if (!user || user->server_info->guest) {
4587                         reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4588                         return;
4589                 }
4590         }
4591
4592         rdata = (char *)SMB_MALLOC(1024);
4593         if (rdata) {
4594                 memset(rdata,'\0',1024);
4595         }
4596
4597         rparam = (char *)SMB_MALLOC(1024);
4598         if (rparam) {
4599                 memset(rparam,'\0',1024);
4600         }
4601
4602         if(!rdata || !rparam) {
4603                 DEBUG(0,("api_reply: malloc fail !\n"));
4604                 SAFE_FREE(rdata);
4605                 SAFE_FREE(rparam);
4606                 reply_nterror(req, NT_STATUS_NO_MEMORY);
4607                 return;
4608         }
4609
4610         reply = api_commands[i].fn(conn,
4611                                 vuid,
4612                                 params,tpscnt,  /* params + length */
4613                                 data,tdscnt,    /* data + length */
4614                                 mdrcnt,mprcnt,
4615                                 &rdata,&rparam,&rdata_len,&rparam_len);
4616
4617
4618         if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4619                 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4620                                         &rdata,&rparam,&rdata_len,&rparam_len);
4621         }
4622
4623         /* if we get False back then it's actually unsupported */
4624         if (!reply) {
4625                 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4626                         &rdata,&rparam,&rdata_len,&rparam_len);
4627         }
4628
4629         /* If api_Unsupported returns false we can't return anything. */
4630         if (reply) {
4631                 send_trans_reply(conn, req, rparam, rparam_len,
4632                                  rdata, rdata_len, False);
4633         }
4634
4635         SAFE_FREE(rdata);
4636         SAFE_FREE(rparam);
4637         return;
4638 }