r23510: Tidy calls to smb_panic by removing trailing newlines. Print the
[Samba.git] / source3 / smbd / lanman.c
blob0a9a529a85f4cc8846c608a257d48a9d378783c4
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 load_registry_shares();
1724 count = load_usershare_shares();
1725 unbecome_root();
1727 data_len = fixed_len = string_len = 0;
1728 for (i=0;i<count;i++) {
1729 fstring servicename_dos;
1730 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1731 continue;
1733 push_ascii_fstring(servicename_dos, lp_servicename(i));
1734 /* Maximum name length = 13. */
1735 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1736 total++;
1737 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1738 if (data_len <= buf_len) {
1739 counted++;
1740 fixed_len += f_len;
1741 string_len += s_len;
1742 } else {
1743 missed = True;
1748 *rdata_len = fixed_len + string_len;
1749 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1750 if (!*rdata) {
1751 return False;
1753 memset(*rdata,0,*rdata_len);
1755 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1756 p = *rdata;
1757 f_len = fixed_len;
1758 s_len = string_len;
1760 for( i = 0; i < count; i++ ) {
1761 fstring servicename_dos;
1762 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1763 continue;
1766 push_ascii_fstring(servicename_dos, lp_servicename(i));
1767 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1768 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1769 break;
1774 *rparam_len = 8;
1775 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1776 if (!*rparam) {
1777 return False;
1779 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1780 SSVAL(*rparam,2,0);
1781 SSVAL(*rparam,4,counted);
1782 SSVAL(*rparam,6,total);
1784 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1785 counted,total,uLevel,
1786 buf_len,*rdata_len,mdrcnt));
1788 return True;
1791 /****************************************************************************
1792 Add a share
1793 ****************************************************************************/
1795 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1796 char *param, int tpscnt,
1797 char *data, int tdscnt,
1798 int mdrcnt,int mprcnt,
1799 char **rdata,char **rparam,
1800 int *rdata_len,int *rparam_len)
1802 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1803 char *str2 = skip_string(param,tpscnt,str1);
1804 char *p = skip_string(param,tpscnt,str2);
1805 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1806 fstring sharename;
1807 fstring comment;
1808 pstring pathname;
1809 char *command, *cmdname;
1810 unsigned int offset;
1811 int snum;
1812 int res = ERRunsup;
1814 if (!str1 || !str2 || !p) {
1815 return False;
1818 /* check it's a supported varient */
1819 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1820 return False;
1822 if (!check_share_info(uLevel,str2)) {
1823 return False;
1825 if (uLevel != 2) {
1826 return False;
1829 /* Do we have a string ? */
1830 if (skip_string(data,mdrcnt,data) == NULL) {
1831 return False;
1833 pull_ascii_fstring(sharename,data);
1834 snum = find_service(sharename);
1835 if (snum >= 0) { /* already exists */
1836 res = ERRfilexists;
1837 goto error_exit;
1840 if (mdrcnt < 28) {
1841 return False;
1844 /* only support disk share adds */
1845 if (SVAL(data,14)!=STYPE_DISKTREE) {
1846 return False;
1849 offset = IVAL(data, 16);
1850 if (offset >= mdrcnt) {
1851 res = ERRinvalidparam;
1852 goto error_exit;
1855 /* Do we have a string ? */
1856 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1857 return False;
1859 pull_ascii_fstring(comment, offset? (data+offset) : "");
1861 offset = IVAL(data, 26);
1863 if (offset >= mdrcnt) {
1864 res = ERRinvalidparam;
1865 goto error_exit;
1868 /* Do we have a string ? */
1869 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1870 return False;
1872 pull_ascii_pstring(pathname, offset? (data+offset) : "");
1874 string_replace(sharename, '"', ' ');
1875 string_replace(pathname, '"', ' ');
1876 string_replace(comment, '"', ' ');
1878 cmdname = lp_add_share_cmd();
1880 if (!cmdname || *cmdname == '\0') {
1881 return False;
1884 asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1885 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1887 if (command) {
1888 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1890 if ((res = smbrun(command, NULL)) != 0) {
1891 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1892 SAFE_FREE(command);
1893 res = ERRnoaccess;
1894 goto error_exit;
1895 } else {
1896 SAFE_FREE(command);
1897 message_send_all(smbd_messaging_context(),
1898 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1900 } else {
1901 return False;
1904 *rparam_len = 6;
1905 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1906 if (!*rparam) {
1907 return False;
1909 SSVAL(*rparam,0,NERR_Success);
1910 SSVAL(*rparam,2,0); /* converter word */
1911 SSVAL(*rparam,4,*rdata_len);
1912 *rdata_len = 0;
1914 return True;
1916 error_exit:
1918 *rparam_len = 4;
1919 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1920 if (!*rparam) {
1921 return False;
1923 *rdata_len = 0;
1924 SSVAL(*rparam,0,res);
1925 SSVAL(*rparam,2,0);
1926 return True;
1929 /****************************************************************************
1930 view list of groups available
1931 ****************************************************************************/
1933 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
1934 char *param, int tpscnt,
1935 char *data, int tdscnt,
1936 int mdrcnt,int mprcnt,
1937 char **rdata,char **rparam,
1938 int *rdata_len,int *rparam_len)
1940 int i;
1941 int errflags=0;
1942 int resume_context, cli_buf_size;
1943 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1944 char *str2 = skip_string(param,tpscnt,str1);
1945 char *p = skip_string(param,tpscnt,str2);
1947 struct pdb_search *search;
1948 struct samr_displayentry *entries;
1950 int num_entries;
1952 if (!str1 || !str2 || !p) {
1953 return False;
1956 if (strcmp(str1,"WrLeh") != 0) {
1957 return False;
1960 /* parameters
1961 * W-> resume context (number of users to skip)
1962 * r -> return parameter pointer to receive buffer
1963 * L -> length of receive buffer
1964 * e -> return parameter number of entries
1965 * h -> return parameter total number of users
1968 if (strcmp("B21",str2) != 0) {
1969 return False;
1972 /* get list of domain groups SID_DOMAIN_GRP=2 */
1973 become_root();
1974 search = pdb_search_groups();
1975 unbecome_root();
1977 if (search == NULL) {
1978 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1979 return False;
1982 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
1983 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
1984 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1985 "%d\n", resume_context, cli_buf_size));
1987 become_root();
1988 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1989 &entries);
1990 unbecome_root();
1992 *rdata_len = cli_buf_size;
1993 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1994 if (!*rdata) {
1995 return False;
1998 p = *rdata;
2000 for(i=0; i<num_entries; i++) {
2001 fstring name;
2002 fstrcpy(name, entries[i].account_name);
2003 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2004 /* truncate the name at 21 chars. */
2005 memcpy(p, name, 21);
2006 DEBUG(10,("adding entry %d group %s\n", i, p));
2007 p += 21;
2008 p += 5; /* Both NT4 and W2k3SP1 do padding here.
2009 No idea why... */
2010 } else {
2011 /* set overflow error */
2012 DEBUG(3,("overflow on entry %d group %s\n", i, name));
2013 errflags=234;
2014 break;
2018 pdb_search_destroy(search);
2020 *rdata_len = PTR_DIFF(p,*rdata);
2022 *rparam_len = 8;
2023 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2024 if (!*rparam) {
2025 return False;
2027 SSVAL(*rparam, 0, errflags);
2028 SSVAL(*rparam, 2, 0); /* converter word */
2029 SSVAL(*rparam, 4, i); /* is this right?? */
2030 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
2032 return(True);
2035 /*******************************************************************
2036 Get groups that a user is a member of.
2037 ******************************************************************/
2039 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2040 char *param, int tpscnt,
2041 char *data, int tdscnt,
2042 int mdrcnt,int mprcnt,
2043 char **rdata,char **rparam,
2044 int *rdata_len,int *rparam_len)
2046 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2047 char *str2 = skip_string(param,tpscnt,str1);
2048 char *UserName = skip_string(param,tpscnt,str2);
2049 char *p = skip_string(param,tpscnt,UserName);
2050 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2051 const char *level_string;
2052 int count=0;
2053 struct samu *sampw = NULL;
2054 BOOL ret = False;
2055 DOM_SID *sids;
2056 gid_t *gids;
2057 size_t num_groups;
2058 size_t i;
2059 NTSTATUS result;
2060 DOM_SID user_sid;
2061 enum lsa_SidType type;
2062 TALLOC_CTX *mem_ctx;
2064 if (!str1 || !str2 || !UserName || !p) {
2065 return False;
2068 *rparam_len = 8;
2069 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2070 if (!*rparam) {
2071 return False;
2074 /* check it's a supported varient */
2076 if ( strcmp(str1,"zWrLeh") != 0 )
2077 return False;
2079 switch( uLevel ) {
2080 case 0:
2081 level_string = "B21";
2082 break;
2083 default:
2084 return False;
2087 if (strcmp(level_string,str2) != 0)
2088 return False;
2090 *rdata_len = mdrcnt + 1024;
2091 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2092 if (!*rdata) {
2093 return False;
2095 SSVAL(*rparam,0,NERR_Success);
2096 SSVAL(*rparam,2,0); /* converter word */
2098 p = *rdata;
2100 mem_ctx = talloc_new(NULL);
2101 if (mem_ctx == NULL) {
2102 DEBUG(0, ("talloc_new failed\n"));
2103 return False;
2106 if ( !(sampw = samu_new(mem_ctx)) ) {
2107 DEBUG(0, ("samu_new() failed!\n"));
2108 TALLOC_FREE(mem_ctx);
2109 return False;
2112 /* Lookup the user information; This should only be one of
2113 our accounts (not remote domains) */
2115 become_root(); /* ROOT BLOCK */
2117 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2118 NULL, NULL, &user_sid, &type)) {
2119 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2120 goto done;
2123 if (type != SID_NAME_USER) {
2124 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2125 sid_type_lookup(type)));
2126 goto done;
2129 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2130 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2131 sid_string_static(&user_sid), UserName));
2132 goto done;
2135 gids = NULL;
2136 sids = NULL;
2137 num_groups = 0;
2139 result = pdb_enum_group_memberships(mem_ctx, sampw,
2140 &sids, &gids, &num_groups);
2142 if (!NT_STATUS_IS_OK(result)) {
2143 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2144 UserName));
2145 goto done;
2148 for (i=0; i<num_groups; i++) {
2150 const char *grp_name;
2152 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2153 pstrcpy(p, grp_name);
2154 p += 21;
2155 count++;
2159 *rdata_len = PTR_DIFF(p,*rdata);
2161 SSVAL(*rparam,4,count); /* is this right?? */
2162 SSVAL(*rparam,6,count); /* is this right?? */
2164 ret = True;
2166 done:
2167 unbecome_root(); /* END ROOT BLOCK */
2169 TALLOC_FREE(mem_ctx);
2171 return ret;
2174 /*******************************************************************
2175 Get all users.
2176 ******************************************************************/
2178 static BOOL api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2179 char *param, int tpscnt,
2180 char *data, int tdscnt,
2181 int mdrcnt,int mprcnt,
2182 char **rdata,char **rparam,
2183 int *rdata_len,int *rparam_len)
2185 int count_sent=0;
2186 int num_users=0;
2187 int errflags=0;
2188 int i, resume_context, cli_buf_size;
2189 struct pdb_search *search;
2190 struct samr_displayentry *users;
2192 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2193 char *str2 = skip_string(param,tpscnt,str1);
2194 char *p = skip_string(param,tpscnt,str2);
2196 if (!str1 || !str2 || !p) {
2197 return False;
2200 if (strcmp(str1,"WrLeh") != 0)
2201 return False;
2202 /* parameters
2203 * W-> resume context (number of users to skip)
2204 * r -> return parameter pointer to receive buffer
2205 * L -> length of receive buffer
2206 * e -> return parameter number of entries
2207 * h -> return parameter total number of users
2210 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2211 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2212 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2213 resume_context, cli_buf_size));
2215 *rparam_len = 8;
2216 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2217 if (!*rparam) {
2218 return False;
2221 /* check it's a supported varient */
2222 if (strcmp("B21",str2) != 0)
2223 return False;
2225 *rdata_len = cli_buf_size;
2226 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2227 if (!*rdata) {
2228 return False;
2231 p = *rdata;
2233 become_root();
2234 search = pdb_search_users(ACB_NORMAL);
2235 unbecome_root();
2236 if (search == NULL) {
2237 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2238 return False;
2241 become_root();
2242 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2243 &users);
2244 unbecome_root();
2246 errflags=NERR_Success;
2248 for (i=0; i<num_users; i++) {
2249 const char *name = users[i].account_name;
2251 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2252 pstrcpy(p,name);
2253 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2254 "%s\n",count_sent,p));
2255 p += 21;
2256 count_sent++;
2257 } else {
2258 /* set overflow error */
2259 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2260 "username %s\n",count_sent,name));
2261 errflags=234;
2262 break;
2266 pdb_search_destroy(search);
2268 *rdata_len = PTR_DIFF(p,*rdata);
2270 SSVAL(*rparam,0,errflags);
2271 SSVAL(*rparam,2,0); /* converter word */
2272 SSVAL(*rparam,4,count_sent); /* is this right?? */
2273 SSVAL(*rparam,6,num_users); /* is this right?? */
2275 return True;
2278 /****************************************************************************
2279 Get the time of day info.
2280 ****************************************************************************/
2282 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2283 char *param, int tpscnt,
2284 char *data, int tdscnt,
2285 int mdrcnt,int mprcnt,
2286 char **rdata,char **rparam,
2287 int *rdata_len,int *rparam_len)
2289 struct tm *t;
2290 time_t unixdate = time(NULL);
2291 char *p;
2293 *rparam_len = 4;
2294 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2295 if (!*rparam) {
2296 return False;
2299 *rdata_len = 21;
2300 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2301 if (!*rdata) {
2302 return False;
2305 SSVAL(*rparam,0,NERR_Success);
2306 SSVAL(*rparam,2,0); /* converter word */
2308 p = *rdata;
2310 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2311 by NT in a "net time" operation,
2312 it seems to ignore the one below */
2314 /* the client expects to get localtime, not GMT, in this bit
2315 (I think, this needs testing) */
2316 t = localtime(&unixdate);
2317 if (!t) {
2318 return False;
2321 SIVAL(p,4,0); /* msecs ? */
2322 SCVAL(p,8,t->tm_hour);
2323 SCVAL(p,9,t->tm_min);
2324 SCVAL(p,10,t->tm_sec);
2325 SCVAL(p,11,0); /* hundredths of seconds */
2326 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2327 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2328 SCVAL(p,16,t->tm_mday);
2329 SCVAL(p,17,t->tm_mon + 1);
2330 SSVAL(p,18,1900+t->tm_year);
2331 SCVAL(p,20,t->tm_wday);
2333 return True;
2336 /****************************************************************************
2337 Set the user password.
2338 *****************************************************************************/
2340 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid,
2341 char *param, int tpscnt,
2342 char *data, int tdscnt,
2343 int mdrcnt,int mprcnt,
2344 char **rdata,char **rparam,
2345 int *rdata_len,int *rparam_len)
2347 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2348 char *p = NULL;
2349 fstring user;
2350 fstring pass1,pass2;
2352 /* Skip 2 strings. */
2353 p = skip_string(param,tpscnt,np);
2354 p = skip_string(param,tpscnt,p);
2356 if (!np || !p) {
2357 return False;
2360 /* Do we have a string ? */
2361 if (skip_string(param,tpscnt,p) == NULL) {
2362 return False;
2364 pull_ascii_fstring(user,p);
2366 p = skip_string(param,tpscnt,p);
2367 if (!p) {
2368 return False;
2371 memset(pass1,'\0',sizeof(pass1));
2372 memset(pass2,'\0',sizeof(pass2));
2374 * We use 31 here not 32 as we're checking
2375 * the last byte we want to access is safe.
2377 if (!is_offset_safe(param,tpscnt,p,31)) {
2378 return False;
2380 memcpy(pass1,p,16);
2381 memcpy(pass2,p+16,16);
2383 *rparam_len = 4;
2384 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2385 if (!*rparam) {
2386 return False;
2389 *rdata_len = 0;
2391 SSVAL(*rparam,0,NERR_badpass);
2392 SSVAL(*rparam,2,0); /* converter word */
2394 DEBUG(3,("Set password for <%s>\n",user));
2397 * Attempt to verify the old password against smbpasswd entries
2398 * Win98 clients send old and new password in plaintext for this call.
2402 auth_serversupplied_info *server_info = NULL;
2403 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2405 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2407 become_root();
2408 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2409 SSVAL(*rparam,0,NERR_Success);
2411 unbecome_root();
2413 TALLOC_FREE(server_info);
2415 data_blob_clear_free(&password);
2419 * If the plaintext change failed, attempt
2420 * the old encrypted method. NT will generate this
2421 * after trying the samr method. Note that this
2422 * method is done as a last resort as this
2423 * password change method loses the NT password hash
2424 * and cannot change the UNIX password as no plaintext
2425 * is received.
2428 if(SVAL(*rparam,0) != NERR_Success) {
2429 struct samu *hnd = NULL;
2431 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2432 become_root();
2433 if (change_lanman_password(hnd,(uchar *)pass2)) {
2434 SSVAL(*rparam,0,NERR_Success);
2436 unbecome_root();
2437 TALLOC_FREE(hnd);
2441 memset((char *)pass1,'\0',sizeof(fstring));
2442 memset((char *)pass2,'\0',sizeof(fstring));
2444 return(True);
2447 /****************************************************************************
2448 Set the user password (SamOEM version - gets plaintext).
2449 ****************************************************************************/
2451 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2452 char *param, int tpscnt,
2453 char *data, int tdscnt,
2454 int mdrcnt,int mprcnt,
2455 char **rdata,char **rparam,
2456 int *rdata_len,int *rparam_len)
2458 fstring user;
2459 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2460 *rparam_len = 2;
2461 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2462 if (!*rparam) {
2463 return False;
2466 if (!p) {
2467 return False;
2469 *rdata_len = 0;
2471 SSVAL(*rparam,0,NERR_badpass);
2474 * Check the parameter definition is correct.
2477 /* Do we have a string ? */
2478 if (skip_string(param,tpscnt,p) == 0) {
2479 return False;
2481 if(!strequal(p, "zsT")) {
2482 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2483 return False;
2485 p = skip_string(param, tpscnt, p);
2486 if (!p) {
2487 return False;
2490 /* Do we have a string ? */
2491 if (skip_string(param,tpscnt,p) == 0) {
2492 return False;
2494 if(!strequal(p, "B516B16")) {
2495 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2496 return False;
2498 p = skip_string(param,tpscnt,p);
2499 if (!p) {
2500 return False;
2502 /* Do we have a string ? */
2503 if (skip_string(param,tpscnt,p) == 0) {
2504 return False;
2506 p += pull_ascii_fstring(user,p);
2508 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2511 * Pass the user through the NT -> unix user mapping
2512 * function.
2515 (void)map_username(user);
2517 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2518 SSVAL(*rparam,0,NERR_Success);
2521 return(True);
2524 /****************************************************************************
2525 delete a print job
2526 Form: <W> <>
2527 ****************************************************************************/
2529 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2530 char *param, int tpscnt,
2531 char *data, int tdscnt,
2532 int mdrcnt,int mprcnt,
2533 char **rdata,char **rparam,
2534 int *rdata_len,int *rparam_len)
2536 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2537 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2538 char *str2 = skip_string(param,tpscnt,str1);
2539 char *p = skip_string(param,tpscnt,str2);
2540 uint32 jobid;
2541 int snum;
2542 fstring sharename;
2543 int errcode;
2544 WERROR werr = WERR_OK;
2546 if (!str1 || !str2 || !p) {
2547 return False;
2550 * We use 1 here not 2 as we're checking
2551 * the last byte we want to access is safe.
2553 if (!is_offset_safe(param,tpscnt,p,1)) {
2554 return False;
2556 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2557 return False;
2559 /* check it's a supported varient */
2560 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2561 return(False);
2563 *rparam_len = 4;
2564 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2565 if (!*rparam) {
2566 return False;
2568 *rdata_len = 0;
2570 if (!print_job_exists(sharename, jobid)) {
2571 errcode = NERR_JobNotFound;
2572 goto out;
2575 snum = lp_servicenumber( sharename);
2576 if (snum == -1) {
2577 errcode = NERR_DestNotFound;
2578 goto out;
2581 errcode = NERR_notsupported;
2583 switch (function) {
2584 case 81: /* delete */
2585 if (print_job_delete(&current_user, snum, jobid, &werr))
2586 errcode = NERR_Success;
2587 break;
2588 case 82: /* pause */
2589 if (print_job_pause(&current_user, snum, jobid, &werr))
2590 errcode = NERR_Success;
2591 break;
2592 case 83: /* resume */
2593 if (print_job_resume(&current_user, snum, jobid, &werr))
2594 errcode = NERR_Success;
2595 break;
2598 if (!W_ERROR_IS_OK(werr))
2599 errcode = W_ERROR_V(werr);
2601 out:
2602 SSVAL(*rparam,0,errcode);
2603 SSVAL(*rparam,2,0); /* converter word */
2605 return(True);
2608 /****************************************************************************
2609 Purge a print queue - or pause or resume it.
2610 ****************************************************************************/
2612 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2613 char *param, int tpscnt,
2614 char *data, int tdscnt,
2615 int mdrcnt,int mprcnt,
2616 char **rdata,char **rparam,
2617 int *rdata_len,int *rparam_len)
2619 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2620 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2621 char *str2 = skip_string(param,tpscnt,str1);
2622 char *QueueName = skip_string(param,tpscnt,str2);
2623 int errcode = NERR_notsupported;
2624 int snum;
2625 WERROR werr = WERR_OK;
2627 if (!str1 || !str2 || !QueueName) {
2628 return False;
2631 /* check it's a supported varient */
2632 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2633 return(False);
2635 *rparam_len = 4;
2636 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2637 if (!*rparam) {
2638 return False;
2640 *rdata_len = 0;
2642 if (skip_string(param,tpscnt,QueueName) == NULL) {
2643 return False;
2645 snum = print_queue_snum(QueueName);
2647 if (snum == -1) {
2648 errcode = NERR_JobNotFound;
2649 goto out;
2652 switch (function) {
2653 case 74: /* Pause queue */
2654 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2655 break;
2656 case 75: /* Resume queue */
2657 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2658 break;
2659 case 103: /* Purge */
2660 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2661 break;
2664 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2666 out:
2667 SSVAL(*rparam,0,errcode);
2668 SSVAL(*rparam,2,0); /* converter word */
2670 return(True);
2673 /****************************************************************************
2674 set the property of a print job (undocumented?)
2675 ? function = 0xb -> set name of print job
2676 ? function = 0x6 -> move print job up/down
2677 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2678 or <WWsTP> <WB21BB16B10zWWzDDz>
2679 ****************************************************************************/
2681 static int check_printjob_info(struct pack_desc* desc,
2682 int uLevel, char* id)
2684 desc->subformat = NULL;
2685 switch( uLevel ) {
2686 case 0: desc->format = "W"; break;
2687 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2688 case 2: desc->format = "WWzWWDDzz"; break;
2689 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2690 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2691 default:
2692 DEBUG(0,("check_printjob_info: invalid level %d\n",
2693 uLevel ));
2694 return False;
2696 if (id == NULL || strcmp(desc->format,id) != 0) {
2697 DEBUG(0,("check_printjob_info: invalid format %s\n",
2698 id ? id : "<NULL>" ));
2699 return False;
2701 return True;
2704 static BOOL api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2705 char *param, int tpscnt,
2706 char *data, int tdscnt,
2707 int mdrcnt,int mprcnt,
2708 char **rdata,char **rparam,
2709 int *rdata_len,int *rparam_len)
2711 struct pack_desc desc;
2712 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2713 char *str2 = skip_string(param,tpscnt,str1);
2714 char *p = skip_string(param,tpscnt,str2);
2715 uint32 jobid;
2716 fstring sharename;
2717 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2718 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2719 int place, errcode;
2721 if (!str1 || !str2 || !p) {
2722 return False;
2725 * We use 1 here not 2 as we're checking
2726 * the last byte we want to access is safe.
2728 if (!is_offset_safe(param,tpscnt,p,1)) {
2729 return False;
2731 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2732 return False;
2733 *rparam_len = 4;
2734 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2735 if (!*rparam) {
2736 return False;
2739 if (!share_defined(sharename)) {
2740 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2741 sharename));
2742 return False;
2745 *rdata_len = 0;
2747 /* check it's a supported varient */
2748 if ((strcmp(str1,"WWsTP")) ||
2749 (!check_printjob_info(&desc,uLevel,str2)))
2750 return(False);
2752 if (!print_job_exists(sharename, jobid)) {
2753 errcode=NERR_JobNotFound;
2754 goto out;
2757 errcode = NERR_notsupported;
2759 switch (function) {
2760 case 0x6:
2761 /* change job place in the queue,
2762 data gives the new place */
2763 place = SVAL(data,0);
2764 if (print_job_set_place(sharename, jobid, place)) {
2765 errcode=NERR_Success;
2767 break;
2769 case 0xb:
2770 /* change print job name, data gives the name */
2771 if (print_job_set_name(sharename, jobid, data)) {
2772 errcode=NERR_Success;
2774 break;
2776 default:
2777 return False;
2780 out:
2781 SSVALS(*rparam,0,errcode);
2782 SSVAL(*rparam,2,0); /* converter word */
2784 return(True);
2788 /****************************************************************************
2789 Get info about the server.
2790 ****************************************************************************/
2792 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2793 char *param, int tpscnt,
2794 char *data, int tdscnt,
2795 int mdrcnt,int mprcnt,
2796 char **rdata,char **rparam,
2797 int *rdata_len,int *rparam_len)
2799 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2800 char *str2 = skip_string(param,tpscnt,str1);
2801 char *p = skip_string(param,tpscnt,str2);
2802 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2803 char *p2;
2804 int struct_len;
2806 if (!str1 || !str2 || !p) {
2807 return False;
2810 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2812 /* check it's a supported varient */
2813 if (!prefix_ok(str1,"WrLh")) {
2814 return False;
2817 switch( uLevel ) {
2818 case 0:
2819 if (strcmp(str2,"B16") != 0) {
2820 return False;
2822 struct_len = 16;
2823 break;
2824 case 1:
2825 if (strcmp(str2,"B16BBDz") != 0) {
2826 return False;
2828 struct_len = 26;
2829 break;
2830 case 2:
2831 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2832 return False;
2834 struct_len = 134;
2835 break;
2836 case 3:
2837 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2838 return False;
2840 struct_len = 144;
2841 break;
2842 case 20:
2843 if (strcmp(str2,"DN") != 0) {
2844 return False;
2846 struct_len = 6;
2847 break;
2848 case 50:
2849 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2850 return False;
2852 struct_len = 42;
2853 break;
2854 default:
2855 return False;
2858 *rdata_len = mdrcnt;
2859 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2860 if (!*rdata) {
2861 return False;
2864 p = *rdata;
2865 p2 = p + struct_len;
2866 if (uLevel != 20) {
2867 srvstr_push(NULL, p,global_myname(),16,
2868 STR_ASCII|STR_UPPER|STR_TERMINATE);
2870 p += 16;
2871 if (uLevel > 0) {
2872 struct srv_info_struct *servers=NULL;
2873 int i,count;
2874 pstring comment;
2875 uint32 servertype= lp_default_server_announce();
2877 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2879 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2880 for (i=0;i<count;i++) {
2881 if (strequal(servers[i].name,global_myname())) {
2882 servertype = servers[i].type;
2883 push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2888 SAFE_FREE(servers);
2890 SCVAL(p,0,lp_major_announce_version());
2891 SCVAL(p,1,lp_minor_announce_version());
2892 SIVAL(p,2,servertype);
2894 if (mdrcnt == struct_len) {
2895 SIVAL(p,6,0);
2896 } else {
2897 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2898 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2899 conn->connectpath, conn->gid,
2900 get_current_username(),
2901 current_user_info.domain,
2902 comment, sizeof(comment));
2903 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2904 p2 = skip_string(*rdata,*rdata_len,p2);
2905 if (!p2) {
2906 return False;
2911 if (uLevel > 1) {
2912 return False; /* not yet implemented */
2915 *rdata_len = PTR_DIFF(p2,*rdata);
2917 *rparam_len = 6;
2918 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2919 if (!*rparam) {
2920 return False;
2922 SSVAL(*rparam,0,NERR_Success);
2923 SSVAL(*rparam,2,0); /* converter word */
2924 SSVAL(*rparam,4,*rdata_len);
2926 return True;
2929 /****************************************************************************
2930 Get info about the server.
2931 ****************************************************************************/
2933 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
2934 char *param, int tpscnt,
2935 char *data, int tdscnt,
2936 int mdrcnt,int mprcnt,
2937 char **rdata,char **rparam,
2938 int *rdata_len,int *rparam_len)
2940 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2941 char *str2 = skip_string(param,tpscnt,str1);
2942 char *p = skip_string(param,tpscnt,str2);
2943 char *p2;
2944 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
2946 if (!str1 || !str2 || !p) {
2947 return False;
2950 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2952 *rparam_len = 6;
2953 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2954 if (!*rparam) {
2955 return False;
2958 /* check it's a supported varient */
2959 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2960 return False;
2963 *rdata_len = mdrcnt + 1024;
2964 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2965 if (!*rdata) {
2966 return False;
2969 SSVAL(*rparam,0,NERR_Success);
2970 SSVAL(*rparam,2,0); /* converter word */
2972 p = *rdata;
2973 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
2974 if (!p2) {
2975 return False;
2978 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2979 pstrcpy(p2,get_local_machine_name());
2980 strupper_m(p2);
2981 p2 = skip_string(*rdata,*rdata_len,p2);
2982 if (!p2) {
2983 return False;
2985 p += 4;
2987 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2988 pstrcpy(p2,current_user_info.smb_name);
2989 p2 = skip_string(*rdata,*rdata_len,p2);
2990 if (!p2) {
2991 return False;
2993 p += 4;
2995 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2996 pstrcpy(p2,lp_workgroup());
2997 strupper_m(p2);
2998 p2 = skip_string(*rdata,*rdata_len,p2);
2999 if (!p2) {
3000 return False;
3002 p += 4;
3004 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3005 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3006 p += 2;
3008 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3009 pstrcpy(p2,lp_workgroup()); /* don't know. login domain?? */
3010 p2 = skip_string(*rdata,*rdata_len,p2);
3011 if (!p2) {
3012 return False;
3014 p += 4;
3016 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3017 pstrcpy(p2,"");
3018 p2 = skip_string(*rdata,*rdata_len,p2);
3019 if (!p2) {
3020 return False;
3022 p += 4;
3024 *rdata_len = PTR_DIFF(p2,*rdata);
3026 SSVAL(*rparam,4,*rdata_len);
3028 return True;
3031 /****************************************************************************
3032 get info about a user
3034 struct user_info_11 {
3035 char usri11_name[21]; 0-20
3036 char usri11_pad; 21
3037 char *usri11_comment; 22-25
3038 char *usri11_usr_comment; 26-29
3039 unsigned short usri11_priv; 30-31
3040 unsigned long usri11_auth_flags; 32-35
3041 long usri11_password_age; 36-39
3042 char *usri11_homedir; 40-43
3043 char *usri11_parms; 44-47
3044 long usri11_last_logon; 48-51
3045 long usri11_last_logoff; 52-55
3046 unsigned short usri11_bad_pw_count; 56-57
3047 unsigned short usri11_num_logons; 58-59
3048 char *usri11_logon_server; 60-63
3049 unsigned short usri11_country_code; 64-65
3050 char *usri11_workstations; 66-69
3051 unsigned long usri11_max_storage; 70-73
3052 unsigned short usri11_units_per_week; 74-75
3053 unsigned char *usri11_logon_hours; 76-79
3054 unsigned short usri11_code_page; 80-81
3057 where:
3059 usri11_name specifies the user name for which information is retireved
3061 usri11_pad aligns the next data structure element to a word boundary
3063 usri11_comment is a null terminated ASCII comment
3065 usri11_user_comment is a null terminated ASCII comment about the user
3067 usri11_priv specifies the level of the privilege assigned to the user.
3068 The possible values are:
3070 Name Value Description
3071 USER_PRIV_GUEST 0 Guest privilege
3072 USER_PRIV_USER 1 User privilege
3073 USER_PRV_ADMIN 2 Administrator privilege
3075 usri11_auth_flags specifies the account operator privileges. The
3076 possible values are:
3078 Name Value Description
3079 AF_OP_PRINT 0 Print operator
3082 Leach, Naik [Page 28]
3086 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3089 AF_OP_COMM 1 Communications operator
3090 AF_OP_SERVER 2 Server operator
3091 AF_OP_ACCOUNTS 3 Accounts operator
3094 usri11_password_age specifies how many seconds have elapsed since the
3095 password was last changed.
3097 usri11_home_dir points to a null terminated ASCII string that contains
3098 the path name of the user's home directory.
3100 usri11_parms points to a null terminated ASCII string that is set
3101 aside for use by applications.
3103 usri11_last_logon specifies the time when the user last logged on.
3104 This value is stored as the number of seconds elapsed since
3105 00:00:00, January 1, 1970.
3107 usri11_last_logoff specifies the time when the user last logged off.
3108 This value is stored as the number of seconds elapsed since
3109 00:00:00, January 1, 1970. A value of 0 means the last logoff
3110 time is unknown.
3112 usri11_bad_pw_count specifies the number of incorrect passwords
3113 entered since the last successful logon.
3115 usri11_log1_num_logons specifies the number of times this user has
3116 logged on. A value of -1 means the number of logons is unknown.
3118 usri11_logon_server points to a null terminated ASCII string that
3119 contains the name of the server to which logon requests are sent.
3120 A null string indicates logon requests should be sent to the
3121 domain controller.
3123 usri11_country_code specifies the country code for the user's language
3124 of choice.
3126 usri11_workstations points to a null terminated ASCII string that
3127 contains the names of workstations the user may log on from.
3128 There may be up to 8 workstations, with the names separated by
3129 commas. A null strings indicates there are no restrictions.
3131 usri11_max_storage specifies the maximum amount of disk space the user
3132 can occupy. A value of 0xffffffff indicates there are no
3133 restrictions.
3135 usri11_units_per_week specifies the equal number of time units into
3136 which a week is divided. This value must be equal to 168.
3138 usri11_logon_hours points to a 21 byte (168 bits) string that
3139 specifies the time during which the user can log on. Each bit
3140 represents one unique hour in a week. The first bit (bit 0, word
3141 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3145 Leach, Naik [Page 29]
3149 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3152 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3153 are no restrictions.
3155 usri11_code_page specifies the code page for the user's language of
3156 choice
3158 All of the pointers in this data structure need to be treated
3159 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3160 to be ignored. The converter word returned in the parameters section
3161 needs to be subtracted from the lower 16 bits to calculate an offset
3162 into the return buffer where this ASCII string resides.
3164 There is no auxiliary data in the response.
3166 ****************************************************************************/
3168 #define usri11_name 0
3169 #define usri11_pad 21
3170 #define usri11_comment 22
3171 #define usri11_usr_comment 26
3172 #define usri11_full_name 30
3173 #define usri11_priv 34
3174 #define usri11_auth_flags 36
3175 #define usri11_password_age 40
3176 #define usri11_homedir 44
3177 #define usri11_parms 48
3178 #define usri11_last_logon 52
3179 #define usri11_last_logoff 56
3180 #define usri11_bad_pw_count 60
3181 #define usri11_num_logons 62
3182 #define usri11_logon_server 64
3183 #define usri11_country_code 68
3184 #define usri11_workstations 70
3185 #define usri11_max_storage 74
3186 #define usri11_units_per_week 78
3187 #define usri11_logon_hours 80
3188 #define usri11_code_page 84
3189 #define usri11_end 86
3191 #define USER_PRIV_GUEST 0
3192 #define USER_PRIV_USER 1
3193 #define USER_PRIV_ADMIN 2
3195 #define AF_OP_PRINT 0
3196 #define AF_OP_COMM 1
3197 #define AF_OP_SERVER 2
3198 #define AF_OP_ACCOUNTS 3
3201 static BOOL api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3202 char *param, int tpscnt,
3203 char *data, int tdscnt,
3204 int mdrcnt,int mprcnt,
3205 char **rdata,char **rparam,
3206 int *rdata_len,int *rparam_len)
3208 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3209 char *str2 = skip_string(param,tpscnt,str1);
3210 char *UserName = skip_string(param,tpscnt,str2);
3211 char *p = skip_string(param,tpscnt,UserName);
3212 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3213 char *p2;
3214 const char *level_string;
3216 /* get NIS home of a previously validated user - simeon */
3217 /* With share level security vuid will always be zero.
3218 Don't depend on vuser being non-null !!. JRA */
3219 user_struct *vuser = get_valid_user_struct(vuid);
3220 if(vuser != NULL) {
3221 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3222 vuser->user.unix_name));
3225 if (!str1 || !str2 || !UserName || !p) {
3226 return False;
3229 *rparam_len = 6;
3230 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3231 if (!*rparam) {
3232 return False;
3235 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3237 /* check it's a supported variant */
3238 if (strcmp(str1,"zWrLh") != 0) {
3239 return False;
3241 switch( uLevel ) {
3242 case 0: level_string = "B21"; break;
3243 case 1: level_string = "B21BB16DWzzWz"; break;
3244 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3245 case 10: level_string = "B21Bzzz"; break;
3246 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3247 default: return False;
3250 if (strcmp(level_string,str2) != 0) {
3251 return False;
3254 *rdata_len = mdrcnt + 1024;
3255 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
3256 if (!*rdata) {
3257 return False;
3260 SSVAL(*rparam,0,NERR_Success);
3261 SSVAL(*rparam,2,0); /* converter word */
3263 p = *rdata;
3264 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3265 if (!p2) {
3266 return False;
3269 memset(p,0,21);
3270 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3272 if (uLevel > 0) {
3273 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3274 *p2 = 0;
3277 if (uLevel >= 10) {
3278 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3279 pstrcpy(p2,"Comment");
3280 p2 = skip_string(*rdata,*rdata_len,p2);
3281 if (!p2) {
3282 return False;
3285 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3286 pstrcpy(p2,"UserComment");
3287 p2 = skip_string(*rdata,*rdata_len,p2);
3288 if (!p2) {
3289 return False;
3292 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3293 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3294 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3295 p2 = skip_string(*rdata,*rdata_len,p2);
3296 if (!p2) {
3297 return False;
3301 if (uLevel == 11) {
3302 /* modelled after NTAS 3.51 reply */
3303 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3304 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3305 SIVALS(p,usri11_password_age,-1); /* password age */
3306 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3307 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3308 p2 = skip_string(*rdata,*rdata_len,p2);
3309 if (!p2) {
3310 return False;
3312 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3313 pstrcpy(p2,"");
3314 p2 = skip_string(*rdata,*rdata_len,p2);
3315 if (!p2) {
3316 return False;
3318 SIVAL(p,usri11_last_logon,0); /* last logon */
3319 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3320 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3321 SSVALS(p,usri11_num_logons,-1); /* num logons */
3322 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3323 pstrcpy(p2,"\\\\*");
3324 p2 = skip_string(*rdata,*rdata_len,p2);
3325 if (!p2) {
3326 return False;
3328 SSVAL(p,usri11_country_code,0); /* country code */
3330 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3331 pstrcpy(p2,"");
3332 p2 = skip_string(*rdata,*rdata_len,p2);
3333 if (!p2) {
3334 return False;
3337 SIVALS(p,usri11_max_storage,-1); /* max storage */
3338 SSVAL(p,usri11_units_per_week,168); /* units per week */
3339 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3341 /* a simple way to get logon hours at all times. */
3342 memset(p2,0xff,21);
3343 SCVAL(p2,21,0); /* fix zero termination */
3344 p2 = skip_string(*rdata,*rdata_len,p2);
3345 if (!p2) {
3346 return False;
3349 SSVAL(p,usri11_code_page,0); /* code page */
3352 if (uLevel == 1 || uLevel == 2) {
3353 memset(p+22,' ',16); /* password */
3354 SIVALS(p,38,-1); /* password age */
3355 SSVAL(p,42,
3356 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3357 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3358 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3359 p2 = skip_string(*rdata,*rdata_len,p2);
3360 if (!p2) {
3361 return False;
3363 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3364 *p2++ = 0;
3365 SSVAL(p,52,0); /* flags */
3366 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3367 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3368 p2 = skip_string(*rdata,*rdata_len,p2);
3369 if (!p2) {
3370 return False;
3372 if (uLevel == 2) {
3373 SIVAL(p,60,0); /* auth_flags */
3374 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3375 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3376 p2 = skip_string(*rdata,*rdata_len,p2);
3377 if (!p2) {
3378 return False;
3380 SIVAL(p,68,0); /* urs_comment */
3381 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3382 pstrcpy(p2,"");
3383 p2 = skip_string(*rdata,*rdata_len,p2);
3384 if (!p2) {
3385 return False;
3387 SIVAL(p,76,0); /* workstations */
3388 SIVAL(p,80,0); /* last_logon */
3389 SIVAL(p,84,0); /* last_logoff */
3390 SIVALS(p,88,-1); /* acct_expires */
3391 SIVALS(p,92,-1); /* max_storage */
3392 SSVAL(p,96,168); /* units_per_week */
3393 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3394 memset(p2,-1,21);
3395 p2 += 21;
3396 SSVALS(p,102,-1); /* bad_pw_count */
3397 SSVALS(p,104,-1); /* num_logons */
3398 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3400 pstring tmp;
3401 pstrcpy(tmp, "\\\\%L");
3402 standard_sub_basic("", "", tmp, sizeof(tmp));
3403 pstrcpy(p2, tmp);
3405 p2 = skip_string(*rdata,*rdata_len,p2);
3406 if (!p2) {
3407 return False;
3409 SSVAL(p,110,49); /* country_code */
3410 SSVAL(p,112,860); /* code page */
3414 *rdata_len = PTR_DIFF(p2,*rdata);
3416 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3418 return(True);
3421 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3422 char *param, int tpscnt,
3423 char *data, int tdscnt,
3424 int mdrcnt,int mprcnt,
3425 char **rdata,char **rparam,
3426 int *rdata_len,int *rparam_len)
3428 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3429 char *str2 = skip_string(param,tpscnt,str1);
3430 char *p = skip_string(param,tpscnt,str2);
3431 int uLevel;
3432 struct pack_desc desc;
3433 char* name;
3434 /* With share level security vuid will always be zero.
3435 Don't depend on vuser being non-null !!. JRA */
3436 user_struct *vuser = get_valid_user_struct(vuid);
3438 if (!str1 || !str2 || !p) {
3439 return False;
3442 if(vuser != NULL) {
3443 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3444 vuser->user.unix_name));
3447 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3448 name = get_safe_str_ptr(param,tpscnt,p,2);
3449 if (!name) {
3450 return False;
3453 memset((char *)&desc,'\0',sizeof(desc));
3455 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3457 /* check it's a supported varient */
3458 if (strcmp(str1,"OOWb54WrLh") != 0) {
3459 return False;
3461 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3462 return False;
3464 if (mdrcnt > 0) {
3465 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3466 if (!*rdata) {
3467 return False;
3471 desc.base = *rdata;
3472 desc.buflen = mdrcnt;
3473 desc.subformat = NULL;
3474 desc.format = str2;
3476 if (init_package(&desc,1,0)) {
3477 PACKI(&desc,"W",0); /* code */
3478 PACKS(&desc,"B21",name); /* eff. name */
3479 PACKS(&desc,"B",""); /* pad */
3480 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3481 PACKI(&desc,"D",0); /* auth flags XXX */
3482 PACKI(&desc,"W",0); /* num logons */
3483 PACKI(&desc,"W",0); /* bad pw count */
3484 PACKI(&desc,"D",0); /* last logon */
3485 PACKI(&desc,"D",-1); /* last logoff */
3486 PACKI(&desc,"D",-1); /* logoff time */
3487 PACKI(&desc,"D",-1); /* kickoff time */
3488 PACKI(&desc,"D",0); /* password age */
3489 PACKI(&desc,"D",0); /* password can change */
3490 PACKI(&desc,"D",-1); /* password must change */
3493 fstring mypath;
3494 fstrcpy(mypath,"\\\\");
3495 fstrcat(mypath,get_local_machine_name());
3496 strupper_m(mypath);
3497 PACKS(&desc,"z",mypath); /* computer */
3500 PACKS(&desc,"z",lp_workgroup());/* domain */
3501 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3502 PACKI(&desc,"D",0x00000000); /* reserved */
3505 *rdata_len = desc.usedlen;
3506 *rparam_len = 6;
3507 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3508 if (!*rparam) {
3509 return False;
3511 SSVALS(*rparam,0,desc.errcode);
3512 SSVAL(*rparam,2,0);
3513 SSVAL(*rparam,4,desc.neededlen);
3515 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3517 return True;
3520 /****************************************************************************
3521 api_WAccessGetUserPerms
3522 ****************************************************************************/
3524 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3525 char *param, int tpscnt,
3526 char *data, int tdscnt,
3527 int mdrcnt,int mprcnt,
3528 char **rdata,char **rparam,
3529 int *rdata_len,int *rparam_len)
3531 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3532 char *str2 = skip_string(param,tpscnt,str1);
3533 char *user = skip_string(param,tpscnt,str2);
3534 char *resource = skip_string(param,tpscnt,user);
3536 if (!str1 || !str2 || !user || !resource) {
3537 return False;
3540 if (skip_string(param,tpscnt,resource) == NULL) {
3541 return False;
3543 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3545 /* check it's a supported varient */
3546 if (strcmp(str1,"zzh") != 0) {
3547 return False;
3549 if (strcmp(str2,"") != 0) {
3550 return False;
3553 *rparam_len = 6;
3554 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3555 if (!*rparam) {
3556 return False;
3558 SSVALS(*rparam,0,0); /* errorcode */
3559 SSVAL(*rparam,2,0); /* converter word */
3560 SSVAL(*rparam,4,0x7f); /* permission flags */
3562 return True;
3565 /****************************************************************************
3566 api_WPrintJobEnumerate
3567 ****************************************************************************/
3569 static BOOL api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3570 char *param, int tpscnt,
3571 char *data, int tdscnt,
3572 int mdrcnt,int mprcnt,
3573 char **rdata,char **rparam,
3574 int *rdata_len,int *rparam_len)
3576 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3577 char *str2 = skip_string(param,tpscnt,str1);
3578 char *p = skip_string(param,tpscnt,str2);
3579 int uLevel;
3580 int count;
3581 int i;
3582 int snum;
3583 fstring sharename;
3584 uint32 jobid;
3585 struct pack_desc desc;
3586 print_queue_struct *queue=NULL;
3587 print_status_struct status;
3588 char *tmpdata=NULL;
3590 if (!str1 || !str2 || !p) {
3591 return False;
3594 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3596 memset((char *)&desc,'\0',sizeof(desc));
3597 memset((char *)&status,'\0',sizeof(status));
3599 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3601 /* check it's a supported varient */
3602 if (strcmp(str1,"WWrLh") != 0) {
3603 return False;
3605 if (!check_printjob_info(&desc,uLevel,str2)) {
3606 return False;
3609 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3610 return False;
3613 snum = lp_servicenumber( sharename);
3614 if (snum < 0 || !VALID_SNUM(snum)) {
3615 return(False);
3618 count = print_queue_status(snum,&queue,&status);
3619 for (i = 0; i < count; i++) {
3620 if (queue[i].job == jobid) {
3621 break;
3625 if (mdrcnt > 0) {
3626 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3627 if (!*rdata) {
3628 return False;
3630 desc.base = *rdata;
3631 desc.buflen = mdrcnt;
3632 } else {
3634 * Don't return data but need to get correct length
3635 * init_package will return wrong size if buflen=0
3637 desc.buflen = getlen(desc.format);
3638 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3641 if (init_package(&desc,1,0)) {
3642 if (i < count) {
3643 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3644 *rdata_len = desc.usedlen;
3645 } else {
3646 desc.errcode = NERR_JobNotFound;
3647 *rdata_len = 0;
3651 *rparam_len = 6;
3652 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3653 if (!*rparam) {
3654 return False;
3656 SSVALS(*rparam,0,desc.errcode);
3657 SSVAL(*rparam,2,0);
3658 SSVAL(*rparam,4,desc.neededlen);
3660 SAFE_FREE(queue);
3661 SAFE_FREE(tmpdata);
3663 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3665 return True;
3668 static BOOL api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3669 char *param, int tpscnt,
3670 char *data, int tdscnt,
3671 int mdrcnt,int mprcnt,
3672 char **rdata,char **rparam,
3673 int *rdata_len,int *rparam_len)
3675 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3676 char *str2 = skip_string(param,tpscnt,str1);
3677 char *p = skip_string(param,tpscnt,str2);
3678 char *name = p;
3679 int uLevel;
3680 int count;
3681 int i, succnt=0;
3682 int snum;
3683 struct pack_desc desc;
3684 print_queue_struct *queue=NULL;
3685 print_status_struct status;
3687 if (!str1 || !str2 || !p) {
3688 return False;
3691 memset((char *)&desc,'\0',sizeof(desc));
3692 memset((char *)&status,'\0',sizeof(status));
3694 p = skip_string(param,tpscnt,p);
3695 if (!p) {
3696 return False;
3698 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3700 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3702 /* check it's a supported variant */
3703 if (strcmp(str1,"zWrLeh") != 0) {
3704 return False;
3707 if (uLevel > 2) {
3708 return False; /* defined only for uLevel 0,1,2 */
3711 if (!check_printjob_info(&desc,uLevel,str2)) {
3712 return False;
3715 snum = find_service(name);
3716 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3717 return False;
3720 count = print_queue_status(snum,&queue,&status);
3721 if (mdrcnt > 0) {
3722 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3723 if (!*rdata) {
3724 return False;
3727 desc.base = *rdata;
3728 desc.buflen = mdrcnt;
3730 if (init_package(&desc,count,0)) {
3731 succnt = 0;
3732 for (i = 0; i < count; i++) {
3733 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3734 if (desc.errcode == NERR_Success) {
3735 succnt = i+1;
3740 *rdata_len = desc.usedlen;
3742 *rparam_len = 8;
3743 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3744 if (!*rparam) {
3745 return False;
3747 SSVALS(*rparam,0,desc.errcode);
3748 SSVAL(*rparam,2,0);
3749 SSVAL(*rparam,4,succnt);
3750 SSVAL(*rparam,6,count);
3752 SAFE_FREE(queue);
3754 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3756 return True;
3759 static int check_printdest_info(struct pack_desc* desc,
3760 int uLevel, char* id)
3762 desc->subformat = NULL;
3763 switch( uLevel ) {
3764 case 0:
3765 desc->format = "B9";
3766 break;
3767 case 1:
3768 desc->format = "B9B21WWzW";
3769 break;
3770 case 2:
3771 desc->format = "z";
3772 break;
3773 case 3:
3774 desc->format = "zzzWWzzzWW";
3775 break;
3776 default:
3777 DEBUG(0,("check_printdest_info: invalid level %d\n",
3778 uLevel));
3779 return False;
3781 if (id == NULL || strcmp(desc->format,id) != 0) {
3782 DEBUG(0,("check_printdest_info: invalid string %s\n",
3783 id ? id : "<NULL>" ));
3784 return False;
3786 return True;
3789 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3790 struct pack_desc* desc)
3792 char buf[100];
3794 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3795 buf[sizeof(buf)-1] = 0;
3796 strupper_m(buf);
3798 if (uLevel <= 1) {
3799 PACKS(desc,"B9",buf); /* szName */
3800 if (uLevel == 1) {
3801 PACKS(desc,"B21",""); /* szUserName */
3802 PACKI(desc,"W",0); /* uJobId */
3803 PACKI(desc,"W",0); /* fsStatus */
3804 PACKS(desc,"z",""); /* pszStatus */
3805 PACKI(desc,"W",0); /* time */
3809 if (uLevel == 2 || uLevel == 3) {
3810 PACKS(desc,"z",buf); /* pszPrinterName */
3811 if (uLevel == 3) {
3812 PACKS(desc,"z",""); /* pszUserName */
3813 PACKS(desc,"z",""); /* pszLogAddr */
3814 PACKI(desc,"W",0); /* uJobId */
3815 PACKI(desc,"W",0); /* fsStatus */
3816 PACKS(desc,"z",""); /* pszStatus */
3817 PACKS(desc,"z",""); /* pszComment */
3818 PACKS(desc,"z","NULL"); /* pszDrivers */
3819 PACKI(desc,"W",0); /* time */
3820 PACKI(desc,"W",0); /* pad1 */
3825 static BOOL api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3826 char *param, int tpscnt,
3827 char *data, int tdscnt,
3828 int mdrcnt,int mprcnt,
3829 char **rdata,char **rparam,
3830 int *rdata_len,int *rparam_len)
3832 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3833 char *str2 = skip_string(param,tpscnt,str1);
3834 char *p = skip_string(param,tpscnt,str2);
3835 char* PrinterName = p;
3836 int uLevel;
3837 struct pack_desc desc;
3838 int snum;
3839 char *tmpdata=NULL;
3841 if (!str1 || !str2 || !p) {
3842 return False;
3845 memset((char *)&desc,'\0',sizeof(desc));
3847 p = skip_string(param,tpscnt,p);
3848 if (!p) {
3849 return False;
3851 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3853 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3855 /* check it's a supported varient */
3856 if (strcmp(str1,"zWrLh") != 0) {
3857 return False;
3859 if (!check_printdest_info(&desc,uLevel,str2)) {
3860 return False;
3863 snum = find_service(PrinterName);
3864 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3865 *rdata_len = 0;
3866 desc.errcode = NERR_DestNotFound;
3867 desc.neededlen = 0;
3868 } else {
3869 if (mdrcnt > 0) {
3870 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3871 if (!*rdata) {
3872 return False;
3874 desc.base = *rdata;
3875 desc.buflen = mdrcnt;
3876 } else {
3878 * Don't return data but need to get correct length
3879 * init_package will return wrong size if buflen=0
3881 desc.buflen = getlen(desc.format);
3882 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3884 if (init_package(&desc,1,0)) {
3885 fill_printdest_info(conn,snum,uLevel,&desc);
3887 *rdata_len = desc.usedlen;
3890 *rparam_len = 6;
3891 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3892 if (!*rparam) {
3893 return False;
3895 SSVALS(*rparam,0,desc.errcode);
3896 SSVAL(*rparam,2,0);
3897 SSVAL(*rparam,4,desc.neededlen);
3899 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3900 SAFE_FREE(tmpdata);
3902 return True;
3905 static BOOL api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
3906 char *param, int tpscnt,
3907 char *data, int tdscnt,
3908 int mdrcnt,int mprcnt,
3909 char **rdata,char **rparam,
3910 int *rdata_len,int *rparam_len)
3912 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3913 char *str2 = skip_string(param,tpscnt,str1);
3914 char *p = skip_string(param,tpscnt,str2);
3915 int uLevel;
3916 int queuecnt;
3917 int i, n, succnt=0;
3918 struct pack_desc desc;
3919 int services = lp_numservices();
3921 if (!str1 || !str2 || !p) {
3922 return False;
3925 memset((char *)&desc,'\0',sizeof(desc));
3927 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3929 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3931 /* check it's a supported varient */
3932 if (strcmp(str1,"WrLeh") != 0) {
3933 return False;
3935 if (!check_printdest_info(&desc,uLevel,str2)) {
3936 return False;
3939 queuecnt = 0;
3940 for (i = 0; i < services; i++) {
3941 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3942 queuecnt++;
3946 if (mdrcnt > 0) {
3947 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3948 if (!*rdata) {
3949 return False;
3953 desc.base = *rdata;
3954 desc.buflen = mdrcnt;
3955 if (init_package(&desc,queuecnt,0)) {
3956 succnt = 0;
3957 n = 0;
3958 for (i = 0; i < services; i++) {
3959 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3960 fill_printdest_info(conn,i,uLevel,&desc);
3961 n++;
3962 if (desc.errcode == NERR_Success) {
3963 succnt = n;
3969 *rdata_len = desc.usedlen;
3971 *rparam_len = 8;
3972 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3973 if (!*rparam) {
3974 return False;
3976 SSVALS(*rparam,0,desc.errcode);
3977 SSVAL(*rparam,2,0);
3978 SSVAL(*rparam,4,succnt);
3979 SSVAL(*rparam,6,queuecnt);
3981 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3983 return True;
3986 static BOOL api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
3987 char *param, int tpscnt,
3988 char *data, int tdscnt,
3989 int mdrcnt,int mprcnt,
3990 char **rdata,char **rparam,
3991 int *rdata_len,int *rparam_len)
3993 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3994 char *str2 = skip_string(param,tpscnt,str1);
3995 char *p = skip_string(param,tpscnt,str2);
3996 int uLevel;
3997 int succnt;
3998 struct pack_desc desc;
4000 if (!str1 || !str2 || !p) {
4001 return False;
4004 memset((char *)&desc,'\0',sizeof(desc));
4006 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4008 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4010 /* check it's a supported varient */
4011 if (strcmp(str1,"WrLeh") != 0) {
4012 return False;
4014 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4015 return False;
4018 if (mdrcnt > 0) {
4019 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4020 if (!*rdata) {
4021 return False;
4024 desc.base = *rdata;
4025 desc.buflen = mdrcnt;
4026 if (init_package(&desc,1,0)) {
4027 PACKS(&desc,"B41","NULL");
4030 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4032 *rdata_len = desc.usedlen;
4034 *rparam_len = 8;
4035 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4036 if (!*rparam) {
4037 return False;
4039 SSVALS(*rparam,0,desc.errcode);
4040 SSVAL(*rparam,2,0);
4041 SSVAL(*rparam,4,succnt);
4042 SSVAL(*rparam,6,1);
4044 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4046 return True;
4049 static BOOL api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4050 char *param, int tpscnt,
4051 char *data, int tdscnt,
4052 int mdrcnt,int mprcnt,
4053 char **rdata,char **rparam,
4054 int *rdata_len,int *rparam_len)
4056 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4057 char *str2 = skip_string(param,tpscnt,str1);
4058 char *p = skip_string(param,tpscnt,str2);
4059 int uLevel;
4060 int succnt;
4061 struct pack_desc desc;
4063 if (!str1 || !str2 || !p) {
4064 return False;
4066 memset((char *)&desc,'\0',sizeof(desc));
4068 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4070 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4072 /* check it's a supported varient */
4073 if (strcmp(str1,"WrLeh") != 0) {
4074 return False;
4076 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4077 return False;
4080 if (mdrcnt > 0) {
4081 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4082 if (!*rdata) {
4083 return False;
4086 desc.base = *rdata;
4087 desc.buflen = mdrcnt;
4088 desc.format = str2;
4089 if (init_package(&desc,1,0)) {
4090 PACKS(&desc,"B13","lpd");
4093 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4095 *rdata_len = desc.usedlen;
4097 *rparam_len = 8;
4098 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4099 if (!*rparam) {
4100 return False;
4102 SSVALS(*rparam,0,desc.errcode);
4103 SSVAL(*rparam,2,0);
4104 SSVAL(*rparam,4,succnt);
4105 SSVAL(*rparam,6,1);
4107 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4109 return True;
4112 static BOOL api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4113 char *param, int tpscnt,
4114 char *data, int tdscnt,
4115 int mdrcnt,int mprcnt,
4116 char **rdata,char **rparam,
4117 int *rdata_len,int *rparam_len)
4119 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4120 char *str2 = skip_string(param,tpscnt,str1);
4121 char *p = skip_string(param,tpscnt,str2);
4122 int uLevel;
4123 int succnt;
4124 struct pack_desc desc;
4126 if (!str1 || !str2 || !p) {
4127 return False;
4130 memset((char *)&desc,'\0',sizeof(desc));
4132 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4134 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4136 /* check it's a supported varient */
4137 if (strcmp(str1,"WrLeh") != 0) {
4138 return False;
4140 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4141 return False;
4144 if (mdrcnt > 0) {
4145 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4146 if (!*rdata) {
4147 return False;
4150 memset((char *)&desc,'\0',sizeof(desc));
4151 desc.base = *rdata;
4152 desc.buflen = mdrcnt;
4153 desc.format = str2;
4154 if (init_package(&desc,1,0)) {
4155 PACKS(&desc,"B13","lp0");
4158 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4160 *rdata_len = desc.usedlen;
4162 *rparam_len = 8;
4163 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4164 if (!*rparam) {
4165 return False;
4167 SSVALS(*rparam,0,desc.errcode);
4168 SSVAL(*rparam,2,0);
4169 SSVAL(*rparam,4,succnt);
4170 SSVAL(*rparam,6,1);
4172 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4174 return True;
4177 /****************************************************************************
4178 List open sessions
4179 ****************************************************************************/
4181 static BOOL api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4182 char *param, int tpscnt,
4183 char *data, int tdscnt,
4184 int mdrcnt,int mprcnt,
4185 char **rdata,char **rparam,
4186 int *rdata_len,int *rparam_len)
4189 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4190 char *str2 = skip_string(param,tpscnt,str1);
4191 char *p = skip_string(param,tpscnt,str2);
4192 int uLevel;
4193 struct pack_desc desc;
4194 struct sessionid *session_list;
4195 int i, num_sessions;
4197 if (!str1 || !str2 || !p) {
4198 return False;
4201 memset((char *)&desc,'\0',sizeof(desc));
4203 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4205 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4206 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4207 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4209 /* check it's a supported varient */
4210 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4211 return False;
4213 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4214 return False;
4217 num_sessions = list_sessions(tmp_talloc_ctx(), &session_list);
4219 if (mdrcnt > 0) {
4220 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4221 if (!*rdata) {
4222 return False;
4225 memset((char *)&desc,'\0',sizeof(desc));
4226 desc.base = *rdata;
4227 desc.buflen = mdrcnt;
4228 desc.format = str2;
4229 if (!init_package(&desc,num_sessions,0)) {
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 return False;
4252 SSVALS(*rparam,0,desc.errcode);
4253 SSVAL(*rparam,2,0); /* converter */
4254 SSVAL(*rparam,4,num_sessions); /* count */
4256 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4258 return True;
4262 /****************************************************************************
4263 The buffer was too small.
4264 ****************************************************************************/
4266 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4267 int mdrcnt, int mprcnt,
4268 char **rdata, char **rparam,
4269 int *rdata_len, int *rparam_len)
4271 *rparam_len = MIN(*rparam_len,mprcnt);
4272 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4273 if (!*rparam) {
4274 return False;
4277 *rdata_len = 0;
4279 SSVAL(*rparam,0,NERR_BufTooSmall);
4281 DEBUG(3,("Supplied buffer too small in API command\n"));
4283 return True;
4286 /****************************************************************************
4287 The request is not supported.
4288 ****************************************************************************/
4290 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
4291 char *param, int tpscnt,
4292 char *data, int tdscnt,
4293 int mdrcnt, int mprcnt,
4294 char **rdata, char **rparam,
4295 int *rdata_len, int *rparam_len)
4297 *rparam_len = 4;
4298 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4299 if (!*rparam) {
4300 return False;
4303 *rdata_len = 0;
4305 SSVAL(*rparam,0,NERR_notsupported);
4306 SSVAL(*rparam,2,0); /* converter word */
4308 DEBUG(3,("Unsupported API command\n"));
4310 return True;
4313 static const struct {
4314 const char *name;
4315 int id;
4316 BOOL (*fn)(connection_struct *, uint16,
4317 char *, int,
4318 char *, int,
4319 int,int,char **,char **,int *,int *);
4320 BOOL auth_user; /* Deny anonymous access? */
4321 } api_commands[] = {
4322 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4323 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4324 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4325 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4326 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4327 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4328 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4329 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4330 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4331 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4332 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4333 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4334 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4335 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4336 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4337 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4338 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4339 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4340 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4341 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4342 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4343 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4344 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4345 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4346 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4347 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4348 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4349 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4350 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4351 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4352 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4353 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4354 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4355 {NULL, -1, api_Unsupported}
4356 /* The following RAP calls are not implemented by Samba:
4358 RAP_WFileEnum2 - anon not OK
4363 /****************************************************************************
4364 Handle remote api calls.
4365 ****************************************************************************/
4367 int api_reply(connection_struct *conn,
4368 uint16 vuid,
4369 const char *inbuf,
4370 char *outbuf,
4371 char *data,
4372 char *params,
4373 int tdscnt,
4374 int tpscnt,
4375 int mdrcnt,
4376 int mprcnt)
4378 int api_command;
4379 char *rdata = NULL;
4380 char *rparam = NULL;
4381 const char *name1 = NULL;
4382 const char *name2 = NULL;
4383 int rdata_len = 0;
4384 int rparam_len = 0;
4385 BOOL reply=False;
4386 int i;
4388 if (!params) {
4389 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4390 return 0;
4393 if (tpscnt < 2) {
4394 return 0;
4396 api_command = SVAL(params,0);
4397 /* Is there a string at position params+2 ? */
4398 if (skip_string(params,tpscnt,params+2)) {
4399 name1 = params + 2;
4400 } else {
4401 name1 = "";
4403 name2 = skip_string(params,tpscnt,params+2);
4404 if (!name2) {
4405 name2 = "";
4408 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4409 api_command,
4410 name1,
4411 name2,
4412 tdscnt,tpscnt,mdrcnt,mprcnt));
4414 for (i=0;api_commands[i].name;i++) {
4415 if (api_commands[i].id == api_command && api_commands[i].fn) {
4416 DEBUG(3,("Doing %s\n",api_commands[i].name));
4417 break;
4421 /* Check whether this api call can be done anonymously */
4423 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4424 user_struct *user = get_valid_user_struct(vuid);
4426 if (!user || user->guest) {
4427 return ERROR_NT(NT_STATUS_ACCESS_DENIED);
4431 rdata = (char *)SMB_MALLOC(1024);
4432 if (rdata) {
4433 memset(rdata,'\0',1024);
4436 rparam = (char *)SMB_MALLOC(1024);
4437 if (rparam) {
4438 memset(rparam,'\0',1024);
4441 if(!rdata || !rparam) {
4442 DEBUG(0,("api_reply: malloc fail !\n"));
4443 SAFE_FREE(rdata);
4444 SAFE_FREE(rparam);
4445 return -1;
4448 reply = api_commands[i].fn(conn,
4449 vuid,
4450 params,tpscnt, /* params + length */
4451 data,tdscnt, /* data + length */
4452 mdrcnt,mprcnt,
4453 &rdata,&rparam,&rdata_len,&rparam_len);
4456 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4457 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4458 &rdata,&rparam,&rdata_len,&rparam_len);
4461 /* if we get False back then it's actually unsupported */
4462 if (!reply) {
4463 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4464 &rdata,&rparam,&rdata_len,&rparam_len);
4467 /* If api_Unsupported returns false we can't return anything. */
4468 if (reply) {
4469 send_trans_reply(inbuf,
4470 outbuf,
4471 rparam,
4472 rparam_len,
4473 rdata,
4474 rdata_len,
4475 False);
4478 SAFE_FREE(rdata);
4479 SAFE_FREE(rparam);
4480 return -1;