[GLUE] Rsync SAMBA_3_0 SVN r25598 in order to create the v3-0-test branch.
[Samba.git] / source / smbd / lanman.c
blobff2044b2eb988e3ef91b67b9be3b83cf822e8ff0
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.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
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 2 of the License, or
13 (at your option) any later version.
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.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 This file handles the named pipe and mailslot calls
26 in the SMBtrans protocol
29 #include "includes.h"
31 extern struct current_user current_user;
32 extern userdom_struct current_user_info;
34 #ifdef CHECK_TYPES
35 #undef CHECK_TYPES
36 #endif
37 #define CHECK_TYPES 0
39 #define NERR_Success 0
40 #define NERR_badpass 86
41 #define NERR_notsupported 50
43 #define NERR_BASE (2100)
44 #define NERR_BufTooSmall (NERR_BASE+23)
45 #define NERR_JobNotFound (NERR_BASE+51)
46 #define NERR_DestNotFound (NERR_BASE+52)
48 #define ACCESS_READ 0x01
49 #define ACCESS_WRITE 0x02
50 #define ACCESS_CREATE 0x04
52 #define SHPWLEN 8 /* share password length */
54 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
55 char *param, int tpscnt,
56 char *data, int tdscnt,
57 int mdrcnt, int mprcnt,
58 char **rdata, char **rparam,
59 int *rdata_len, int *rparam_len);
61 static BOOL api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
62 int mdrcnt, int mprcnt,
63 char **rdata, char **rparam,
64 int *rdata_len, int *rparam_len);
67 static int CopyExpanded(connection_struct *conn,
68 int snum, char **dst, char *src, int *n)
70 pstring buf;
71 int l;
73 if (!src || !dst || !n || !(*dst)) {
74 return 0;
77 StrnCpy(buf,src,sizeof(buf)/2);
78 pstring_sub(buf,"%S",lp_servicename(snum));
79 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
80 conn->connectpath, conn->gid,
81 get_current_username(),
82 current_user_info.domain,
83 buf, sizeof(buf));
84 l = push_ascii(*dst,buf,*n, STR_TERMINATE);
85 (*dst) += l;
86 (*n) -= l;
87 return l;
90 static int CopyAndAdvance(char **dst, char *src, int *n)
92 int l;
93 if (!src || !dst || !n || !(*dst)) {
94 return 0;
96 l = push_ascii(*dst,src,*n, STR_TERMINATE);
97 (*dst) += l;
98 (*n) -= l;
99 return l;
102 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
104 pstring buf;
105 if (!s) {
106 return 0;
108 StrnCpy(buf,s,sizeof(buf)/2);
109 pstring_sub(buf,"%S",lp_servicename(snum));
110 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
111 conn->connectpath, conn->gid,
112 get_current_username(),
113 current_user_info.domain,
114 buf, sizeof(buf));
115 return strlen(buf) + 1;
118 static char *Expand(connection_struct *conn, int snum, char *s)
120 static pstring buf;
121 if (!s) {
122 return NULL;
124 StrnCpy(buf,s,sizeof(buf)/2);
125 pstring_sub(buf,"%S",lp_servicename(snum));
126 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
127 conn->connectpath, conn->gid,
128 get_current_username(),
129 current_user_info.domain,
130 buf, sizeof(buf));
131 return &buf[0];
134 /*******************************************************************
135 Check a API string for validity when we only need to check the prefix.
136 ******************************************************************/
138 static BOOL prefix_ok(const char *str, const char *prefix)
140 return(strncmp(str,prefix,strlen(prefix)) == 0);
143 struct pack_desc {
144 const char *format; /* formatstring for structure */
145 const char *subformat; /* subformat for structure */
146 char *base; /* baseaddress of buffer */
147 int buflen; /* remaining size for fixed part; on init: length of base */
148 int subcount; /* count of substructures */
149 char *structbuf; /* pointer into buffer for remaining fixed part */
150 int stringlen; /* remaining size for variable part */
151 char *stringbuf; /* pointer into buffer for remaining variable part */
152 int neededlen; /* total needed size */
153 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
154 const char *curpos; /* current position; pointer into format or subformat */
155 int errcode;
158 static int get_counter(const char **p)
160 int i, n;
161 if (!p || !(*p)) {
162 return 1;
164 if (!isdigit((int)**p)) {
165 return 1;
167 for (n = 0;;) {
168 i = **p;
169 if (isdigit(i)) {
170 n = 10 * n + (i - '0');
171 } else {
172 return n;
174 (*p)++;
178 static int getlen(const char *p)
180 int n = 0;
181 if (!p) {
182 return 0;
185 while (*p) {
186 switch( *p++ ) {
187 case 'W': /* word (2 byte) */
188 n += 2;
189 break;
190 case 'K': /* status word? (2 byte) */
191 n += 2;
192 break;
193 case 'N': /* count of substructures (word) at end */
194 n += 2;
195 break;
196 case 'D': /* double word (4 byte) */
197 case 'z': /* offset to zero terminated string (4 byte) */
198 case 'l': /* offset to user data (4 byte) */
199 n += 4;
200 break;
201 case 'b': /* offset to data (with counter) (4 byte) */
202 n += 4;
203 get_counter(&p);
204 break;
205 case 'B': /* byte (with optional counter) */
206 n += get_counter(&p);
207 break;
210 return n;
213 static BOOL init_package(struct pack_desc *p, int count, int subcount)
215 int n = p->buflen;
216 int i;
218 if (!p->format || !p->base) {
219 return False;
222 i = count * getlen(p->format);
223 if (p->subformat) {
224 i += subcount * getlen(p->subformat);
226 p->structbuf = p->base;
227 p->neededlen = 0;
228 p->usedlen = 0;
229 p->subcount = 0;
230 p->curpos = p->format;
231 if (i > n) {
232 p->neededlen = i;
233 i = n = 0;
234 #if 0
236 * This is the old error code we used. Aparently
237 * WinNT/2k systems return ERRbuftoosmall (2123) and
238 * OS/2 needs this. I'm leaving this here so we can revert
239 * if needed. JRA.
241 p->errcode = ERRmoredata;
242 #else
243 p->errcode = ERRbuftoosmall;
244 #endif
245 } else {
246 p->errcode = NERR_Success;
248 p->buflen = i;
249 n -= i;
250 p->stringbuf = p->base + i;
251 p->stringlen = n;
252 return (p->errcode == NERR_Success);
255 static int package(struct pack_desc *p, ...)
257 va_list args;
258 int needed=0, stringneeded;
259 const char *str=NULL;
260 int is_string=0, stringused;
261 int32 temp;
263 va_start(args,p);
265 if (!*p->curpos) {
266 if (!p->subcount) {
267 p->curpos = p->format;
268 } else {
269 p->curpos = p->subformat;
270 p->subcount--;
273 #if CHECK_TYPES
274 str = va_arg(args,char*);
275 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
276 #endif
277 stringneeded = -1;
279 if (!p->curpos) {
280 va_end(args);
281 return 0;
284 switch( *p->curpos++ ) {
285 case 'W': /* word (2 byte) */
286 needed = 2;
287 temp = va_arg(args,int);
288 if (p->buflen >= needed) {
289 SSVAL(p->structbuf,0,temp);
291 break;
292 case 'K': /* status word? (2 byte) */
293 needed = 2;
294 temp = va_arg(args,int);
295 if (p->buflen >= needed) {
296 SSVAL(p->structbuf,0,temp);
298 break;
299 case 'N': /* count of substructures (word) at end */
300 needed = 2;
301 p->subcount = va_arg(args,int);
302 if (p->buflen >= needed) {
303 SSVAL(p->structbuf,0,p->subcount);
305 break;
306 case 'D': /* double word (4 byte) */
307 needed = 4;
308 temp = va_arg(args,int);
309 if (p->buflen >= needed) {
310 SIVAL(p->structbuf,0,temp);
312 break;
313 case 'B': /* byte (with optional counter) */
314 needed = get_counter(&p->curpos);
316 char *s = va_arg(args,char*);
317 if (p->buflen >= needed) {
318 StrnCpy(p->structbuf,s?s:"",needed-1);
321 break;
322 case 'z': /* offset to zero terminated string (4 byte) */
323 str = va_arg(args,char*);
324 stringneeded = (str ? strlen(str)+1 : 0);
325 is_string = 1;
326 break;
327 case 'l': /* offset to user data (4 byte) */
328 str = va_arg(args,char*);
329 stringneeded = va_arg(args,int);
330 is_string = 0;
331 break;
332 case 'b': /* offset to data (with counter) (4 byte) */
333 str = va_arg(args,char*);
334 stringneeded = get_counter(&p->curpos);
335 is_string = 0;
336 break;
339 va_end(args);
340 if (stringneeded >= 0) {
341 needed = 4;
342 if (p->buflen >= needed) {
343 stringused = stringneeded;
344 if (stringused > p->stringlen) {
345 stringused = (is_string ? p->stringlen : 0);
346 if (p->errcode == NERR_Success) {
347 p->errcode = ERRmoredata;
350 if (!stringused) {
351 SIVAL(p->structbuf,0,0);
352 } else {
353 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
354 memcpy(p->stringbuf,str?str:"",stringused);
355 if (is_string) {
356 p->stringbuf[stringused-1] = '\0';
358 p->stringbuf += stringused;
359 p->stringlen -= stringused;
360 p->usedlen += stringused;
363 p->neededlen += stringneeded;
366 p->neededlen += needed;
367 if (p->buflen >= needed) {
368 p->structbuf += needed;
369 p->buflen -= needed;
370 p->usedlen += needed;
371 } else {
372 if (p->errcode == NERR_Success) {
373 p->errcode = ERRmoredata;
376 return 1;
379 #if CHECK_TYPES
380 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
381 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
382 #else
383 #define PACK(desc,t,v) package(desc,v)
384 #define PACKl(desc,t,v,l) package(desc,v,l)
385 #endif
387 static void PACKI(struct pack_desc* desc, const char *t,int v)
389 PACK(desc,t,v);
392 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
394 PACK(desc,t,v);
397 /****************************************************************************
398 Get a print queue.
399 ****************************************************************************/
401 static void PackDriverData(struct pack_desc* desc)
403 char drivdata[4+4+32];
404 SIVAL(drivdata,0,sizeof drivdata); /* cb */
405 SIVAL(drivdata,4,1000); /* lVersion */
406 memset(drivdata+8,0,32); /* szDeviceName */
407 push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
408 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
411 static int check_printq_info(struct pack_desc* desc,
412 unsigned int uLevel, char *id1, char *id2)
414 desc->subformat = NULL;
415 switch( uLevel ) {
416 case 0:
417 desc->format = "B13";
418 break;
419 case 1:
420 desc->format = "B13BWWWzzzzzWW";
421 break;
422 case 2:
423 desc->format = "B13BWWWzzzzzWN";
424 desc->subformat = "WB21BB16B10zWWzDDz";
425 break;
426 case 3:
427 desc->format = "zWWWWzzzzWWzzl";
428 break;
429 case 4:
430 desc->format = "zWWWWzzzzWNzzl";
431 desc->subformat = "WWzWWDDzz";
432 break;
433 case 5:
434 desc->format = "z";
435 break;
436 case 51:
437 desc->format = "K";
438 break;
439 case 52:
440 desc->format = "WzzzzzzzzN";
441 desc->subformat = "z";
442 break;
443 default:
444 DEBUG(0,("check_printq_info: invalid level %d\n",
445 uLevel ));
446 return False;
448 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
449 DEBUG(0,("check_printq_info: invalid format %s\n",
450 id1 ? id1 : "<NULL>" ));
451 return False;
453 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
454 DEBUG(0,("check_printq_info: invalid subformat %s\n",
455 id2 ? id2 : "<NULL>" ));
456 return False;
458 return True;
462 #define RAP_JOB_STATUS_QUEUED 0
463 #define RAP_JOB_STATUS_PAUSED 1
464 #define RAP_JOB_STATUS_SPOOLING 2
465 #define RAP_JOB_STATUS_PRINTING 3
466 #define RAP_JOB_STATUS_PRINTED 4
468 #define RAP_QUEUE_STATUS_PAUSED 1
469 #define RAP_QUEUE_STATUS_ERROR 2
471 /* turn a print job status into a on the wire status
473 static int printj_status(int v)
475 switch (v) {
476 case LPQ_QUEUED:
477 return RAP_JOB_STATUS_QUEUED;
478 case LPQ_PAUSED:
479 return RAP_JOB_STATUS_PAUSED;
480 case LPQ_SPOOLING:
481 return RAP_JOB_STATUS_SPOOLING;
482 case LPQ_PRINTING:
483 return RAP_JOB_STATUS_PRINTING;
485 return 0;
488 /* turn a print queue status into a on the wire status
490 static int printq_status(int v)
492 switch (v) {
493 case LPQ_QUEUED:
494 return 0;
495 case LPQ_PAUSED:
496 return RAP_QUEUE_STATUS_PAUSED;
498 return RAP_QUEUE_STATUS_ERROR;
501 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
502 struct pack_desc *desc,
503 print_queue_struct *queue, int n)
505 time_t t = queue->time;
507 /* the client expects localtime */
508 t -= get_time_zone(t);
510 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
511 if (uLevel == 1) {
512 PACKS(desc,"B21",queue->fs_user); /* szUserName */
513 PACKS(desc,"B",""); /* pad */
514 PACKS(desc,"B16",""); /* szNotifyName */
515 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
516 PACKS(desc,"z",""); /* pszParms */
517 PACKI(desc,"W",n+1); /* uPosition */
518 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
519 PACKS(desc,"z",""); /* pszStatus */
520 PACKI(desc,"D",t); /* ulSubmitted */
521 PACKI(desc,"D",queue->size); /* ulSize */
522 PACKS(desc,"z",queue->fs_file); /* pszComment */
524 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
525 PACKI(desc,"W",queue->priority); /* uPriority */
526 PACKS(desc,"z",queue->fs_user); /* pszUserName */
527 PACKI(desc,"W",n+1); /* uPosition */
528 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
529 PACKI(desc,"D",t); /* ulSubmitted */
530 PACKI(desc,"D",queue->size); /* ulSize */
531 PACKS(desc,"z","Samba"); /* pszComment */
532 PACKS(desc,"z",queue->fs_file); /* pszDocument */
533 if (uLevel == 3) {
534 PACKS(desc,"z",""); /* pszNotifyName */
535 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
536 PACKS(desc,"z",""); /* pszParms */
537 PACKS(desc,"z",""); /* pszStatus */
538 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
539 PACKS(desc,"z","lpd"); /* pszQProcName */
540 PACKS(desc,"z",""); /* pszQProcParms */
541 PACKS(desc,"z","NULL"); /* pszDriverName */
542 PackDriverData(desc); /* pDriverData */
543 PACKS(desc,"z",""); /* pszPrinterName */
544 } else if (uLevel == 4) { /* OS2 */
545 PACKS(desc,"z",""); /* pszSpoolFileName */
546 PACKS(desc,"z",""); /* pszPortName */
547 PACKS(desc,"z",""); /* pszStatus */
548 PACKI(desc,"D",0); /* ulPagesSpooled */
549 PACKI(desc,"D",0); /* ulPagesSent */
550 PACKI(desc,"D",0); /* ulPagesPrinted */
551 PACKI(desc,"D",0); /* ulTimePrinted */
552 PACKI(desc,"D",0); /* ulExtendJobStatus */
553 PACKI(desc,"D",0); /* ulStartPage */
554 PACKI(desc,"D",0); /* ulEndPage */
559 /********************************************************************
560 Return a driver name given an snum.
561 Returns True if from tdb, False otherwise.
562 ********************************************************************/
564 static BOOL get_driver_name(int snum, pstring drivername)
566 NT_PRINTER_INFO_LEVEL *info = NULL;
567 BOOL in_tdb = False;
569 get_a_printer (NULL, &info, 2, lp_servicename(snum));
570 if (info != NULL) {
571 pstrcpy( drivername, info->info_2->drivername);
572 in_tdb = True;
573 free_a_printer(&info, 2);
576 return in_tdb;
579 /********************************************************************
580 Respond to the DosPrintQInfo command with a level of 52
581 This is used to get printer driver information for Win9x clients
582 ********************************************************************/
583 static void fill_printq_info_52(connection_struct *conn, int snum,
584 struct pack_desc* desc, int count )
586 int i;
587 fstring location;
588 NT_PRINTER_DRIVER_INFO_LEVEL driver;
589 NT_PRINTER_INFO_LEVEL *printer = NULL;
591 ZERO_STRUCT(driver);
593 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
594 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
595 lp_servicename(snum)));
596 goto err;
599 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
600 "Windows 4.0", 0)) )
602 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
603 printer->info_2->drivername));
604 goto err;
607 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
608 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
609 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
611 PACKI(desc, "W", 0x0400); /* don't know */
612 PACKS(desc, "z", driver.info_3->name); /* long printer name */
613 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
614 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
615 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
617 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
618 standard_sub_basic( "", "", location, sizeof(location)-1 );
619 PACKS(desc,"z", location); /* share to retrieve files */
621 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
622 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
623 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
625 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
626 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
627 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
628 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
629 DEBUG(3,("Driver Location: %s:\n",location));
630 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
631 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
632 PACKI(desc,"N",count); /* number of files to copy */
634 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
636 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
637 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
638 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
641 /* sanity check */
642 if ( i != count )
643 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
644 count, i));
646 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
648 desc->errcode=NERR_Success;
649 goto done;
651 err:
652 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
653 desc->errcode=NERR_notsupported;
655 done:
656 if ( printer )
657 free_a_printer( &printer, 2 );
659 if ( driver.info_3 )
660 free_a_printer_driver( driver, 3 );
664 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
665 struct pack_desc* desc,
666 int count, print_queue_struct* queue,
667 print_status_struct* status)
669 switch (uLevel) {
670 case 1:
671 case 2:
672 PACKS(desc,"B13",SERVICE(snum));
673 break;
674 case 3:
675 case 4:
676 case 5:
677 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
678 break;
679 case 51:
680 PACKI(desc,"K",printq_status(status->status));
681 break;
684 if (uLevel == 1 || uLevel == 2) {
685 PACKS(desc,"B",""); /* alignment */
686 PACKI(desc,"W",5); /* priority */
687 PACKI(desc,"W",0); /* start time */
688 PACKI(desc,"W",0); /* until time */
689 PACKS(desc,"z",""); /* pSepFile */
690 PACKS(desc,"z","lpd"); /* pPrProc */
691 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
692 PACKS(desc,"z",""); /* pParms */
693 if (snum < 0) {
694 PACKS(desc,"z","UNKNOWN PRINTER");
695 PACKI(desc,"W",LPSTAT_ERROR);
697 else if (!status || !status->message[0]) {
698 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
699 PACKI(desc,"W",LPSTAT_OK); /* status */
700 } else {
701 PACKS(desc,"z",status->message);
702 PACKI(desc,"W",printq_status(status->status)); /* status */
704 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
707 if (uLevel == 3 || uLevel == 4) {
708 pstring drivername;
710 PACKI(desc,"W",5); /* uPriority */
711 PACKI(desc,"W",0); /* uStarttime */
712 PACKI(desc,"W",0); /* uUntiltime */
713 PACKI(desc,"W",5); /* pad1 */
714 PACKS(desc,"z",""); /* pszSepFile */
715 PACKS(desc,"z","WinPrint"); /* pszPrProc */
716 PACKS(desc,"z",NULL); /* pszParms */
717 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
718 /* "don't ask" that it's done this way to fix corrupted
719 Win9X/ME printer comments. */
720 if (!status) {
721 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
722 } else {
723 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
725 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
726 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
727 get_driver_name(snum,drivername);
728 PACKS(desc,"z",drivername); /* pszDriverName */
729 PackDriverData(desc); /* pDriverData */
732 if (uLevel == 2 || uLevel == 4) {
733 int i;
734 for (i=0;i<count;i++)
735 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
738 if (uLevel==52)
739 fill_printq_info_52( conn, snum, desc, count );
742 /* This function returns the number of files for a given driver */
743 static int get_printerdrivernumber(int snum)
745 int result = 0;
746 NT_PRINTER_DRIVER_INFO_LEVEL driver;
747 NT_PRINTER_INFO_LEVEL *printer = NULL;
749 ZERO_STRUCT(driver);
751 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
752 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
753 lp_servicename(snum)));
754 goto done;
757 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
758 "Windows 4.0", 0)) )
760 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
761 printer->info_2->drivername));
762 goto done;
765 /* count the number of files */
766 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
767 result++;
769 done:
770 if ( printer )
771 free_a_printer( &printer, 2 );
773 if ( driver.info_3 )
774 free_a_printer_driver( driver, 3 );
776 return result;
779 static BOOL api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
780 char *param, int tpscnt,
781 char *data, int tdscnt,
782 int mdrcnt,int mprcnt,
783 char **rdata,char **rparam,
784 int *rdata_len,int *rparam_len)
786 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
787 char *str2 = skip_string(param,tpscnt,str1);
788 char *p = skip_string(param,tpscnt,str2);
789 char *QueueName = p;
790 unsigned int uLevel;
791 int count=0;
792 int snum;
793 char *str3;
794 struct pack_desc desc;
795 print_queue_struct *queue=NULL;
796 print_status_struct status;
797 char* tmpdata=NULL;
799 if (!str1 || !str2 || !p) {
800 return False;
802 memset((char *)&status,'\0',sizeof(status));
803 memset((char *)&desc,'\0',sizeof(desc));
805 p = skip_string(param,tpscnt,p);
806 if (!p) {
807 return False;
809 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
810 str3 = get_safe_str_ptr(param,tpscnt,p,4);
811 /* str3 may be null here and is checked in check_printq_info(). */
813 /* remove any trailing username */
814 if ((p = strchr_m(QueueName,'%')))
815 *p = 0;
817 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
819 /* check it's a supported varient */
820 if (!prefix_ok(str1,"zWrLh"))
821 return False;
822 if (!check_printq_info(&desc,uLevel,str2,str3)) {
824 * Patch from Scott Moomaw <scott@bridgewater.edu>
825 * to return the 'invalid info level' error if an
826 * unknown level was requested.
828 *rdata_len = 0;
829 *rparam_len = 6;
830 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
831 if (!*rparam) {
832 return False;
834 SSVALS(*rparam,0,ERRunknownlevel);
835 SSVAL(*rparam,2,0);
836 SSVAL(*rparam,4,0);
837 return(True);
840 snum = find_service(QueueName);
841 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
842 return False;
844 if (uLevel==52) {
845 count = get_printerdrivernumber(snum);
846 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
847 } else {
848 count = print_queue_status(snum, &queue,&status);
851 if (mdrcnt > 0) {
852 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
853 if (!*rdata) {
854 return False;
856 desc.base = *rdata;
857 desc.buflen = mdrcnt;
858 } else {
860 * Don't return data but need to get correct length
861 * init_package will return wrong size if buflen=0
863 desc.buflen = getlen(desc.format);
864 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
867 if (init_package(&desc,1,count)) {
868 desc.subcount = count;
869 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
872 *rdata_len = desc.usedlen;
875 * We must set the return code to ERRbuftoosmall
876 * in order to support lanman style printing with Win NT/2k
877 * clients --jerry
879 if (!mdrcnt && lp_disable_spoolss())
880 desc.errcode = ERRbuftoosmall;
882 *rdata_len = desc.usedlen;
883 *rparam_len = 6;
884 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
885 if (!*rparam) {
886 return False;
888 SSVALS(*rparam,0,desc.errcode);
889 SSVAL(*rparam,2,0);
890 SSVAL(*rparam,4,desc.neededlen);
892 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
894 SAFE_FREE(queue);
895 SAFE_FREE(tmpdata);
897 return(True);
900 /****************************************************************************
901 View list of all print jobs on all queues.
902 ****************************************************************************/
904 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
905 char *param, int tpscnt,
906 char *data, int tdscnt,
907 int mdrcnt, int mprcnt,
908 char **rdata, char** rparam,
909 int *rdata_len, int *rparam_len)
911 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
912 char *output_format1 = skip_string(param,tpscnt,param_format);
913 char *p = skip_string(param,tpscnt,output_format1);
914 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
915 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
916 int services = lp_numservices();
917 int i, n;
918 struct pack_desc desc;
919 print_queue_struct **queue = NULL;
920 print_status_struct *status = NULL;
921 int *subcntarr = NULL;
922 int queuecnt = 0, subcnt = 0, succnt = 0;
924 if (!param_format || !output_format1 || !p) {
925 return False;
928 memset((char *)&desc,'\0',sizeof(desc));
930 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
932 if (!prefix_ok(param_format,"WrLeh")) {
933 return False;
935 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
937 * Patch from Scott Moomaw <scott@bridgewater.edu>
938 * to return the 'invalid info level' error if an
939 * unknown level was requested.
941 *rdata_len = 0;
942 *rparam_len = 6;
943 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
944 if (!*rparam) {
945 return False;
947 SSVALS(*rparam,0,ERRunknownlevel);
948 SSVAL(*rparam,2,0);
949 SSVAL(*rparam,4,0);
950 return(True);
953 for (i = 0; i < services; i++) {
954 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
955 queuecnt++;
959 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
960 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
961 goto err;
963 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
964 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
965 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
966 goto err;
968 memset(status,0,queuecnt*sizeof(print_status_struct));
969 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
970 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
971 goto err;
974 subcnt = 0;
975 n = 0;
976 for (i = 0; i < services; i++) {
977 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
978 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
979 subcnt += subcntarr[n];
980 n++;
984 if (mdrcnt > 0) {
985 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
986 if (!*rdata) {
987 goto err;
990 desc.base = *rdata;
991 desc.buflen = mdrcnt;
993 if (init_package(&desc,queuecnt,subcnt)) {
994 n = 0;
995 succnt = 0;
996 for (i = 0; i < services; i++) {
997 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
998 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
999 n++;
1000 if (desc.errcode == NERR_Success) {
1001 succnt = n;
1007 SAFE_FREE(subcntarr);
1009 *rdata_len = desc.usedlen;
1010 *rparam_len = 8;
1011 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1012 if (!*rparam) {
1013 goto err;
1015 SSVALS(*rparam,0,desc.errcode);
1016 SSVAL(*rparam,2,0);
1017 SSVAL(*rparam,4,succnt);
1018 SSVAL(*rparam,6,queuecnt);
1020 for (i = 0; i < queuecnt; i++) {
1021 if (queue) {
1022 SAFE_FREE(queue[i]);
1026 SAFE_FREE(queue);
1027 SAFE_FREE(status);
1029 return True;
1031 err:
1033 SAFE_FREE(subcntarr);
1034 for (i = 0; i < queuecnt; i++) {
1035 if (queue) {
1036 SAFE_FREE(queue[i]);
1039 SAFE_FREE(queue);
1040 SAFE_FREE(status);
1042 return False;
1045 /****************************************************************************
1046 Get info level for a server list query.
1047 ****************************************************************************/
1049 static BOOL check_server_info(int uLevel, char* id)
1051 switch( uLevel ) {
1052 case 0:
1053 if (strcmp(id,"B16") != 0) {
1054 return False;
1056 break;
1057 case 1:
1058 if (strcmp(id,"B16BBDz") != 0) {
1059 return False;
1061 break;
1062 default:
1063 return False;
1065 return True;
1068 struct srv_info_struct {
1069 fstring name;
1070 uint32 type;
1071 fstring comment;
1072 fstring domain;
1073 BOOL server_added;
1076 /*******************************************************************
1077 Get server info lists from the files saved by nmbd. Return the
1078 number of entries.
1079 ******************************************************************/
1081 static int get_server_info(uint32 servertype,
1082 struct srv_info_struct **servers,
1083 const char *domain)
1085 int count=0;
1086 int alloced=0;
1087 char **lines;
1088 BOOL local_list_only;
1089 int i;
1091 lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1092 if (!lines) {
1093 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1094 return 0;
1097 /* request for everything is code for request all servers */
1098 if (servertype == SV_TYPE_ALL) {
1099 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1102 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1104 DEBUG(4,("Servertype search: %8x\n",servertype));
1106 for (i=0;lines[i];i++) {
1107 fstring stype;
1108 struct srv_info_struct *s;
1109 const char *ptr = lines[i];
1110 BOOL ok = True;
1112 if (!*ptr) {
1113 continue;
1116 if (count == alloced) {
1117 alloced += 10;
1118 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1119 if (!*servers) {
1120 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1121 file_lines_free(lines);
1122 return 0;
1124 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1126 s = &(*servers)[count];
1128 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1129 continue;
1131 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1132 continue;
1134 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1135 continue;
1137 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1138 /* this allows us to cope with an old nmbd */
1139 fstrcpy(s->domain,lp_workgroup());
1142 if (sscanf(stype,"%X",&s->type) != 1) {
1143 DEBUG(4,("r:host file "));
1144 ok = False;
1147 /* Filter the servers/domains we return based on what was asked for. */
1149 /* Check to see if we are being asked for a local list only. */
1150 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1151 DEBUG(4,("r: local list only"));
1152 ok = False;
1155 /* doesn't match up: don't want it */
1156 if (!(servertype & s->type)) {
1157 DEBUG(4,("r:serv type "));
1158 ok = False;
1161 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1162 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1163 DEBUG(4,("s: dom mismatch "));
1164 ok = False;
1167 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1168 ok = False;
1171 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1172 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1174 if (ok) {
1175 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1176 s->name, s->type, s->comment, s->domain));
1177 s->server_added = True;
1178 count++;
1179 } else {
1180 DEBUG(4,("%20s %8x %25s %15s\n",
1181 s->name, s->type, s->comment, s->domain));
1185 file_lines_free(lines);
1186 return count;
1189 /*******************************************************************
1190 Fill in a server info structure.
1191 ******************************************************************/
1193 static int fill_srv_info(struct srv_info_struct *service,
1194 int uLevel, char **buf, int *buflen,
1195 char **stringbuf, int *stringspace, char *baseaddr)
1197 int struct_len;
1198 char* p;
1199 char* p2;
1200 int l2;
1201 int len;
1203 switch (uLevel) {
1204 case 0:
1205 struct_len = 16;
1206 break;
1207 case 1:
1208 struct_len = 26;
1209 break;
1210 default:
1211 return -1;
1214 if (!buf) {
1215 len = 0;
1216 switch (uLevel) {
1217 case 1:
1218 len = strlen(service->comment)+1;
1219 break;
1222 *buflen = struct_len;
1223 *stringspace = len;
1224 return struct_len + len;
1227 len = struct_len;
1228 p = *buf;
1229 if (*buflen < struct_len) {
1230 return -1;
1232 if (stringbuf) {
1233 p2 = *stringbuf;
1234 l2 = *stringspace;
1235 } else {
1236 p2 = p + struct_len;
1237 l2 = *buflen - struct_len;
1239 if (!baseaddr) {
1240 baseaddr = p;
1243 switch (uLevel) {
1244 case 0:
1245 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1246 break;
1248 case 1:
1249 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1250 SIVAL(p,18,service->type);
1251 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1252 len += CopyAndAdvance(&p2,service->comment,&l2);
1253 break;
1256 if (stringbuf) {
1257 *buf = p + struct_len;
1258 *buflen -= struct_len;
1259 *stringbuf = p2;
1260 *stringspace = l2;
1261 } else {
1262 *buf = p2;
1263 *buflen -= len;
1265 return len;
1269 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1271 return(strcmp(s1->name,s2->name));
1274 /****************************************************************************
1275 View list of servers available (or possibly domains). The info is
1276 extracted from lists saved by nmbd on the local host.
1277 ****************************************************************************/
1279 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1280 char *param, int tpscnt,
1281 char *data, int tdscnt,
1282 int mdrcnt, int mprcnt, char **rdata,
1283 char **rparam, int *rdata_len, int *rparam_len)
1285 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1286 char *str2 = skip_string(param,tpscnt,str1);
1287 char *p = skip_string(param,tpscnt,str2);
1288 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1289 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1290 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1291 char *p2;
1292 int data_len, fixed_len, string_len;
1293 int f_len = 0, s_len = 0;
1294 struct srv_info_struct *servers=NULL;
1295 int counted=0,total=0;
1296 int i,missed;
1297 fstring domain;
1298 BOOL domain_request;
1299 BOOL local_request;
1301 if (!str1 || !str2 || !p) {
1302 return False;
1305 /* If someone sets all the bits they don't really mean to set
1306 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1307 known servers. */
1309 if (servertype == SV_TYPE_ALL) {
1310 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1313 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1314 any other bit (they may just set this bit on it's own) they
1315 want all the locally seen servers. However this bit can be
1316 set on its own so set the requested servers to be
1317 ALL - DOMAIN_ENUM. */
1319 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1320 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1323 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1324 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1326 p += 8;
1328 if (!prefix_ok(str1,"WrLehD")) {
1329 return False;
1331 if (!check_server_info(uLevel,str2)) {
1332 return False;
1335 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1336 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1337 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1339 if (strcmp(str1, "WrLehDz") == 0) {
1340 if (skip_string(param,tpscnt,p) == NULL) {
1341 return False;
1343 pull_ascii_fstring(domain, p);
1344 } else {
1345 fstrcpy(domain, lp_workgroup());
1348 if (lp_browse_list()) {
1349 total = get_server_info(servertype,&servers,domain);
1352 data_len = fixed_len = string_len = 0;
1353 missed = 0;
1355 if (total > 0) {
1356 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1360 char *lastname=NULL;
1362 for (i=0;i<total;i++) {
1363 struct srv_info_struct *s = &servers[i];
1365 if (lastname && strequal(lastname,s->name)) {
1366 continue;
1368 lastname = s->name;
1369 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1370 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1371 s->name, s->type, s->comment, s->domain));
1373 if (data_len <= buf_len) {
1374 counted++;
1375 fixed_len += f_len;
1376 string_len += s_len;
1377 } else {
1378 missed++;
1383 *rdata_len = fixed_len + string_len;
1384 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1385 if (!*rdata) {
1386 return False;
1388 memset(*rdata,'\0',*rdata_len);
1390 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1391 p = *rdata;
1392 f_len = fixed_len;
1393 s_len = string_len;
1396 char *lastname=NULL;
1397 int count2 = counted;
1399 for (i = 0; i < total && count2;i++) {
1400 struct srv_info_struct *s = &servers[i];
1402 if (lastname && strequal(lastname,s->name)) {
1403 continue;
1405 lastname = s->name;
1406 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1407 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1408 s->name, s->type, s->comment, s->domain));
1409 count2--;
1413 *rparam_len = 8;
1414 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1415 if (!*rparam) {
1416 return False;
1418 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1419 SSVAL(*rparam,2,0);
1420 SSVAL(*rparam,4,counted);
1421 SSVAL(*rparam,6,counted+missed);
1423 SAFE_FREE(servers);
1425 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1426 domain,uLevel,counted,counted+missed));
1428 return True;
1431 /****************************************************************************
1432 command 0x34 - suspected of being a "Lookup Names" stub api
1433 ****************************************************************************/
1435 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1436 char *param, int tpscnt,
1437 char *data, int tdscnt,
1438 int mdrcnt, int mprcnt, char **rdata,
1439 char **rparam, int *rdata_len, int *rparam_len)
1441 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1442 char *str2 = skip_string(param,tpscnt,str1);
1443 char *p = skip_string(param,tpscnt,str2);
1444 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1445 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1446 int counted=0;
1447 int missed=0;
1449 if (!str1 || !str2 || !p) {
1450 return False;
1453 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1454 str1, str2, p, uLevel, buf_len));
1456 if (!prefix_ok(str1,"zWrLeh")) {
1457 return False;
1460 *rdata_len = 0;
1462 *rparam_len = 8;
1463 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1464 if (!*rparam) {
1465 return False;
1468 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1469 SSVAL(*rparam,2,0);
1470 SSVAL(*rparam,4,counted);
1471 SSVAL(*rparam,6,counted+missed);
1473 return True;
1476 /****************************************************************************
1477 get info about a share
1478 ****************************************************************************/
1480 static BOOL check_share_info(int uLevel, char* id)
1482 switch( uLevel ) {
1483 case 0:
1484 if (strcmp(id,"B13") != 0) {
1485 return False;
1487 break;
1488 case 1:
1489 if (strcmp(id,"B13BWz") != 0) {
1490 return False;
1492 break;
1493 case 2:
1494 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1495 return False;
1497 break;
1498 case 91:
1499 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1500 return False;
1502 break;
1503 default:
1504 return False;
1506 return True;
1509 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1510 char** buf, int* buflen,
1511 char** stringbuf, int* stringspace, char* baseaddr)
1513 int struct_len;
1514 char* p;
1515 char* p2;
1516 int l2;
1517 int len;
1519 switch( uLevel ) {
1520 case 0:
1521 struct_len = 13;
1522 break;
1523 case 1:
1524 struct_len = 20;
1525 break;
1526 case 2:
1527 struct_len = 40;
1528 break;
1529 case 91:
1530 struct_len = 68;
1531 break;
1532 default:
1533 return -1;
1537 if (!buf) {
1538 len = 0;
1540 if (uLevel > 0) {
1541 len += StrlenExpanded(conn,snum,lp_comment(snum));
1543 if (uLevel > 1) {
1544 len += strlen(lp_pathname(snum)) + 1;
1546 if (buflen) {
1547 *buflen = struct_len;
1549 if (stringspace) {
1550 *stringspace = len;
1552 return struct_len + len;
1555 len = struct_len;
1556 p = *buf;
1557 if ((*buflen) < struct_len) {
1558 return -1;
1561 if (stringbuf) {
1562 p2 = *stringbuf;
1563 l2 = *stringspace;
1564 } else {
1565 p2 = p + struct_len;
1566 l2 = (*buflen) - struct_len;
1569 if (!baseaddr) {
1570 baseaddr = p;
1573 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1575 if (uLevel > 0) {
1576 int type;
1578 SCVAL(p,13,0);
1579 type = STYPE_DISKTREE;
1580 if (lp_print_ok(snum)) {
1581 type = STYPE_PRINTQ;
1583 if (strequal("IPC",lp_fstype(snum))) {
1584 type = STYPE_IPC;
1586 SSVAL(p,14,type); /* device type */
1587 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1588 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1591 if (uLevel > 1) {
1592 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1593 SSVALS(p,22,-1); /* max uses */
1594 SSVAL(p,24,1); /* current uses */
1595 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1596 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1597 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1600 if (uLevel > 2) {
1601 memset(p+40,0,SHPWLEN+2);
1602 SSVAL(p,50,0);
1603 SIVAL(p,52,0);
1604 SSVAL(p,56,0);
1605 SSVAL(p,58,0);
1606 SIVAL(p,60,0);
1607 SSVAL(p,64,0);
1608 SSVAL(p,66,0);
1611 if (stringbuf) {
1612 (*buf) = p + struct_len;
1613 (*buflen) -= struct_len;
1614 (*stringbuf) = p2;
1615 (*stringspace) = l2;
1616 } else {
1617 (*buf) = p2;
1618 (*buflen) -= len;
1621 return len;
1624 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1625 char *param, int tpscnt,
1626 char *data, int tdscnt,
1627 int mdrcnt,int mprcnt,
1628 char **rdata,char **rparam,
1629 int *rdata_len,int *rparam_len)
1631 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1632 char *str2 = skip_string(param,tpscnt,str1);
1633 char *netname = skip_string(param,tpscnt,str2);
1634 char *p = skip_string(param,tpscnt,netname);
1635 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1636 int snum;
1638 if (!str1 || !str2 || !netname || !p) {
1639 return False;
1642 snum = find_service(netname);
1643 if (snum < 0) {
1644 return False;
1647 /* check it's a supported varient */
1648 if (!prefix_ok(str1,"zWrLh")) {
1649 return False;
1651 if (!check_share_info(uLevel,str2)) {
1652 return False;
1655 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
1656 if (!*rdata) {
1657 return False;
1659 p = *rdata;
1660 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1661 if (*rdata_len < 0) {
1662 return False;
1665 *rparam_len = 6;
1666 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1667 if (!*rparam) {
1668 return False;
1670 SSVAL(*rparam,0,NERR_Success);
1671 SSVAL(*rparam,2,0); /* converter word */
1672 SSVAL(*rparam,4,*rdata_len);
1674 return True;
1677 /****************************************************************************
1678 View the list of available shares.
1680 This function is the server side of the NetShareEnum() RAP call.
1681 It fills the return buffer with share names and share comments.
1682 Note that the return buffer normally (in all known cases) allows only
1683 twelve byte strings for share names (plus one for a nul terminator).
1684 Share names longer than 12 bytes must be skipped.
1685 ****************************************************************************/
1687 static BOOL api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1688 char *param, int tpscnt,
1689 char *data, int tdscnt,
1690 int mdrcnt,
1691 int mprcnt,
1692 char **rdata,
1693 char **rparam,
1694 int *rdata_len,
1695 int *rparam_len )
1697 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1698 char *str2 = skip_string(param,tpscnt,str1);
1699 char *p = skip_string(param,tpscnt,str2);
1700 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1701 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1702 char *p2;
1703 int count = 0;
1704 int total=0,counted=0;
1705 BOOL missed = False;
1706 int i;
1707 int data_len, fixed_len, string_len;
1708 int f_len = 0, s_len = 0;
1710 if (!str1 || !str2 || !p) {
1711 return False;
1714 if (!prefix_ok(str1,"WrLeh")) {
1715 return False;
1717 if (!check_share_info(uLevel,str2)) {
1718 return False;
1721 /* Ensure all the usershares are loaded. */
1722 become_root();
1723 count = load_usershare_shares();
1724 unbecome_root();
1726 data_len = fixed_len = string_len = 0;
1727 for (i=0;i<count;i++) {
1728 fstring servicename_dos;
1729 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1730 continue;
1732 push_ascii_fstring(servicename_dos, lp_servicename(i));
1733 /* Maximum name length = 13. */
1734 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1735 total++;
1736 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1737 if (data_len <= buf_len) {
1738 counted++;
1739 fixed_len += f_len;
1740 string_len += s_len;
1741 } else {
1742 missed = True;
1747 *rdata_len = fixed_len + string_len;
1748 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1749 if (!*rdata) {
1750 return False;
1752 memset(*rdata,0,*rdata_len);
1754 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1755 p = *rdata;
1756 f_len = fixed_len;
1757 s_len = string_len;
1759 for( i = 0; i < count; i++ ) {
1760 fstring servicename_dos;
1761 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1762 continue;
1765 push_ascii_fstring(servicename_dos, lp_servicename(i));
1766 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1767 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1768 break;
1773 *rparam_len = 8;
1774 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1775 if (!*rparam) {
1776 return False;
1778 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1779 SSVAL(*rparam,2,0);
1780 SSVAL(*rparam,4,counted);
1781 SSVAL(*rparam,6,total);
1783 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1784 counted,total,uLevel,
1785 buf_len,*rdata_len,mdrcnt));
1787 return True;
1790 /****************************************************************************
1791 Add a share
1792 ****************************************************************************/
1794 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1795 char *param, int tpscnt,
1796 char *data, int tdscnt,
1797 int mdrcnt,int mprcnt,
1798 char **rdata,char **rparam,
1799 int *rdata_len,int *rparam_len)
1801 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1802 char *str2 = skip_string(param,tpscnt,str1);
1803 char *p = skip_string(param,tpscnt,str2);
1804 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1805 fstring sharename;
1806 fstring comment;
1807 pstring pathname;
1808 char *command, *cmdname;
1809 unsigned int offset;
1810 int snum;
1811 int res = ERRunsup;
1813 if (!str1 || !str2 || !p) {
1814 return False;
1817 /* check it's a supported varient */
1818 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1819 return False;
1821 if (!check_share_info(uLevel,str2)) {
1822 return False;
1824 if (uLevel != 2) {
1825 return False;
1828 /* Do we have a string ? */
1829 if (skip_string(data,mdrcnt,data) == NULL) {
1830 return False;
1832 pull_ascii_fstring(sharename,data);
1833 snum = find_service(sharename);
1834 if (snum >= 0) { /* already exists */
1835 res = ERRfilexists;
1836 goto error_exit;
1839 if (mdrcnt < 28) {
1840 return False;
1843 /* only support disk share adds */
1844 if (SVAL(data,14)!=STYPE_DISKTREE) {
1845 return False;
1848 offset = IVAL(data, 16);
1849 if (offset >= mdrcnt) {
1850 res = ERRinvalidparam;
1851 goto error_exit;
1854 /* Do we have a string ? */
1855 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1856 return False;
1858 pull_ascii_fstring(comment, offset? (data+offset) : "");
1860 offset = IVAL(data, 26);
1862 if (offset >= mdrcnt) {
1863 res = ERRinvalidparam;
1864 goto error_exit;
1867 /* Do we have a string ? */
1868 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1869 return False;
1871 pull_ascii_pstring(pathname, offset? (data+offset) : "");
1873 string_replace(sharename, '"', ' ');
1874 string_replace(pathname, '"', ' ');
1875 string_replace(comment, '"', ' ');
1877 cmdname = lp_add_share_cmd();
1879 if (!cmdname || *cmdname == '\0') {
1880 return False;
1883 asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1884 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1886 if (command) {
1887 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1889 if ((res = smbrun(command, NULL)) != 0) {
1890 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1891 SAFE_FREE(command);
1892 res = ERRnoaccess;
1893 goto error_exit;
1894 } else {
1895 SAFE_FREE(command);
1896 message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
1898 } else {
1899 return False;
1902 *rparam_len = 6;
1903 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1904 if (!*rparam) {
1905 return False;
1907 SSVAL(*rparam,0,NERR_Success);
1908 SSVAL(*rparam,2,0); /* converter word */
1909 SSVAL(*rparam,4,*rdata_len);
1910 *rdata_len = 0;
1912 return True;
1914 error_exit:
1916 *rparam_len = 4;
1917 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1918 if (!*rparam) {
1919 return False;
1921 *rdata_len = 0;
1922 SSVAL(*rparam,0,res);
1923 SSVAL(*rparam,2,0);
1924 return True;
1927 /****************************************************************************
1928 view list of groups available
1929 ****************************************************************************/
1931 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
1932 char *param, int tpscnt,
1933 char *data, int tdscnt,
1934 int mdrcnt,int mprcnt,
1935 char **rdata,char **rparam,
1936 int *rdata_len,int *rparam_len)
1938 int i;
1939 int errflags=0;
1940 int resume_context, cli_buf_size;
1941 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1942 char *str2 = skip_string(param,tpscnt,str1);
1943 char *p = skip_string(param,tpscnt,str2);
1945 struct pdb_search *search;
1946 struct samr_displayentry *entries;
1948 int num_entries;
1950 if (!str1 || !str2 || !p) {
1951 return False;
1954 if (strcmp(str1,"WrLeh") != 0) {
1955 return False;
1958 /* parameters
1959 * W-> resume context (number of users to skip)
1960 * r -> return parameter pointer to receive buffer
1961 * L -> length of receive buffer
1962 * e -> return parameter number of entries
1963 * h -> return parameter total number of users
1966 if (strcmp("B21",str2) != 0) {
1967 return False;
1970 /* get list of domain groups SID_DOMAIN_GRP=2 */
1971 become_root();
1972 search = pdb_search_groups();
1973 unbecome_root();
1975 if (search == NULL) {
1976 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1977 return False;
1980 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
1981 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
1982 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1983 "%d\n", resume_context, cli_buf_size));
1985 become_root();
1986 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1987 &entries);
1988 unbecome_root();
1990 *rdata_len = cli_buf_size;
1991 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1992 if (!*rdata) {
1993 return False;
1996 p = *rdata;
1998 for(i=0; i<num_entries; i++) {
1999 fstring name;
2000 fstrcpy(name, entries[i].account_name);
2001 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2002 /* truncate the name at 21 chars. */
2003 memcpy(p, name, 21);
2004 DEBUG(10,("adding entry %d group %s\n", i, p));
2005 p += 21;
2006 p += 5; /* Both NT4 and W2k3SP1 do padding here.
2007 No idea why... */
2008 } else {
2009 /* set overflow error */
2010 DEBUG(3,("overflow on entry %d group %s\n", i, name));
2011 errflags=234;
2012 break;
2016 pdb_search_destroy(search);
2018 *rdata_len = PTR_DIFF(p,*rdata);
2020 *rparam_len = 8;
2021 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2022 if (!*rparam) {
2023 return False;
2025 SSVAL(*rparam, 0, errflags);
2026 SSVAL(*rparam, 2, 0); /* converter word */
2027 SSVAL(*rparam, 4, i); /* is this right?? */
2028 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
2030 return(True);
2033 /*******************************************************************
2034 Get groups that a user is a member of.
2035 ******************************************************************/
2037 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2038 char *param, int tpscnt,
2039 char *data, int tdscnt,
2040 int mdrcnt,int mprcnt,
2041 char **rdata,char **rparam,
2042 int *rdata_len,int *rparam_len)
2044 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2045 char *str2 = skip_string(param,tpscnt,str1);
2046 char *UserName = skip_string(param,tpscnt,str2);
2047 char *p = skip_string(param,tpscnt,UserName);
2048 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2049 const char *level_string;
2050 int count=0;
2051 struct samu *sampw = NULL;
2052 BOOL ret = False;
2053 DOM_SID *sids;
2054 gid_t *gids;
2055 size_t num_groups;
2056 size_t i;
2057 NTSTATUS result;
2058 DOM_SID user_sid;
2059 enum lsa_SidType type;
2060 TALLOC_CTX *mem_ctx;
2062 if (!str1 || !str2 || !UserName || !p) {
2063 return False;
2066 *rparam_len = 8;
2067 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2068 if (!*rparam) {
2069 return False;
2072 /* check it's a supported varient */
2074 if ( strcmp(str1,"zWrLeh") != 0 )
2075 return False;
2077 switch( uLevel ) {
2078 case 0:
2079 level_string = "B21";
2080 break;
2081 default:
2082 return False;
2085 if (strcmp(level_string,str2) != 0)
2086 return False;
2088 *rdata_len = mdrcnt + 1024;
2089 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2090 if (!*rdata) {
2091 return False;
2093 SSVAL(*rparam,0,NERR_Success);
2094 SSVAL(*rparam,2,0); /* converter word */
2096 p = *rdata;
2098 mem_ctx = talloc_new(NULL);
2099 if (mem_ctx == NULL) {
2100 DEBUG(0, ("talloc_new failed\n"));
2101 return False;
2104 if ( !(sampw = samu_new(mem_ctx)) ) {
2105 DEBUG(0, ("samu_new() failed!\n"));
2106 TALLOC_FREE(mem_ctx);
2107 return False;
2110 /* Lookup the user information; This should only be one of
2111 our accounts (not remote domains) */
2113 become_root(); /* ROOT BLOCK */
2115 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2116 NULL, NULL, &user_sid, &type)) {
2117 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2118 goto done;
2121 if (type != SID_NAME_USER) {
2122 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2123 sid_type_lookup(type)));
2124 goto done;
2127 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2128 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2129 sid_string_static(&user_sid), UserName));
2130 goto done;
2133 gids = NULL;
2134 sids = NULL;
2135 num_groups = 0;
2137 result = pdb_enum_group_memberships(mem_ctx, sampw,
2138 &sids, &gids, &num_groups);
2140 if (!NT_STATUS_IS_OK(result)) {
2141 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2142 UserName));
2143 goto done;
2146 for (i=0; i<num_groups; i++) {
2148 const char *grp_name;
2150 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2151 pstrcpy(p, grp_name);
2152 p += 21;
2153 count++;
2157 *rdata_len = PTR_DIFF(p,*rdata);
2159 SSVAL(*rparam,4,count); /* is this right?? */
2160 SSVAL(*rparam,6,count); /* is this right?? */
2162 ret = True;
2164 done:
2165 unbecome_root(); /* END ROOT BLOCK */
2167 TALLOC_FREE(mem_ctx);
2169 return ret;
2172 /*******************************************************************
2173 Get all users.
2174 ******************************************************************/
2176 static BOOL api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2177 char *param, int tpscnt,
2178 char *data, int tdscnt,
2179 int mdrcnt,int mprcnt,
2180 char **rdata,char **rparam,
2181 int *rdata_len,int *rparam_len)
2183 int count_sent=0;
2184 int num_users=0;
2185 int errflags=0;
2186 int i, resume_context, cli_buf_size;
2187 struct pdb_search *search;
2188 struct samr_displayentry *users;
2190 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2191 char *str2 = skip_string(param,tpscnt,str1);
2192 char *p = skip_string(param,tpscnt,str2);
2194 if (!str1 || !str2 || !p) {
2195 return False;
2198 if (strcmp(str1,"WrLeh") != 0)
2199 return False;
2200 /* parameters
2201 * W-> resume context (number of users to skip)
2202 * r -> return parameter pointer to receive buffer
2203 * L -> length of receive buffer
2204 * e -> return parameter number of entries
2205 * h -> return parameter total number of users
2208 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2209 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2210 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2211 resume_context, cli_buf_size));
2213 *rparam_len = 8;
2214 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2215 if (!*rparam) {
2216 return False;
2219 /* check it's a supported varient */
2220 if (strcmp("B21",str2) != 0)
2221 return False;
2223 *rdata_len = cli_buf_size;
2224 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2225 if (!*rdata) {
2226 return False;
2229 p = *rdata;
2231 become_root();
2232 search = pdb_search_users(ACB_NORMAL);
2233 unbecome_root();
2234 if (search == NULL) {
2235 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2236 return False;
2239 become_root();
2240 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2241 &users);
2242 unbecome_root();
2244 errflags=NERR_Success;
2246 for (i=0; i<num_users; i++) {
2247 const char *name = users[i].account_name;
2249 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2250 pstrcpy(p,name);
2251 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2252 "%s\n",count_sent,p));
2253 p += 21;
2254 count_sent++;
2255 } else {
2256 /* set overflow error */
2257 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2258 "username %s\n",count_sent,name));
2259 errflags=234;
2260 break;
2264 pdb_search_destroy(search);
2266 *rdata_len = PTR_DIFF(p,*rdata);
2268 SSVAL(*rparam,0,errflags);
2269 SSVAL(*rparam,2,0); /* converter word */
2270 SSVAL(*rparam,4,count_sent); /* is this right?? */
2271 SSVAL(*rparam,6,num_users); /* is this right?? */
2273 return True;
2276 /****************************************************************************
2277 Get the time of day info.
2278 ****************************************************************************/
2280 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2281 char *param, int tpscnt,
2282 char *data, int tdscnt,
2283 int mdrcnt,int mprcnt,
2284 char **rdata,char **rparam,
2285 int *rdata_len,int *rparam_len)
2287 struct tm *t;
2288 time_t unixdate = time(NULL);
2289 char *p;
2291 *rparam_len = 4;
2292 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2293 if (!*rparam) {
2294 return False;
2297 *rdata_len = 21;
2298 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2299 if (!*rdata) {
2300 return False;
2303 SSVAL(*rparam,0,NERR_Success);
2304 SSVAL(*rparam,2,0); /* converter word */
2306 p = *rdata;
2308 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2309 by NT in a "net time" operation,
2310 it seems to ignore the one below */
2312 /* the client expects to get localtime, not GMT, in this bit
2313 (I think, this needs testing) */
2314 t = localtime(&unixdate);
2315 if (!t) {
2316 return False;
2319 SIVAL(p,4,0); /* msecs ? */
2320 SCVAL(p,8,t->tm_hour);
2321 SCVAL(p,9,t->tm_min);
2322 SCVAL(p,10,t->tm_sec);
2323 SCVAL(p,11,0); /* hundredths of seconds */
2324 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2325 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2326 SCVAL(p,16,t->tm_mday);
2327 SCVAL(p,17,t->tm_mon + 1);
2328 SSVAL(p,18,1900+t->tm_year);
2329 SCVAL(p,20,t->tm_wday);
2331 return True;
2334 /****************************************************************************
2335 Set the user password.
2336 *****************************************************************************/
2338 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid,
2339 char *param, int tpscnt,
2340 char *data, int tdscnt,
2341 int mdrcnt,int mprcnt,
2342 char **rdata,char **rparam,
2343 int *rdata_len,int *rparam_len)
2345 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2346 char *p = NULL;
2347 fstring user;
2348 fstring pass1,pass2;
2350 /* Skip 2 strings. */
2351 p = skip_string(param,tpscnt,np);
2352 p = skip_string(param,tpscnt,p);
2354 if (!np || !p) {
2355 return False;
2358 /* Do we have a string ? */
2359 if (skip_string(param,tpscnt,p) == NULL) {
2360 return False;
2362 pull_ascii_fstring(user,p);
2364 p = skip_string(param,tpscnt,p);
2365 if (!p) {
2366 return False;
2369 memset(pass1,'\0',sizeof(pass1));
2370 memset(pass2,'\0',sizeof(pass2));
2372 * We use 31 here not 32 as we're checking
2373 * the last byte we want to access is safe.
2375 if (!is_offset_safe(param,tpscnt,p,31)) {
2376 return False;
2378 memcpy(pass1,p,16);
2379 memcpy(pass2,p+16,16);
2381 *rparam_len = 4;
2382 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2383 if (!*rparam) {
2384 return False;
2387 *rdata_len = 0;
2389 SSVAL(*rparam,0,NERR_badpass);
2390 SSVAL(*rparam,2,0); /* converter word */
2392 DEBUG(3,("Set password for <%s>\n",user));
2395 * Attempt to verify the old password against smbpasswd entries
2396 * Win98 clients send old and new password in plaintext for this call.
2400 auth_serversupplied_info *server_info = NULL;
2401 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2403 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2405 become_root();
2406 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2407 SSVAL(*rparam,0,NERR_Success);
2409 unbecome_root();
2411 TALLOC_FREE(server_info);
2413 data_blob_clear_free(&password);
2417 * If the plaintext change failed, attempt
2418 * the old encrypted method. NT will generate this
2419 * after trying the samr method. Note that this
2420 * method is done as a last resort as this
2421 * password change method loses the NT password hash
2422 * and cannot change the UNIX password as no plaintext
2423 * is received.
2426 if(SVAL(*rparam,0) != NERR_Success) {
2427 struct samu *hnd = NULL;
2429 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2430 become_root();
2431 if (change_lanman_password(hnd,(uchar *)pass2)) {
2432 SSVAL(*rparam,0,NERR_Success);
2434 unbecome_root();
2435 TALLOC_FREE(hnd);
2439 memset((char *)pass1,'\0',sizeof(fstring));
2440 memset((char *)pass2,'\0',sizeof(fstring));
2442 return(True);
2445 /****************************************************************************
2446 Set the user password (SamOEM version - gets plaintext).
2447 ****************************************************************************/
2449 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2450 char *param, int tpscnt,
2451 char *data, int tdscnt,
2452 int mdrcnt,int mprcnt,
2453 char **rdata,char **rparam,
2454 int *rdata_len,int *rparam_len)
2456 fstring user;
2457 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2458 *rparam_len = 2;
2459 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2460 if (!*rparam) {
2461 return False;
2464 if (!p) {
2465 return False;
2467 *rdata_len = 0;
2469 SSVAL(*rparam,0,NERR_badpass);
2472 * Check the parameter definition is correct.
2475 /* Do we have a string ? */
2476 if (skip_string(param,tpscnt,p) == 0) {
2477 return False;
2479 if(!strequal(p, "zsT")) {
2480 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2481 return False;
2483 p = skip_string(param, tpscnt, p);
2484 if (!p) {
2485 return False;
2488 /* Do we have a string ? */
2489 if (skip_string(param,tpscnt,p) == 0) {
2490 return False;
2492 if(!strequal(p, "B516B16")) {
2493 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2494 return False;
2496 p = skip_string(param,tpscnt,p);
2497 if (!p) {
2498 return False;
2500 /* Do we have a string ? */
2501 if (skip_string(param,tpscnt,p) == 0) {
2502 return False;
2504 p += pull_ascii_fstring(user,p);
2506 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2509 * Pass the user through the NT -> unix user mapping
2510 * function.
2513 (void)map_username(user);
2515 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2516 SSVAL(*rparam,0,NERR_Success);
2519 return(True);
2522 /****************************************************************************
2523 delete a print job
2524 Form: <W> <>
2525 ****************************************************************************/
2527 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2528 char *param, int tpscnt,
2529 char *data, int tdscnt,
2530 int mdrcnt,int mprcnt,
2531 char **rdata,char **rparam,
2532 int *rdata_len,int *rparam_len)
2534 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2535 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2536 char *str2 = skip_string(param,tpscnt,str1);
2537 char *p = skip_string(param,tpscnt,str2);
2538 uint32 jobid;
2539 int snum;
2540 fstring sharename;
2541 int errcode;
2542 WERROR werr = WERR_OK;
2544 if (!str1 || !str2 || !p) {
2545 return False;
2548 * We use 1 here not 2 as we're checking
2549 * the last byte we want to access is safe.
2551 if (!is_offset_safe(param,tpscnt,p,1)) {
2552 return False;
2554 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2555 return False;
2557 /* check it's a supported varient */
2558 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2559 return(False);
2561 *rparam_len = 4;
2562 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2563 if (!*rparam) {
2564 return False;
2566 *rdata_len = 0;
2568 if (!print_job_exists(sharename, jobid)) {
2569 errcode = NERR_JobNotFound;
2570 goto out;
2573 snum = lp_servicenumber( sharename);
2574 if (snum == -1) {
2575 errcode = NERR_DestNotFound;
2576 goto out;
2579 errcode = NERR_notsupported;
2581 switch (function) {
2582 case 81: /* delete */
2583 if (print_job_delete(&current_user, snum, jobid, &werr))
2584 errcode = NERR_Success;
2585 break;
2586 case 82: /* pause */
2587 if (print_job_pause(&current_user, snum, jobid, &werr))
2588 errcode = NERR_Success;
2589 break;
2590 case 83: /* resume */
2591 if (print_job_resume(&current_user, snum, jobid, &werr))
2592 errcode = NERR_Success;
2593 break;
2596 if (!W_ERROR_IS_OK(werr))
2597 errcode = W_ERROR_V(werr);
2599 out:
2600 SSVAL(*rparam,0,errcode);
2601 SSVAL(*rparam,2,0); /* converter word */
2603 return(True);
2606 /****************************************************************************
2607 Purge a print queue - or pause or resume it.
2608 ****************************************************************************/
2610 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2611 char *param, int tpscnt,
2612 char *data, int tdscnt,
2613 int mdrcnt,int mprcnt,
2614 char **rdata,char **rparam,
2615 int *rdata_len,int *rparam_len)
2617 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2618 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2619 char *str2 = skip_string(param,tpscnt,str1);
2620 char *QueueName = skip_string(param,tpscnt,str2);
2621 int errcode = NERR_notsupported;
2622 int snum;
2623 WERROR werr = WERR_OK;
2625 if (!str1 || !str2 || !QueueName) {
2626 return False;
2629 /* check it's a supported varient */
2630 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2631 return(False);
2633 *rparam_len = 4;
2634 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2635 if (!*rparam) {
2636 return False;
2638 *rdata_len = 0;
2640 if (skip_string(param,tpscnt,QueueName) == NULL) {
2641 return False;
2643 snum = print_queue_snum(QueueName);
2645 if (snum == -1) {
2646 errcode = NERR_JobNotFound;
2647 goto out;
2650 switch (function) {
2651 case 74: /* Pause queue */
2652 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2653 break;
2654 case 75: /* Resume queue */
2655 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2656 break;
2657 case 103: /* Purge */
2658 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2659 break;
2662 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2664 out:
2665 SSVAL(*rparam,0,errcode);
2666 SSVAL(*rparam,2,0); /* converter word */
2668 return(True);
2671 /****************************************************************************
2672 set the property of a print job (undocumented?)
2673 ? function = 0xb -> set name of print job
2674 ? function = 0x6 -> move print job up/down
2675 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2676 or <WWsTP> <WB21BB16B10zWWzDDz>
2677 ****************************************************************************/
2679 static int check_printjob_info(struct pack_desc* desc,
2680 int uLevel, char* id)
2682 desc->subformat = NULL;
2683 switch( uLevel ) {
2684 case 0: desc->format = "W"; break;
2685 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2686 case 2: desc->format = "WWzWWDDzz"; break;
2687 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2688 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2689 default:
2690 DEBUG(0,("check_printjob_info: invalid level %d\n",
2691 uLevel ));
2692 return False;
2694 if (id == NULL || strcmp(desc->format,id) != 0) {
2695 DEBUG(0,("check_printjob_info: invalid format %s\n",
2696 id ? id : "<NULL>" ));
2697 return False;
2699 return True;
2702 static BOOL api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2703 char *param, int tpscnt,
2704 char *data, int tdscnt,
2705 int mdrcnt,int mprcnt,
2706 char **rdata,char **rparam,
2707 int *rdata_len,int *rparam_len)
2709 struct pack_desc desc;
2710 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2711 char *str2 = skip_string(param,tpscnt,str1);
2712 char *p = skip_string(param,tpscnt,str2);
2713 uint32 jobid;
2714 fstring sharename;
2715 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2716 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2717 int place, errcode;
2719 if (!str1 || !str2 || !p) {
2720 return False;
2723 * We use 1 here not 2 as we're checking
2724 * the last byte we want to access is safe.
2726 if (!is_offset_safe(param,tpscnt,p,1)) {
2727 return False;
2729 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2730 return False;
2731 *rparam_len = 4;
2732 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2733 if (!*rparam) {
2734 return False;
2737 if (!share_defined(sharename)) {
2738 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2739 sharename));
2740 return False;
2743 *rdata_len = 0;
2745 /* check it's a supported varient */
2746 if ((strcmp(str1,"WWsTP")) ||
2747 (!check_printjob_info(&desc,uLevel,str2)))
2748 return(False);
2750 if (!print_job_exists(sharename, jobid)) {
2751 errcode=NERR_JobNotFound;
2752 goto out;
2755 errcode = NERR_notsupported;
2757 switch (function) {
2758 case 0x6:
2759 /* change job place in the queue,
2760 data gives the new place */
2761 place = SVAL(data,0);
2762 if (print_job_set_place(sharename, jobid, place)) {
2763 errcode=NERR_Success;
2765 break;
2767 case 0xb:
2768 /* change print job name, data gives the name */
2769 if (print_job_set_name(sharename, jobid, data)) {
2770 errcode=NERR_Success;
2772 break;
2774 default:
2775 return False;
2778 out:
2779 SSVALS(*rparam,0,errcode);
2780 SSVAL(*rparam,2,0); /* converter word */
2782 return(True);
2786 /****************************************************************************
2787 Get info about the server.
2788 ****************************************************************************/
2790 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2791 char *param, int tpscnt,
2792 char *data, int tdscnt,
2793 int mdrcnt,int mprcnt,
2794 char **rdata,char **rparam,
2795 int *rdata_len,int *rparam_len)
2797 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2798 char *str2 = skip_string(param,tpscnt,str1);
2799 char *p = skip_string(param,tpscnt,str2);
2800 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2801 char *p2;
2802 int struct_len;
2804 if (!str1 || !str2 || !p) {
2805 return False;
2808 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2810 /* check it's a supported varient */
2811 if (!prefix_ok(str1,"WrLh")) {
2812 return False;
2815 switch( uLevel ) {
2816 case 0:
2817 if (strcmp(str2,"B16") != 0) {
2818 return False;
2820 struct_len = 16;
2821 break;
2822 case 1:
2823 if (strcmp(str2,"B16BBDz") != 0) {
2824 return False;
2826 struct_len = 26;
2827 break;
2828 case 2:
2829 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2830 return False;
2832 struct_len = 134;
2833 break;
2834 case 3:
2835 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2836 return False;
2838 struct_len = 144;
2839 break;
2840 case 20:
2841 if (strcmp(str2,"DN") != 0) {
2842 return False;
2844 struct_len = 6;
2845 break;
2846 case 50:
2847 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2848 return False;
2850 struct_len = 42;
2851 break;
2852 default:
2853 return False;
2856 *rdata_len = mdrcnt;
2857 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2858 if (!*rdata) {
2859 return False;
2862 p = *rdata;
2863 p2 = p + struct_len;
2864 if (uLevel != 20) {
2865 srvstr_push(NULL, p,global_myname(),16,
2866 STR_ASCII|STR_UPPER|STR_TERMINATE);
2868 p += 16;
2869 if (uLevel > 0) {
2870 struct srv_info_struct *servers=NULL;
2871 int i,count;
2872 pstring comment;
2873 uint32 servertype= lp_default_server_announce();
2875 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2877 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2878 for (i=0;i<count;i++) {
2879 if (strequal(servers[i].name,global_myname())) {
2880 servertype = servers[i].type;
2881 push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2886 SAFE_FREE(servers);
2888 SCVAL(p,0,lp_major_announce_version());
2889 SCVAL(p,1,lp_minor_announce_version());
2890 SIVAL(p,2,servertype);
2892 if (mdrcnt == struct_len) {
2893 SIVAL(p,6,0);
2894 } else {
2895 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2896 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2897 conn->connectpath, conn->gid,
2898 get_current_username(),
2899 current_user_info.domain,
2900 comment, sizeof(comment));
2901 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2902 p2 = skip_string(*rdata,*rdata_len,p2);
2903 if (!p2) {
2904 return False;
2909 if (uLevel > 1) {
2910 return False; /* not yet implemented */
2913 *rdata_len = PTR_DIFF(p2,*rdata);
2915 *rparam_len = 6;
2916 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2917 if (!*rparam) {
2918 return False;
2920 SSVAL(*rparam,0,NERR_Success);
2921 SSVAL(*rparam,2,0); /* converter word */
2922 SSVAL(*rparam,4,*rdata_len);
2924 return True;
2927 /****************************************************************************
2928 Get info about the server.
2929 ****************************************************************************/
2931 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
2932 char *param, int tpscnt,
2933 char *data, int tdscnt,
2934 int mdrcnt,int mprcnt,
2935 char **rdata,char **rparam,
2936 int *rdata_len,int *rparam_len)
2938 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2939 char *str2 = skip_string(param,tpscnt,str1);
2940 char *p = skip_string(param,tpscnt,str2);
2941 char *p2;
2942 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
2944 if (!str1 || !str2 || !p) {
2945 return False;
2948 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2950 *rparam_len = 6;
2951 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2952 if (!*rparam) {
2953 return False;
2956 /* check it's a supported varient */
2957 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2958 return False;
2961 *rdata_len = mdrcnt + 1024;
2962 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2963 if (!*rdata) {
2964 return False;
2967 SSVAL(*rparam,0,NERR_Success);
2968 SSVAL(*rparam,2,0); /* converter word */
2970 p = *rdata;
2971 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
2972 if (!p2) {
2973 return False;
2976 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2977 pstrcpy(p2,get_local_machine_name());
2978 strupper_m(p2);
2979 p2 = skip_string(*rdata,*rdata_len,p2);
2980 if (!p2) {
2981 return False;
2983 p += 4;
2985 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2986 pstrcpy(p2,current_user_info.smb_name);
2987 p2 = skip_string(*rdata,*rdata_len,p2);
2988 if (!p2) {
2989 return False;
2991 p += 4;
2993 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2994 pstrcpy(p2,lp_workgroup());
2995 strupper_m(p2);
2996 p2 = skip_string(*rdata,*rdata_len,p2);
2997 if (!p2) {
2998 return False;
3000 p += 4;
3002 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3003 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3004 p += 2;
3006 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3007 pstrcpy(p2,lp_workgroup()); /* don't know. login domain?? */
3008 p2 = skip_string(*rdata,*rdata_len,p2);
3009 if (!p2) {
3010 return False;
3012 p += 4;
3014 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3015 pstrcpy(p2,"");
3016 p2 = skip_string(*rdata,*rdata_len,p2);
3017 if (!p2) {
3018 return False;
3020 p += 4;
3022 *rdata_len = PTR_DIFF(p2,*rdata);
3024 SSVAL(*rparam,4,*rdata_len);
3026 return True;
3029 /****************************************************************************
3030 get info about a user
3032 struct user_info_11 {
3033 char usri11_name[21]; 0-20
3034 char usri11_pad; 21
3035 char *usri11_comment; 22-25
3036 char *usri11_usr_comment; 26-29
3037 unsigned short usri11_priv; 30-31
3038 unsigned long usri11_auth_flags; 32-35
3039 long usri11_password_age; 36-39
3040 char *usri11_homedir; 40-43
3041 char *usri11_parms; 44-47
3042 long usri11_last_logon; 48-51
3043 long usri11_last_logoff; 52-55
3044 unsigned short usri11_bad_pw_count; 56-57
3045 unsigned short usri11_num_logons; 58-59
3046 char *usri11_logon_server; 60-63
3047 unsigned short usri11_country_code; 64-65
3048 char *usri11_workstations; 66-69
3049 unsigned long usri11_max_storage; 70-73
3050 unsigned short usri11_units_per_week; 74-75
3051 unsigned char *usri11_logon_hours; 76-79
3052 unsigned short usri11_code_page; 80-81
3055 where:
3057 usri11_name specifies the user name for which information is retireved
3059 usri11_pad aligns the next data structure element to a word boundary
3061 usri11_comment is a null terminated ASCII comment
3063 usri11_user_comment is a null terminated ASCII comment about the user
3065 usri11_priv specifies the level of the privilege assigned to the user.
3066 The possible values are:
3068 Name Value Description
3069 USER_PRIV_GUEST 0 Guest privilege
3070 USER_PRIV_USER 1 User privilege
3071 USER_PRV_ADMIN 2 Administrator privilege
3073 usri11_auth_flags specifies the account operator privileges. The
3074 possible values are:
3076 Name Value Description
3077 AF_OP_PRINT 0 Print operator
3080 Leach, Naik [Page 28]
3084 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3087 AF_OP_COMM 1 Communications operator
3088 AF_OP_SERVER 2 Server operator
3089 AF_OP_ACCOUNTS 3 Accounts operator
3092 usri11_password_age specifies how many seconds have elapsed since the
3093 password was last changed.
3095 usri11_home_dir points to a null terminated ASCII string that contains
3096 the path name of the user's home directory.
3098 usri11_parms points to a null terminated ASCII string that is set
3099 aside for use by applications.
3101 usri11_last_logon specifies the time when the user last logged on.
3102 This value is stored as the number of seconds elapsed since
3103 00:00:00, January 1, 1970.
3105 usri11_last_logoff specifies the time when the user last logged off.
3106 This value is stored as the number of seconds elapsed since
3107 00:00:00, January 1, 1970. A value of 0 means the last logoff
3108 time is unknown.
3110 usri11_bad_pw_count specifies the number of incorrect passwords
3111 entered since the last successful logon.
3113 usri11_log1_num_logons specifies the number of times this user has
3114 logged on. A value of -1 means the number of logons is unknown.
3116 usri11_logon_server points to a null terminated ASCII string that
3117 contains the name of the server to which logon requests are sent.
3118 A null string indicates logon requests should be sent to the
3119 domain controller.
3121 usri11_country_code specifies the country code for the user's language
3122 of choice.
3124 usri11_workstations points to a null terminated ASCII string that
3125 contains the names of workstations the user may log on from.
3126 There may be up to 8 workstations, with the names separated by
3127 commas. A null strings indicates there are no restrictions.
3129 usri11_max_storage specifies the maximum amount of disk space the user
3130 can occupy. A value of 0xffffffff indicates there are no
3131 restrictions.
3133 usri11_units_per_week specifies the equal number of time units into
3134 which a week is divided. This value must be equal to 168.
3136 usri11_logon_hours points to a 21 byte (168 bits) string that
3137 specifies the time during which the user can log on. Each bit
3138 represents one unique hour in a week. The first bit (bit 0, word
3139 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3143 Leach, Naik [Page 29]
3147 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3150 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3151 are no restrictions.
3153 usri11_code_page specifies the code page for the user's language of
3154 choice
3156 All of the pointers in this data structure need to be treated
3157 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3158 to be ignored. The converter word returned in the parameters section
3159 needs to be subtracted from the lower 16 bits to calculate an offset
3160 into the return buffer where this ASCII string resides.
3162 There is no auxiliary data in the response.
3164 ****************************************************************************/
3166 #define usri11_name 0
3167 #define usri11_pad 21
3168 #define usri11_comment 22
3169 #define usri11_usr_comment 26
3170 #define usri11_full_name 30
3171 #define usri11_priv 34
3172 #define usri11_auth_flags 36
3173 #define usri11_password_age 40
3174 #define usri11_homedir 44
3175 #define usri11_parms 48
3176 #define usri11_last_logon 52
3177 #define usri11_last_logoff 56
3178 #define usri11_bad_pw_count 60
3179 #define usri11_num_logons 62
3180 #define usri11_logon_server 64
3181 #define usri11_country_code 68
3182 #define usri11_workstations 70
3183 #define usri11_max_storage 74
3184 #define usri11_units_per_week 78
3185 #define usri11_logon_hours 80
3186 #define usri11_code_page 84
3187 #define usri11_end 86
3189 #define USER_PRIV_GUEST 0
3190 #define USER_PRIV_USER 1
3191 #define USER_PRIV_ADMIN 2
3193 #define AF_OP_PRINT 0
3194 #define AF_OP_COMM 1
3195 #define AF_OP_SERVER 2
3196 #define AF_OP_ACCOUNTS 3
3199 static BOOL api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3200 char *param, int tpscnt,
3201 char *data, int tdscnt,
3202 int mdrcnt,int mprcnt,
3203 char **rdata,char **rparam,
3204 int *rdata_len,int *rparam_len)
3206 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3207 char *str2 = skip_string(param,tpscnt,str1);
3208 char *UserName = skip_string(param,tpscnt,str2);
3209 char *p = skip_string(param,tpscnt,UserName);
3210 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3211 char *p2;
3212 const char *level_string;
3214 /* get NIS home of a previously validated user - simeon */
3215 /* With share level security vuid will always be zero.
3216 Don't depend on vuser being non-null !!. JRA */
3217 user_struct *vuser = get_valid_user_struct(vuid);
3218 if(vuser != NULL) {
3219 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3220 vuser->user.unix_name));
3223 if (!str1 || !str2 || !UserName || !p) {
3224 return False;
3227 *rparam_len = 6;
3228 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3229 if (!*rparam) {
3230 return False;
3233 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3235 /* check it's a supported variant */
3236 if (strcmp(str1,"zWrLh") != 0) {
3237 return False;
3239 switch( uLevel ) {
3240 case 0: level_string = "B21"; break;
3241 case 1: level_string = "B21BB16DWzzWz"; break;
3242 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3243 case 10: level_string = "B21Bzzz"; break;
3244 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3245 default: return False;
3248 if (strcmp(level_string,str2) != 0) {
3249 return False;
3252 *rdata_len = mdrcnt + 1024;
3253 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
3254 if (!*rdata) {
3255 return False;
3258 SSVAL(*rparam,0,NERR_Success);
3259 SSVAL(*rparam,2,0); /* converter word */
3261 p = *rdata;
3262 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3263 if (!p2) {
3264 return False;
3267 memset(p,0,21);
3268 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3270 if (uLevel > 0) {
3271 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3272 *p2 = 0;
3275 if (uLevel >= 10) {
3276 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3277 pstrcpy(p2,"Comment");
3278 p2 = skip_string(*rdata,*rdata_len,p2);
3279 if (!p2) {
3280 return False;
3283 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3284 pstrcpy(p2,"UserComment");
3285 p2 = skip_string(*rdata,*rdata_len,p2);
3286 if (!p2) {
3287 return False;
3290 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3291 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3292 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3293 p2 = skip_string(*rdata,*rdata_len,p2);
3294 if (!p2) {
3295 return False;
3299 if (uLevel == 11) {
3300 /* modelled after NTAS 3.51 reply */
3301 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3302 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3303 SIVALS(p,usri11_password_age,-1); /* password age */
3304 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3305 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3306 p2 = skip_string(*rdata,*rdata_len,p2);
3307 if (!p2) {
3308 return False;
3310 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3311 pstrcpy(p2,"");
3312 p2 = skip_string(*rdata,*rdata_len,p2);
3313 if (!p2) {
3314 return False;
3316 SIVAL(p,usri11_last_logon,0); /* last logon */
3317 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3318 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3319 SSVALS(p,usri11_num_logons,-1); /* num logons */
3320 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3321 pstrcpy(p2,"\\\\*");
3322 p2 = skip_string(*rdata,*rdata_len,p2);
3323 if (!p2) {
3324 return False;
3326 SSVAL(p,usri11_country_code,0); /* country code */
3328 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3329 pstrcpy(p2,"");
3330 p2 = skip_string(*rdata,*rdata_len,p2);
3331 if (!p2) {
3332 return False;
3335 SIVALS(p,usri11_max_storage,-1); /* max storage */
3336 SSVAL(p,usri11_units_per_week,168); /* units per week */
3337 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3339 /* a simple way to get logon hours at all times. */
3340 memset(p2,0xff,21);
3341 SCVAL(p2,21,0); /* fix zero termination */
3342 p2 = skip_string(*rdata,*rdata_len,p2);
3343 if (!p2) {
3344 return False;
3347 SSVAL(p,usri11_code_page,0); /* code page */
3350 if (uLevel == 1 || uLevel == 2) {
3351 memset(p+22,' ',16); /* password */
3352 SIVALS(p,38,-1); /* password age */
3353 SSVAL(p,42,
3354 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3355 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3356 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3357 p2 = skip_string(*rdata,*rdata_len,p2);
3358 if (!p2) {
3359 return False;
3361 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3362 *p2++ = 0;
3363 SSVAL(p,52,0); /* flags */
3364 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3365 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3366 p2 = skip_string(*rdata,*rdata_len,p2);
3367 if (!p2) {
3368 return False;
3370 if (uLevel == 2) {
3371 SIVAL(p,60,0); /* auth_flags */
3372 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3373 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3374 p2 = skip_string(*rdata,*rdata_len,p2);
3375 if (!p2) {
3376 return False;
3378 SIVAL(p,68,0); /* urs_comment */
3379 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3380 pstrcpy(p2,"");
3381 p2 = skip_string(*rdata,*rdata_len,p2);
3382 if (!p2) {
3383 return False;
3385 SIVAL(p,76,0); /* workstations */
3386 SIVAL(p,80,0); /* last_logon */
3387 SIVAL(p,84,0); /* last_logoff */
3388 SIVALS(p,88,-1); /* acct_expires */
3389 SIVALS(p,92,-1); /* max_storage */
3390 SSVAL(p,96,168); /* units_per_week */
3391 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3392 memset(p2,-1,21);
3393 p2 += 21;
3394 SSVALS(p,102,-1); /* bad_pw_count */
3395 SSVALS(p,104,-1); /* num_logons */
3396 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3398 pstring tmp;
3399 pstrcpy(tmp, "\\\\%L");
3400 standard_sub_basic("", "", tmp, sizeof(tmp));
3401 pstrcpy(p2, tmp);
3403 p2 = skip_string(*rdata,*rdata_len,p2);
3404 if (!p2) {
3405 return False;
3407 SSVAL(p,110,49); /* country_code */
3408 SSVAL(p,112,860); /* code page */
3412 *rdata_len = PTR_DIFF(p2,*rdata);
3414 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3416 return(True);
3419 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3420 char *param, int tpscnt,
3421 char *data, int tdscnt,
3422 int mdrcnt,int mprcnt,
3423 char **rdata,char **rparam,
3424 int *rdata_len,int *rparam_len)
3426 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3427 char *str2 = skip_string(param,tpscnt,str1);
3428 char *p = skip_string(param,tpscnt,str2);
3429 int uLevel;
3430 struct pack_desc desc;
3431 char* name;
3432 /* With share level security vuid will always be zero.
3433 Don't depend on vuser being non-null !!. JRA */
3434 user_struct *vuser = get_valid_user_struct(vuid);
3436 if (!str1 || !str2 || !p) {
3437 return False;
3440 if(vuser != NULL) {
3441 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3442 vuser->user.unix_name));
3445 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3446 name = get_safe_str_ptr(param,tpscnt,p,2);
3447 if (!name) {
3448 return False;
3451 memset((char *)&desc,'\0',sizeof(desc));
3453 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3455 /* check it's a supported varient */
3456 if (strcmp(str1,"OOWb54WrLh") != 0) {
3457 return False;
3459 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3460 return False;
3462 if (mdrcnt > 0) {
3463 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3464 if (!*rdata) {
3465 return False;
3469 desc.base = *rdata;
3470 desc.buflen = mdrcnt;
3471 desc.subformat = NULL;
3472 desc.format = str2;
3474 if (init_package(&desc,1,0)) {
3475 PACKI(&desc,"W",0); /* code */
3476 PACKS(&desc,"B21",name); /* eff. name */
3477 PACKS(&desc,"B",""); /* pad */
3478 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3479 PACKI(&desc,"D",0); /* auth flags XXX */
3480 PACKI(&desc,"W",0); /* num logons */
3481 PACKI(&desc,"W",0); /* bad pw count */
3482 PACKI(&desc,"D",0); /* last logon */
3483 PACKI(&desc,"D",-1); /* last logoff */
3484 PACKI(&desc,"D",-1); /* logoff time */
3485 PACKI(&desc,"D",-1); /* kickoff time */
3486 PACKI(&desc,"D",0); /* password age */
3487 PACKI(&desc,"D",0); /* password can change */
3488 PACKI(&desc,"D",-1); /* password must change */
3491 fstring mypath;
3492 fstrcpy(mypath,"\\\\");
3493 fstrcat(mypath,get_local_machine_name());
3494 strupper_m(mypath);
3495 PACKS(&desc,"z",mypath); /* computer */
3498 PACKS(&desc,"z",lp_workgroup());/* domain */
3499 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3500 PACKI(&desc,"D",0x00000000); /* reserved */
3503 *rdata_len = desc.usedlen;
3504 *rparam_len = 6;
3505 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3506 if (!*rparam) {
3507 return False;
3509 SSVALS(*rparam,0,desc.errcode);
3510 SSVAL(*rparam,2,0);
3511 SSVAL(*rparam,4,desc.neededlen);
3513 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3515 return True;
3518 /****************************************************************************
3519 api_WAccessGetUserPerms
3520 ****************************************************************************/
3522 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3523 char *param, int tpscnt,
3524 char *data, int tdscnt,
3525 int mdrcnt,int mprcnt,
3526 char **rdata,char **rparam,
3527 int *rdata_len,int *rparam_len)
3529 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3530 char *str2 = skip_string(param,tpscnt,str1);
3531 char *user = skip_string(param,tpscnt,str2);
3532 char *resource = skip_string(param,tpscnt,user);
3534 if (!str1 || !str2 || !user || !resource) {
3535 return False;
3538 if (skip_string(param,tpscnt,resource) == NULL) {
3539 return False;
3541 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3543 /* check it's a supported varient */
3544 if (strcmp(str1,"zzh") != 0) {
3545 return False;
3547 if (strcmp(str2,"") != 0) {
3548 return False;
3551 *rparam_len = 6;
3552 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3553 if (!*rparam) {
3554 return False;
3556 SSVALS(*rparam,0,0); /* errorcode */
3557 SSVAL(*rparam,2,0); /* converter word */
3558 SSVAL(*rparam,4,0x7f); /* permission flags */
3560 return True;
3563 /****************************************************************************
3564 api_WPrintJobEnumerate
3565 ****************************************************************************/
3567 static BOOL api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3568 char *param, int tpscnt,
3569 char *data, int tdscnt,
3570 int mdrcnt,int mprcnt,
3571 char **rdata,char **rparam,
3572 int *rdata_len,int *rparam_len)
3574 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3575 char *str2 = skip_string(param,tpscnt,str1);
3576 char *p = skip_string(param,tpscnt,str2);
3577 int uLevel;
3578 int count;
3579 int i;
3580 int snum;
3581 fstring sharename;
3582 uint32 jobid;
3583 struct pack_desc desc;
3584 print_queue_struct *queue=NULL;
3585 print_status_struct status;
3586 char *tmpdata=NULL;
3588 if (!str1 || !str2 || !p) {
3589 return False;
3592 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3594 memset((char *)&desc,'\0',sizeof(desc));
3595 memset((char *)&status,'\0',sizeof(status));
3597 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3599 /* check it's a supported varient */
3600 if (strcmp(str1,"WWrLh") != 0) {
3601 return False;
3603 if (!check_printjob_info(&desc,uLevel,str2)) {
3604 return False;
3607 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3608 return False;
3611 snum = lp_servicenumber( sharename);
3612 if (snum < 0 || !VALID_SNUM(snum)) {
3613 return(False);
3616 count = print_queue_status(snum,&queue,&status);
3617 for (i = 0; i < count; i++) {
3618 if (queue[i].job == jobid) {
3619 break;
3623 if (mdrcnt > 0) {
3624 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3625 if (!*rdata) {
3626 return False;
3628 desc.base = *rdata;
3629 desc.buflen = mdrcnt;
3630 } else {
3632 * Don't return data but need to get correct length
3633 * init_package will return wrong size if buflen=0
3635 desc.buflen = getlen(desc.format);
3636 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3639 if (init_package(&desc,1,0)) {
3640 if (i < count) {
3641 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3642 *rdata_len = desc.usedlen;
3643 } else {
3644 desc.errcode = NERR_JobNotFound;
3645 *rdata_len = 0;
3649 *rparam_len = 6;
3650 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3651 if (!*rparam) {
3652 return False;
3654 SSVALS(*rparam,0,desc.errcode);
3655 SSVAL(*rparam,2,0);
3656 SSVAL(*rparam,4,desc.neededlen);
3658 SAFE_FREE(queue);
3659 SAFE_FREE(tmpdata);
3661 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3663 return True;
3666 static BOOL api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3667 char *param, int tpscnt,
3668 char *data, int tdscnt,
3669 int mdrcnt,int mprcnt,
3670 char **rdata,char **rparam,
3671 int *rdata_len,int *rparam_len)
3673 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3674 char *str2 = skip_string(param,tpscnt,str1);
3675 char *p = skip_string(param,tpscnt,str2);
3676 char *name = p;
3677 int uLevel;
3678 int count;
3679 int i, succnt=0;
3680 int snum;
3681 struct pack_desc desc;
3682 print_queue_struct *queue=NULL;
3683 print_status_struct status;
3685 if (!str1 || !str2 || !p) {
3686 return False;
3689 memset((char *)&desc,'\0',sizeof(desc));
3690 memset((char *)&status,'\0',sizeof(status));
3692 p = skip_string(param,tpscnt,p);
3693 if (!p) {
3694 return False;
3696 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3698 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3700 /* check it's a supported variant */
3701 if (strcmp(str1,"zWrLeh") != 0) {
3702 return False;
3705 if (uLevel > 2) {
3706 return False; /* defined only for uLevel 0,1,2 */
3709 if (!check_printjob_info(&desc,uLevel,str2)) {
3710 return False;
3713 snum = find_service(name);
3714 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3715 return False;
3718 count = print_queue_status(snum,&queue,&status);
3719 if (mdrcnt > 0) {
3720 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3721 if (!*rdata) {
3722 return False;
3725 desc.base = *rdata;
3726 desc.buflen = mdrcnt;
3728 if (init_package(&desc,count,0)) {
3729 succnt = 0;
3730 for (i = 0; i < count; i++) {
3731 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3732 if (desc.errcode == NERR_Success) {
3733 succnt = i+1;
3738 *rdata_len = desc.usedlen;
3740 *rparam_len = 8;
3741 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3742 if (!*rparam) {
3743 return False;
3745 SSVALS(*rparam,0,desc.errcode);
3746 SSVAL(*rparam,2,0);
3747 SSVAL(*rparam,4,succnt);
3748 SSVAL(*rparam,6,count);
3750 SAFE_FREE(queue);
3752 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3754 return True;
3757 static int check_printdest_info(struct pack_desc* desc,
3758 int uLevel, char* id)
3760 desc->subformat = NULL;
3761 switch( uLevel ) {
3762 case 0:
3763 desc->format = "B9";
3764 break;
3765 case 1:
3766 desc->format = "B9B21WWzW";
3767 break;
3768 case 2:
3769 desc->format = "z";
3770 break;
3771 case 3:
3772 desc->format = "zzzWWzzzWW";
3773 break;
3774 default:
3775 DEBUG(0,("check_printdest_info: invalid level %d\n",
3776 uLevel));
3777 return False;
3779 if (id == NULL || strcmp(desc->format,id) != 0) {
3780 DEBUG(0,("check_printdest_info: invalid string %s\n",
3781 id ? id : "<NULL>" ));
3782 return False;
3784 return True;
3787 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3788 struct pack_desc* desc)
3790 char buf[100];
3792 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3793 buf[sizeof(buf)-1] = 0;
3794 strupper_m(buf);
3796 if (uLevel <= 1) {
3797 PACKS(desc,"B9",buf); /* szName */
3798 if (uLevel == 1) {
3799 PACKS(desc,"B21",""); /* szUserName */
3800 PACKI(desc,"W",0); /* uJobId */
3801 PACKI(desc,"W",0); /* fsStatus */
3802 PACKS(desc,"z",""); /* pszStatus */
3803 PACKI(desc,"W",0); /* time */
3807 if (uLevel == 2 || uLevel == 3) {
3808 PACKS(desc,"z",buf); /* pszPrinterName */
3809 if (uLevel == 3) {
3810 PACKS(desc,"z",""); /* pszUserName */
3811 PACKS(desc,"z",""); /* pszLogAddr */
3812 PACKI(desc,"W",0); /* uJobId */
3813 PACKI(desc,"W",0); /* fsStatus */
3814 PACKS(desc,"z",""); /* pszStatus */
3815 PACKS(desc,"z",""); /* pszComment */
3816 PACKS(desc,"z","NULL"); /* pszDrivers */
3817 PACKI(desc,"W",0); /* time */
3818 PACKI(desc,"W",0); /* pad1 */
3823 static BOOL api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3824 char *param, int tpscnt,
3825 char *data, int tdscnt,
3826 int mdrcnt,int mprcnt,
3827 char **rdata,char **rparam,
3828 int *rdata_len,int *rparam_len)
3830 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3831 char *str2 = skip_string(param,tpscnt,str1);
3832 char *p = skip_string(param,tpscnt,str2);
3833 char* PrinterName = p;
3834 int uLevel;
3835 struct pack_desc desc;
3836 int snum;
3837 char *tmpdata=NULL;
3839 if (!str1 || !str2 || !p) {
3840 return False;
3843 memset((char *)&desc,'\0',sizeof(desc));
3845 p = skip_string(param,tpscnt,p);
3846 if (!p) {
3847 return False;
3849 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3851 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3853 /* check it's a supported varient */
3854 if (strcmp(str1,"zWrLh") != 0) {
3855 return False;
3857 if (!check_printdest_info(&desc,uLevel,str2)) {
3858 return False;
3861 snum = find_service(PrinterName);
3862 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3863 *rdata_len = 0;
3864 desc.errcode = NERR_DestNotFound;
3865 desc.neededlen = 0;
3866 } else {
3867 if (mdrcnt > 0) {
3868 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3869 if (!*rdata) {
3870 return False;
3872 desc.base = *rdata;
3873 desc.buflen = mdrcnt;
3874 } else {
3876 * Don't return data but need to get correct length
3877 * init_package will return wrong size if buflen=0
3879 desc.buflen = getlen(desc.format);
3880 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3882 if (init_package(&desc,1,0)) {
3883 fill_printdest_info(conn,snum,uLevel,&desc);
3885 *rdata_len = desc.usedlen;
3888 *rparam_len = 6;
3889 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3890 if (!*rparam) {
3891 return False;
3893 SSVALS(*rparam,0,desc.errcode);
3894 SSVAL(*rparam,2,0);
3895 SSVAL(*rparam,4,desc.neededlen);
3897 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3898 SAFE_FREE(tmpdata);
3900 return True;
3903 static BOOL api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
3904 char *param, int tpscnt,
3905 char *data, int tdscnt,
3906 int mdrcnt,int mprcnt,
3907 char **rdata,char **rparam,
3908 int *rdata_len,int *rparam_len)
3910 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3911 char *str2 = skip_string(param,tpscnt,str1);
3912 char *p = skip_string(param,tpscnt,str2);
3913 int uLevel;
3914 int queuecnt;
3915 int i, n, succnt=0;
3916 struct pack_desc desc;
3917 int services = lp_numservices();
3919 if (!str1 || !str2 || !p) {
3920 return False;
3923 memset((char *)&desc,'\0',sizeof(desc));
3925 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3927 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3929 /* check it's a supported varient */
3930 if (strcmp(str1,"WrLeh") != 0) {
3931 return False;
3933 if (!check_printdest_info(&desc,uLevel,str2)) {
3934 return False;
3937 queuecnt = 0;
3938 for (i = 0; i < services; i++) {
3939 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3940 queuecnt++;
3944 if (mdrcnt > 0) {
3945 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3946 if (!*rdata) {
3947 return False;
3951 desc.base = *rdata;
3952 desc.buflen = mdrcnt;
3953 if (init_package(&desc,queuecnt,0)) {
3954 succnt = 0;
3955 n = 0;
3956 for (i = 0; i < services; i++) {
3957 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3958 fill_printdest_info(conn,i,uLevel,&desc);
3959 n++;
3960 if (desc.errcode == NERR_Success) {
3961 succnt = n;
3967 *rdata_len = desc.usedlen;
3969 *rparam_len = 8;
3970 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3971 if (!*rparam) {
3972 return False;
3974 SSVALS(*rparam,0,desc.errcode);
3975 SSVAL(*rparam,2,0);
3976 SSVAL(*rparam,4,succnt);
3977 SSVAL(*rparam,6,queuecnt);
3979 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3981 return True;
3984 static BOOL api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
3985 char *param, int tpscnt,
3986 char *data, int tdscnt,
3987 int mdrcnt,int mprcnt,
3988 char **rdata,char **rparam,
3989 int *rdata_len,int *rparam_len)
3991 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3992 char *str2 = skip_string(param,tpscnt,str1);
3993 char *p = skip_string(param,tpscnt,str2);
3994 int uLevel;
3995 int succnt;
3996 struct pack_desc desc;
3998 if (!str1 || !str2 || !p) {
3999 return False;
4002 memset((char *)&desc,'\0',sizeof(desc));
4004 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4006 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4008 /* check it's a supported varient */
4009 if (strcmp(str1,"WrLeh") != 0) {
4010 return False;
4012 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4013 return False;
4016 if (mdrcnt > 0) {
4017 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4018 if (!*rdata) {
4019 return False;
4022 desc.base = *rdata;
4023 desc.buflen = mdrcnt;
4024 if (init_package(&desc,1,0)) {
4025 PACKS(&desc,"B41","NULL");
4028 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4030 *rdata_len = desc.usedlen;
4032 *rparam_len = 8;
4033 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4034 if (!*rparam) {
4035 return False;
4037 SSVALS(*rparam,0,desc.errcode);
4038 SSVAL(*rparam,2,0);
4039 SSVAL(*rparam,4,succnt);
4040 SSVAL(*rparam,6,1);
4042 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4044 return True;
4047 static BOOL api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4048 char *param, int tpscnt,
4049 char *data, int tdscnt,
4050 int mdrcnt,int mprcnt,
4051 char **rdata,char **rparam,
4052 int *rdata_len,int *rparam_len)
4054 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4055 char *str2 = skip_string(param,tpscnt,str1);
4056 char *p = skip_string(param,tpscnt,str2);
4057 int uLevel;
4058 int succnt;
4059 struct pack_desc desc;
4061 if (!str1 || !str2 || !p) {
4062 return False;
4064 memset((char *)&desc,'\0',sizeof(desc));
4066 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4068 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4070 /* check it's a supported varient */
4071 if (strcmp(str1,"WrLeh") != 0) {
4072 return False;
4074 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4075 return False;
4078 if (mdrcnt > 0) {
4079 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4080 if (!*rdata) {
4081 return False;
4084 desc.base = *rdata;
4085 desc.buflen = mdrcnt;
4086 desc.format = str2;
4087 if (init_package(&desc,1,0)) {
4088 PACKS(&desc,"B13","lpd");
4091 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4093 *rdata_len = desc.usedlen;
4095 *rparam_len = 8;
4096 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4097 if (!*rparam) {
4098 return False;
4100 SSVALS(*rparam,0,desc.errcode);
4101 SSVAL(*rparam,2,0);
4102 SSVAL(*rparam,4,succnt);
4103 SSVAL(*rparam,6,1);
4105 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4107 return True;
4110 static BOOL api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4111 char *param, int tpscnt,
4112 char *data, int tdscnt,
4113 int mdrcnt,int mprcnt,
4114 char **rdata,char **rparam,
4115 int *rdata_len,int *rparam_len)
4117 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4118 char *str2 = skip_string(param,tpscnt,str1);
4119 char *p = skip_string(param,tpscnt,str2);
4120 int uLevel;
4121 int succnt;
4122 struct pack_desc desc;
4124 if (!str1 || !str2 || !p) {
4125 return False;
4128 memset((char *)&desc,'\0',sizeof(desc));
4130 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4132 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4134 /* check it's a supported varient */
4135 if (strcmp(str1,"WrLeh") != 0) {
4136 return False;
4138 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4139 return False;
4142 if (mdrcnt > 0) {
4143 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4144 if (!*rdata) {
4145 return False;
4148 memset((char *)&desc,'\0',sizeof(desc));
4149 desc.base = *rdata;
4150 desc.buflen = mdrcnt;
4151 desc.format = str2;
4152 if (init_package(&desc,1,0)) {
4153 PACKS(&desc,"B13","lp0");
4156 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4158 *rdata_len = desc.usedlen;
4160 *rparam_len = 8;
4161 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4162 if (!*rparam) {
4163 return False;
4165 SSVALS(*rparam,0,desc.errcode);
4166 SSVAL(*rparam,2,0);
4167 SSVAL(*rparam,4,succnt);
4168 SSVAL(*rparam,6,1);
4170 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4172 return True;
4175 /****************************************************************************
4176 List open sessions
4177 ****************************************************************************/
4179 static BOOL api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4180 char *param, int tpscnt,
4181 char *data, int tdscnt,
4182 int mdrcnt,int mprcnt,
4183 char **rdata,char **rparam,
4184 int *rdata_len,int *rparam_len)
4187 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4188 char *str2 = skip_string(param,tpscnt,str1);
4189 char *p = skip_string(param,tpscnt,str2);
4190 int uLevel;
4191 struct pack_desc desc;
4192 struct sessionid *session_list = NULL;
4193 int i, num_sessions;
4195 if (!str1 || !str2 || !p) {
4196 return False;
4199 memset((char *)&desc,'\0',sizeof(desc));
4201 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4203 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4204 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4205 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4207 /* check it's a supported varient */
4208 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4209 return False;
4211 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4212 return False;
4215 num_sessions = list_sessions(&session_list);
4217 if (mdrcnt > 0) {
4218 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4219 if (!*rdata) {
4220 SAFE_FREE(session_list);
4221 return False;
4224 memset((char *)&desc,'\0',sizeof(desc));
4225 desc.base = *rdata;
4226 desc.buflen = mdrcnt;
4227 desc.format = str2;
4228 if (!init_package(&desc,num_sessions,0)) {
4229 SAFE_FREE(session_list);
4230 return False;
4233 for(i=0; i<num_sessions; i++) {
4234 PACKS(&desc, "z", session_list[i].remote_machine);
4235 PACKS(&desc, "z", session_list[i].username);
4236 PACKI(&desc, "W", 1); /* num conns */
4237 PACKI(&desc, "W", 0); /* num opens */
4238 PACKI(&desc, "W", 1); /* num users */
4239 PACKI(&desc, "D", 0); /* session time */
4240 PACKI(&desc, "D", 0); /* idle time */
4241 PACKI(&desc, "D", 0); /* flags */
4242 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4245 *rdata_len = desc.usedlen;
4247 *rparam_len = 8;
4248 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4249 if (!*rparam) {
4250 SAFE_FREE(session_list);
4251 return False;
4253 SSVALS(*rparam,0,desc.errcode);
4254 SSVAL(*rparam,2,0); /* converter */
4255 SSVAL(*rparam,4,num_sessions); /* count */
4257 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4259 SAFE_FREE(session_list);
4260 return True;
4264 /****************************************************************************
4265 The buffer was too small.
4266 ****************************************************************************/
4268 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4269 int mdrcnt, int mprcnt,
4270 char **rdata, char **rparam,
4271 int *rdata_len, int *rparam_len)
4273 *rparam_len = MIN(*rparam_len,mprcnt);
4274 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4275 if (!*rparam) {
4276 return False;
4279 *rdata_len = 0;
4281 SSVAL(*rparam,0,NERR_BufTooSmall);
4283 DEBUG(3,("Supplied buffer too small in API command\n"));
4285 return True;
4288 /****************************************************************************
4289 The request is not supported.
4290 ****************************************************************************/
4292 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
4293 char *param, int tpscnt,
4294 char *data, int tdscnt,
4295 int mdrcnt, int mprcnt,
4296 char **rdata, char **rparam,
4297 int *rdata_len, int *rparam_len)
4299 *rparam_len = 4;
4300 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4301 if (!*rparam) {
4302 return False;
4305 *rdata_len = 0;
4307 SSVAL(*rparam,0,NERR_notsupported);
4308 SSVAL(*rparam,2,0); /* converter word */
4310 DEBUG(3,("Unsupported API command\n"));
4312 return True;
4315 static const struct {
4316 const char *name;
4317 int id;
4318 BOOL (*fn)(connection_struct *, uint16,
4319 char *, int,
4320 char *, int,
4321 int,int,char **,char **,int *,int *);
4322 BOOL auth_user; /* Deny anonymous access? */
4323 } api_commands[] = {
4324 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4325 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4326 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4327 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4328 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4329 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4330 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4331 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4332 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4333 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4334 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4335 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4336 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4337 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4338 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4339 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4340 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4341 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4342 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4343 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4344 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4345 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4346 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4347 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4348 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4349 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4350 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4351 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4352 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4353 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4354 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4355 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4356 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4357 {NULL, -1, api_Unsupported}
4358 /* The following RAP calls are not implemented by Samba:
4360 RAP_WFileEnum2 - anon not OK
4365 /****************************************************************************
4366 Handle remote api calls
4367 ****************************************************************************/
4369 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
4370 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
4372 int api_command;
4373 char *rdata = NULL;
4374 char *rparam = NULL;
4375 const char *name1 = NULL;
4376 const char *name2 = NULL;
4377 int rdata_len = 0;
4378 int rparam_len = 0;
4379 BOOL reply=False;
4380 int i;
4382 if (!params) {
4383 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4384 return 0;
4387 if (tpscnt < 2) {
4388 return 0;
4390 api_command = SVAL(params,0);
4391 /* Is there a string at position params+2 ? */
4392 if (skip_string(params,tpscnt,params+2)) {
4393 name1 = params + 2;
4394 } else {
4395 name1 = "";
4397 name2 = skip_string(params,tpscnt,params+2);
4398 if (!name2) {
4399 name2 = "";
4402 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4403 api_command,
4404 name1,
4405 name2,
4406 tdscnt,tpscnt,mdrcnt,mprcnt));
4408 for (i=0;api_commands[i].name;i++) {
4409 if (api_commands[i].id == api_command && api_commands[i].fn) {
4410 DEBUG(3,("Doing %s\n",api_commands[i].name));
4411 break;
4415 /* Check whether this api call can be done anonymously */
4417 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4418 user_struct *user = get_valid_user_struct(vuid);
4420 if (!user || user->guest) {
4421 return ERROR_NT(NT_STATUS_ACCESS_DENIED);
4425 rdata = (char *)SMB_MALLOC(1024);
4426 if (rdata) {
4427 memset(rdata,'\0',1024);
4430 rparam = (char *)SMB_MALLOC(1024);
4431 if (rparam) {
4432 memset(rparam,'\0',1024);
4435 if(!rdata || !rparam) {
4436 DEBUG(0,("api_reply: malloc fail !\n"));
4437 SAFE_FREE(rdata);
4438 SAFE_FREE(rparam);
4439 return -1;
4442 reply = api_commands[i].fn(conn,
4443 vuid,
4444 params,tpscnt, /* params + length */
4445 data,tdscnt, /* data + length */
4446 mdrcnt,mprcnt,
4447 &rdata,&rparam,&rdata_len,&rparam_len);
4450 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4451 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4452 &rdata,&rparam,&rdata_len,&rparam_len);
4455 /* if we get False back then it's actually unsupported */
4456 if (!reply) {
4457 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4458 &rdata,&rparam,&rdata_len,&rparam_len);
4461 /* If api_Unsupported returns false we can't return anything. */
4462 if (reply) {
4463 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
4466 SAFE_FREE(rdata);
4467 SAFE_FREE(rparam);
4468 return -1;