Mark some targets phony
[Samba.git] / source / smbd / lanman.c
blobabdd4e9a72dda275458f984b131e9c1115da69b5
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 if (l == -1) {
86 return 0;
88 (*dst) += l;
89 (*n) -= l;
90 return l;
93 static int CopyAndAdvance(char **dst, char *src, int *n)
95 int l;
96 if (!src || !dst || !n || !(*dst)) {
97 return 0;
99 l = push_ascii(*dst,src,*n, STR_TERMINATE);
100 if (l == -1) {
101 return 0;
103 (*dst) += l;
104 (*n) -= l;
105 return l;
108 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
110 pstring buf;
111 if (!s) {
112 return 0;
114 StrnCpy(buf,s,sizeof(buf)/2);
115 pstring_sub(buf,"%S",lp_servicename(snum));
116 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
117 conn->connectpath, conn->gid,
118 get_current_username(),
119 current_user_info.domain,
120 buf, sizeof(buf));
121 return strlen(buf) + 1;
124 static char *Expand(connection_struct *conn, int snum, char *s)
126 static pstring buf;
127 if (!s) {
128 return NULL;
130 StrnCpy(buf,s,sizeof(buf)/2);
131 pstring_sub(buf,"%S",lp_servicename(snum));
132 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
133 conn->connectpath, conn->gid,
134 get_current_username(),
135 current_user_info.domain,
136 buf, sizeof(buf));
137 return &buf[0];
140 /*******************************************************************
141 Check a API string for validity when we only need to check the prefix.
142 ******************************************************************/
144 static BOOL prefix_ok(const char *str, const char *prefix)
146 return(strncmp(str,prefix,strlen(prefix)) == 0);
149 struct pack_desc {
150 const char *format; /* formatstring for structure */
151 const char *subformat; /* subformat for structure */
152 char *base; /* baseaddress of buffer */
153 int buflen; /* remaining size for fixed part; on init: length of base */
154 int subcount; /* count of substructures */
155 char *structbuf; /* pointer into buffer for remaining fixed part */
156 int stringlen; /* remaining size for variable part */
157 char *stringbuf; /* pointer into buffer for remaining variable part */
158 int neededlen; /* total needed size */
159 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
160 const char *curpos; /* current position; pointer into format or subformat */
161 int errcode;
164 static int get_counter(const char **p)
166 int i, n;
167 if (!p || !(*p)) {
168 return 1;
170 if (!isdigit((int)**p)) {
171 return 1;
173 for (n = 0;;) {
174 i = **p;
175 if (isdigit(i)) {
176 n = 10 * n + (i - '0');
177 } else {
178 return n;
180 (*p)++;
184 static int getlen(const char *p)
186 int n = 0;
187 if (!p) {
188 return 0;
191 while (*p) {
192 switch( *p++ ) {
193 case 'W': /* word (2 byte) */
194 n += 2;
195 break;
196 case 'K': /* status word? (2 byte) */
197 n += 2;
198 break;
199 case 'N': /* count of substructures (word) at end */
200 n += 2;
201 break;
202 case 'D': /* double word (4 byte) */
203 case 'z': /* offset to zero terminated string (4 byte) */
204 case 'l': /* offset to user data (4 byte) */
205 n += 4;
206 break;
207 case 'b': /* offset to data (with counter) (4 byte) */
208 n += 4;
209 get_counter(&p);
210 break;
211 case 'B': /* byte (with optional counter) */
212 n += get_counter(&p);
213 break;
216 return n;
219 static BOOL init_package(struct pack_desc *p, int count, int subcount)
221 int n = p->buflen;
222 int i;
224 if (!p->format || !p->base) {
225 return False;
228 i = count * getlen(p->format);
229 if (p->subformat) {
230 i += subcount * getlen(p->subformat);
232 p->structbuf = p->base;
233 p->neededlen = 0;
234 p->usedlen = 0;
235 p->subcount = 0;
236 p->curpos = p->format;
237 if (i > n) {
238 p->neededlen = i;
239 i = n = 0;
240 #if 0
242 * This is the old error code we used. Aparently
243 * WinNT/2k systems return ERRbuftoosmall (2123) and
244 * OS/2 needs this. I'm leaving this here so we can revert
245 * if needed. JRA.
247 p->errcode = ERRmoredata;
248 #else
249 p->errcode = ERRbuftoosmall;
250 #endif
251 } else {
252 p->errcode = NERR_Success;
254 p->buflen = i;
255 n -= i;
256 p->stringbuf = p->base + i;
257 p->stringlen = n;
258 return (p->errcode == NERR_Success);
261 static int package(struct pack_desc *p, ...)
263 va_list args;
264 int needed=0, stringneeded;
265 const char *str=NULL;
266 int is_string=0, stringused;
267 int32 temp;
269 va_start(args,p);
271 if (!*p->curpos) {
272 if (!p->subcount) {
273 p->curpos = p->format;
274 } else {
275 p->curpos = p->subformat;
276 p->subcount--;
279 #if CHECK_TYPES
280 str = va_arg(args,char*);
281 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
282 #endif
283 stringneeded = -1;
285 if (!p->curpos) {
286 va_end(args);
287 return 0;
290 switch( *p->curpos++ ) {
291 case 'W': /* word (2 byte) */
292 needed = 2;
293 temp = va_arg(args,int);
294 if (p->buflen >= needed) {
295 SSVAL(p->structbuf,0,temp);
297 break;
298 case 'K': /* status word? (2 byte) */
299 needed = 2;
300 temp = va_arg(args,int);
301 if (p->buflen >= needed) {
302 SSVAL(p->structbuf,0,temp);
304 break;
305 case 'N': /* count of substructures (word) at end */
306 needed = 2;
307 p->subcount = va_arg(args,int);
308 if (p->buflen >= needed) {
309 SSVAL(p->structbuf,0,p->subcount);
311 break;
312 case 'D': /* double word (4 byte) */
313 needed = 4;
314 temp = va_arg(args,int);
315 if (p->buflen >= needed) {
316 SIVAL(p->structbuf,0,temp);
318 break;
319 case 'B': /* byte (with optional counter) */
320 needed = get_counter(&p->curpos);
322 char *s = va_arg(args,char*);
323 if (p->buflen >= needed) {
324 StrnCpy(p->structbuf,s?s:"",needed-1);
327 break;
328 case 'z': /* offset to zero terminated string (4 byte) */
329 str = va_arg(args,char*);
330 stringneeded = (str ? strlen(str)+1 : 0);
331 is_string = 1;
332 break;
333 case 'l': /* offset to user data (4 byte) */
334 str = va_arg(args,char*);
335 stringneeded = va_arg(args,int);
336 is_string = 0;
337 break;
338 case 'b': /* offset to data (with counter) (4 byte) */
339 str = va_arg(args,char*);
340 stringneeded = get_counter(&p->curpos);
341 is_string = 0;
342 break;
345 va_end(args);
346 if (stringneeded >= 0) {
347 needed = 4;
348 if (p->buflen >= needed) {
349 stringused = stringneeded;
350 if (stringused > p->stringlen) {
351 stringused = (is_string ? p->stringlen : 0);
352 if (p->errcode == NERR_Success) {
353 p->errcode = ERRmoredata;
356 if (!stringused) {
357 SIVAL(p->structbuf,0,0);
358 } else {
359 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
360 memcpy(p->stringbuf,str?str:"",stringused);
361 if (is_string) {
362 p->stringbuf[stringused-1] = '\0';
364 p->stringbuf += stringused;
365 p->stringlen -= stringused;
366 p->usedlen += stringused;
369 p->neededlen += stringneeded;
372 p->neededlen += needed;
373 if (p->buflen >= needed) {
374 p->structbuf += needed;
375 p->buflen -= needed;
376 p->usedlen += needed;
377 } else {
378 if (p->errcode == NERR_Success) {
379 p->errcode = ERRmoredata;
382 return 1;
385 #if CHECK_TYPES
386 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
387 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
388 #else
389 #define PACK(desc,t,v) package(desc,v)
390 #define PACKl(desc,t,v,l) package(desc,v,l)
391 #endif
393 static void PACKI(struct pack_desc* desc, const char *t,int v)
395 PACK(desc,t,v);
398 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
400 PACK(desc,t,v);
403 /****************************************************************************
404 Get a print queue.
405 ****************************************************************************/
407 static void PackDriverData(struct pack_desc* desc)
409 char drivdata[4+4+32];
410 SIVAL(drivdata,0,sizeof drivdata); /* cb */
411 SIVAL(drivdata,4,1000); /* lVersion */
412 memset(drivdata+8,0,32); /* szDeviceName */
413 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
414 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
417 static int check_printq_info(struct pack_desc* desc,
418 unsigned int uLevel, char *id1, char *id2)
420 desc->subformat = NULL;
421 switch( uLevel ) {
422 case 0:
423 desc->format = "B13";
424 break;
425 case 1:
426 desc->format = "B13BWWWzzzzzWW";
427 break;
428 case 2:
429 desc->format = "B13BWWWzzzzzWN";
430 desc->subformat = "WB21BB16B10zWWzDDz";
431 break;
432 case 3:
433 desc->format = "zWWWWzzzzWWzzl";
434 break;
435 case 4:
436 desc->format = "zWWWWzzzzWNzzl";
437 desc->subformat = "WWzWWDDzz";
438 break;
439 case 5:
440 desc->format = "z";
441 break;
442 case 51:
443 desc->format = "K";
444 break;
445 case 52:
446 desc->format = "WzzzzzzzzN";
447 desc->subformat = "z";
448 break;
449 default:
450 DEBUG(0,("check_printq_info: invalid level %d\n",
451 uLevel ));
452 return False;
454 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
455 DEBUG(0,("check_printq_info: invalid format %s\n",
456 id1 ? id1 : "<NULL>" ));
457 return False;
459 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
460 DEBUG(0,("check_printq_info: invalid subformat %s\n",
461 id2 ? id2 : "<NULL>" ));
462 return False;
464 return True;
468 #define RAP_JOB_STATUS_QUEUED 0
469 #define RAP_JOB_STATUS_PAUSED 1
470 #define RAP_JOB_STATUS_SPOOLING 2
471 #define RAP_JOB_STATUS_PRINTING 3
472 #define RAP_JOB_STATUS_PRINTED 4
474 #define RAP_QUEUE_STATUS_PAUSED 1
475 #define RAP_QUEUE_STATUS_ERROR 2
477 /* turn a print job status into a on the wire status
479 static int printj_status(int v)
481 switch (v) {
482 case LPQ_QUEUED:
483 return RAP_JOB_STATUS_QUEUED;
484 case LPQ_PAUSED:
485 return RAP_JOB_STATUS_PAUSED;
486 case LPQ_SPOOLING:
487 return RAP_JOB_STATUS_SPOOLING;
488 case LPQ_PRINTING:
489 return RAP_JOB_STATUS_PRINTING;
491 return 0;
494 /* turn a print queue status into a on the wire status
496 static int printq_status(int v)
498 switch (v) {
499 case LPQ_QUEUED:
500 return 0;
501 case LPQ_PAUSED:
502 return RAP_QUEUE_STATUS_PAUSED;
504 return RAP_QUEUE_STATUS_ERROR;
507 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
508 struct pack_desc *desc,
509 print_queue_struct *queue, int n)
511 time_t t = queue->time;
513 /* the client expects localtime */
514 t -= get_time_zone(t);
516 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
517 if (uLevel == 1) {
518 PACKS(desc,"B21",queue->fs_user); /* szUserName */
519 PACKS(desc,"B",""); /* pad */
520 PACKS(desc,"B16",""); /* szNotifyName */
521 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
522 PACKS(desc,"z",""); /* pszParms */
523 PACKI(desc,"W",n+1); /* uPosition */
524 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
525 PACKS(desc,"z",""); /* pszStatus */
526 PACKI(desc,"D",t); /* ulSubmitted */
527 PACKI(desc,"D",queue->size); /* ulSize */
528 PACKS(desc,"z",queue->fs_file); /* pszComment */
530 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
531 PACKI(desc,"W",queue->priority); /* uPriority */
532 PACKS(desc,"z",queue->fs_user); /* pszUserName */
533 PACKI(desc,"W",n+1); /* uPosition */
534 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
535 PACKI(desc,"D",t); /* ulSubmitted */
536 PACKI(desc,"D",queue->size); /* ulSize */
537 PACKS(desc,"z","Samba"); /* pszComment */
538 PACKS(desc,"z",queue->fs_file); /* pszDocument */
539 if (uLevel == 3) {
540 PACKS(desc,"z",""); /* pszNotifyName */
541 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
542 PACKS(desc,"z",""); /* pszParms */
543 PACKS(desc,"z",""); /* pszStatus */
544 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
545 PACKS(desc,"z","lpd"); /* pszQProcName */
546 PACKS(desc,"z",""); /* pszQProcParms */
547 PACKS(desc,"z","NULL"); /* pszDriverName */
548 PackDriverData(desc); /* pDriverData */
549 PACKS(desc,"z",""); /* pszPrinterName */
550 } else if (uLevel == 4) { /* OS2 */
551 PACKS(desc,"z",""); /* pszSpoolFileName */
552 PACKS(desc,"z",""); /* pszPortName */
553 PACKS(desc,"z",""); /* pszStatus */
554 PACKI(desc,"D",0); /* ulPagesSpooled */
555 PACKI(desc,"D",0); /* ulPagesSent */
556 PACKI(desc,"D",0); /* ulPagesPrinted */
557 PACKI(desc,"D",0); /* ulTimePrinted */
558 PACKI(desc,"D",0); /* ulExtendJobStatus */
559 PACKI(desc,"D",0); /* ulStartPage */
560 PACKI(desc,"D",0); /* ulEndPage */
565 /********************************************************************
566 Return a driver name given an snum.
567 Returns True if from tdb, False otherwise.
568 ********************************************************************/
570 static BOOL get_driver_name(int snum, pstring drivername)
572 NT_PRINTER_INFO_LEVEL *info = NULL;
573 BOOL in_tdb = False;
575 get_a_printer (NULL, &info, 2, lp_servicename(snum));
576 if (info != NULL) {
577 pstrcpy( drivername, info->info_2->drivername);
578 in_tdb = True;
579 free_a_printer(&info, 2);
582 return in_tdb;
585 /********************************************************************
586 Respond to the DosPrintQInfo command with a level of 52
587 This is used to get printer driver information for Win9x clients
588 ********************************************************************/
589 static void fill_printq_info_52(connection_struct *conn, int snum,
590 struct pack_desc* desc, int count )
592 int i;
593 fstring location;
594 NT_PRINTER_DRIVER_INFO_LEVEL driver;
595 NT_PRINTER_INFO_LEVEL *printer = NULL;
597 ZERO_STRUCT(driver);
599 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
600 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
601 lp_servicename(snum)));
602 goto err;
605 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
606 "Windows 4.0", 0)) )
608 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
609 printer->info_2->drivername));
610 goto err;
613 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
614 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
615 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
617 PACKI(desc, "W", 0x0400); /* don't know */
618 PACKS(desc, "z", driver.info_3->name); /* long printer name */
619 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
620 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
621 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
623 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
624 standard_sub_basic( "", "", location, sizeof(location)-1 );
625 PACKS(desc,"z", location); /* share to retrieve files */
627 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
628 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
629 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
631 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
632 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
633 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
634 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
635 DEBUG(3,("Driver Location: %s:\n",location));
636 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
637 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
638 PACKI(desc,"N",count); /* number of files to copy */
640 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
642 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
643 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
644 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
647 /* sanity check */
648 if ( i != count )
649 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
650 count, i));
652 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
654 desc->errcode=NERR_Success;
655 goto done;
657 err:
658 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
659 desc->errcode=NERR_notsupported;
661 done:
662 if ( printer )
663 free_a_printer( &printer, 2 );
665 if ( driver.info_3 )
666 free_a_printer_driver( driver, 3 );
670 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
671 struct pack_desc* desc,
672 int count, print_queue_struct* queue,
673 print_status_struct* status)
675 switch (uLevel) {
676 case 1:
677 case 2:
678 PACKS(desc,"B13",SERVICE(snum));
679 break;
680 case 3:
681 case 4:
682 case 5:
683 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
684 break;
685 case 51:
686 PACKI(desc,"K",printq_status(status->status));
687 break;
690 if (uLevel == 1 || uLevel == 2) {
691 PACKS(desc,"B",""); /* alignment */
692 PACKI(desc,"W",5); /* priority */
693 PACKI(desc,"W",0); /* start time */
694 PACKI(desc,"W",0); /* until time */
695 PACKS(desc,"z",""); /* pSepFile */
696 PACKS(desc,"z","lpd"); /* pPrProc */
697 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
698 PACKS(desc,"z",""); /* pParms */
699 if (snum < 0) {
700 PACKS(desc,"z","UNKNOWN PRINTER");
701 PACKI(desc,"W",LPSTAT_ERROR);
703 else if (!status || !status->message[0]) {
704 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
705 PACKI(desc,"W",LPSTAT_OK); /* status */
706 } else {
707 PACKS(desc,"z",status->message);
708 PACKI(desc,"W",printq_status(status->status)); /* status */
710 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
713 if (uLevel == 3 || uLevel == 4) {
714 pstring drivername;
716 PACKI(desc,"W",5); /* uPriority */
717 PACKI(desc,"W",0); /* uStarttime */
718 PACKI(desc,"W",0); /* uUntiltime */
719 PACKI(desc,"W",5); /* pad1 */
720 PACKS(desc,"z",""); /* pszSepFile */
721 PACKS(desc,"z","WinPrint"); /* pszPrProc */
722 PACKS(desc,"z",NULL); /* pszParms */
723 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
724 /* "don't ask" that it's done this way to fix corrupted
725 Win9X/ME printer comments. */
726 if (!status) {
727 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
728 } else {
729 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
731 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
732 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
733 get_driver_name(snum,drivername);
734 PACKS(desc,"z",drivername); /* pszDriverName */
735 PackDriverData(desc); /* pDriverData */
738 if (uLevel == 2 || uLevel == 4) {
739 int i;
740 for (i=0;i<count;i++)
741 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
744 if (uLevel==52)
745 fill_printq_info_52( conn, snum, desc, count );
748 /* This function returns the number of files for a given driver */
749 static int get_printerdrivernumber(int snum)
751 int result = 0;
752 NT_PRINTER_DRIVER_INFO_LEVEL driver;
753 NT_PRINTER_INFO_LEVEL *printer = NULL;
755 ZERO_STRUCT(driver);
757 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
758 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
759 lp_servicename(snum)));
760 goto done;
763 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
764 "Windows 4.0", 0)) )
766 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
767 printer->info_2->drivername));
768 goto done;
771 /* count the number of files */
772 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
773 result++;
775 done:
776 if ( printer )
777 free_a_printer( &printer, 2 );
779 if ( driver.info_3 )
780 free_a_printer_driver( driver, 3 );
782 return result;
785 static BOOL api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
786 char *param, int tpscnt,
787 char *data, int tdscnt,
788 int mdrcnt,int mprcnt,
789 char **rdata,char **rparam,
790 int *rdata_len,int *rparam_len)
792 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
793 char *str2 = skip_string(param,tpscnt,str1);
794 char *p = skip_string(param,tpscnt,str2);
795 char *QueueName = p;
796 unsigned int uLevel;
797 int count=0;
798 int snum;
799 char *str3;
800 struct pack_desc desc;
801 print_queue_struct *queue=NULL;
802 print_status_struct status;
803 char* tmpdata=NULL;
805 if (!str1 || !str2 || !p) {
806 return False;
808 memset((char *)&status,'\0',sizeof(status));
809 memset((char *)&desc,'\0',sizeof(desc));
811 p = skip_string(param,tpscnt,p);
812 if (!p) {
813 return False;
815 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
816 str3 = get_safe_str_ptr(param,tpscnt,p,4);
817 /* str3 may be null here and is checked in check_printq_info(). */
819 /* remove any trailing username */
820 if ((p = strchr_m(QueueName,'%')))
821 *p = 0;
823 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
825 /* check it's a supported varient */
826 if (!prefix_ok(str1,"zWrLh"))
827 return False;
828 if (!check_printq_info(&desc,uLevel,str2,str3)) {
830 * Patch from Scott Moomaw <scott@bridgewater.edu>
831 * to return the 'invalid info level' error if an
832 * unknown level was requested.
834 *rdata_len = 0;
835 *rparam_len = 6;
836 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
837 if (!*rparam) {
838 return False;
840 SSVALS(*rparam,0,ERRunknownlevel);
841 SSVAL(*rparam,2,0);
842 SSVAL(*rparam,4,0);
843 return(True);
846 snum = find_service(QueueName);
847 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
848 return False;
850 if (uLevel==52) {
851 count = get_printerdrivernumber(snum);
852 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
853 } else {
854 count = print_queue_status(snum, &queue,&status);
857 if (mdrcnt > 0) {
858 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
859 if (!*rdata) {
860 return False;
862 desc.base = *rdata;
863 desc.buflen = mdrcnt;
864 } else {
866 * Don't return data but need to get correct length
867 * init_package will return wrong size if buflen=0
869 desc.buflen = getlen(desc.format);
870 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
873 if (init_package(&desc,1,count)) {
874 desc.subcount = count;
875 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
878 *rdata_len = desc.usedlen;
881 * We must set the return code to ERRbuftoosmall
882 * in order to support lanman style printing with Win NT/2k
883 * clients --jerry
885 if (!mdrcnt && lp_disable_spoolss())
886 desc.errcode = ERRbuftoosmall;
888 *rdata_len = desc.usedlen;
889 *rparam_len = 6;
890 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
891 if (!*rparam) {
892 return False;
894 SSVALS(*rparam,0,desc.errcode);
895 SSVAL(*rparam,2,0);
896 SSVAL(*rparam,4,desc.neededlen);
898 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
900 SAFE_FREE(queue);
901 SAFE_FREE(tmpdata);
903 return(True);
906 /****************************************************************************
907 View list of all print jobs on all queues.
908 ****************************************************************************/
910 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
911 char *param, int tpscnt,
912 char *data, int tdscnt,
913 int mdrcnt, int mprcnt,
914 char **rdata, char** rparam,
915 int *rdata_len, int *rparam_len)
917 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
918 char *output_format1 = skip_string(param,tpscnt,param_format);
919 char *p = skip_string(param,tpscnt,output_format1);
920 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
921 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
922 int services = lp_numservices();
923 int i, n;
924 struct pack_desc desc;
925 print_queue_struct **queue = NULL;
926 print_status_struct *status = NULL;
927 int *subcntarr = NULL;
928 int queuecnt = 0, subcnt = 0, succnt = 0;
930 if (!param_format || !output_format1 || !p) {
931 return False;
934 memset((char *)&desc,'\0',sizeof(desc));
936 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
938 if (!prefix_ok(param_format,"WrLeh")) {
939 return False;
941 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
943 * Patch from Scott Moomaw <scott@bridgewater.edu>
944 * to return the 'invalid info level' error if an
945 * unknown level was requested.
947 *rdata_len = 0;
948 *rparam_len = 6;
949 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
950 if (!*rparam) {
951 return False;
953 SSVALS(*rparam,0,ERRunknownlevel);
954 SSVAL(*rparam,2,0);
955 SSVAL(*rparam,4,0);
956 return(True);
959 for (i = 0; i < services; i++) {
960 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
961 queuecnt++;
965 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
966 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
967 goto err;
969 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
970 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
971 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
972 goto err;
974 memset(status,0,queuecnt*sizeof(print_status_struct));
975 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
976 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
977 goto err;
980 subcnt = 0;
981 n = 0;
982 for (i = 0; i < services; i++) {
983 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
984 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
985 subcnt += subcntarr[n];
986 n++;
990 if (mdrcnt > 0) {
991 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
992 if (!*rdata) {
993 goto err;
996 desc.base = *rdata;
997 desc.buflen = mdrcnt;
999 if (init_package(&desc,queuecnt,subcnt)) {
1000 n = 0;
1001 succnt = 0;
1002 for (i = 0; i < services; i++) {
1003 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1004 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1005 n++;
1006 if (desc.errcode == NERR_Success) {
1007 succnt = n;
1013 SAFE_FREE(subcntarr);
1015 *rdata_len = desc.usedlen;
1016 *rparam_len = 8;
1017 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1018 if (!*rparam) {
1019 goto err;
1021 SSVALS(*rparam,0,desc.errcode);
1022 SSVAL(*rparam,2,0);
1023 SSVAL(*rparam,4,succnt);
1024 SSVAL(*rparam,6,queuecnt);
1026 for (i = 0; i < queuecnt; i++) {
1027 if (queue) {
1028 SAFE_FREE(queue[i]);
1032 SAFE_FREE(queue);
1033 SAFE_FREE(status);
1035 return True;
1037 err:
1039 SAFE_FREE(subcntarr);
1040 for (i = 0; i < queuecnt; i++) {
1041 if (queue) {
1042 SAFE_FREE(queue[i]);
1045 SAFE_FREE(queue);
1046 SAFE_FREE(status);
1048 return False;
1051 /****************************************************************************
1052 Get info level for a server list query.
1053 ****************************************************************************/
1055 static BOOL check_server_info(int uLevel, char* id)
1057 switch( uLevel ) {
1058 case 0:
1059 if (strcmp(id,"B16") != 0) {
1060 return False;
1062 break;
1063 case 1:
1064 if (strcmp(id,"B16BBDz") != 0) {
1065 return False;
1067 break;
1068 default:
1069 return False;
1071 return True;
1074 struct srv_info_struct {
1075 fstring name;
1076 uint32 type;
1077 fstring comment;
1078 fstring domain;
1079 BOOL server_added;
1082 /*******************************************************************
1083 Get server info lists from the files saved by nmbd. Return the
1084 number of entries.
1085 ******************************************************************/
1087 static int get_server_info(uint32 servertype,
1088 struct srv_info_struct **servers,
1089 const char *domain)
1091 int count=0;
1092 int alloced=0;
1093 char **lines;
1094 BOOL local_list_only;
1095 int i;
1097 lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1098 if (!lines) {
1099 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1100 return 0;
1103 /* request for everything is code for request all servers */
1104 if (servertype == SV_TYPE_ALL) {
1105 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1108 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1110 DEBUG(4,("Servertype search: %8x\n",servertype));
1112 for (i=0;lines[i];i++) {
1113 fstring stype;
1114 struct srv_info_struct *s;
1115 const char *ptr = lines[i];
1116 BOOL ok = True;
1118 if (!*ptr) {
1119 continue;
1122 if (count == alloced) {
1123 alloced += 10;
1124 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1125 if (!*servers) {
1126 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1127 file_lines_free(lines);
1128 return 0;
1130 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1132 s = &(*servers)[count];
1134 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1135 continue;
1137 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1138 continue;
1140 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1141 continue;
1143 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1144 /* this allows us to cope with an old nmbd */
1145 fstrcpy(s->domain,lp_workgroup());
1148 if (sscanf(stype,"%X",&s->type) != 1) {
1149 DEBUG(4,("r:host file "));
1150 ok = False;
1153 /* Filter the servers/domains we return based on what was asked for. */
1155 /* Check to see if we are being asked for a local list only. */
1156 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1157 DEBUG(4,("r: local list only"));
1158 ok = False;
1161 /* doesn't match up: don't want it */
1162 if (!(servertype & s->type)) {
1163 DEBUG(4,("r:serv type "));
1164 ok = False;
1167 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1168 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1169 DEBUG(4,("s: dom mismatch "));
1170 ok = False;
1173 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1174 ok = False;
1177 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1178 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1180 if (ok) {
1181 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1182 s->name, s->type, s->comment, s->domain));
1183 s->server_added = True;
1184 count++;
1185 } else {
1186 DEBUG(4,("%20s %8x %25s %15s\n",
1187 s->name, s->type, s->comment, s->domain));
1191 file_lines_free(lines);
1192 return count;
1195 /*******************************************************************
1196 Fill in a server info structure.
1197 ******************************************************************/
1199 static int fill_srv_info(struct srv_info_struct *service,
1200 int uLevel, char **buf, int *buflen,
1201 char **stringbuf, int *stringspace, char *baseaddr)
1203 int struct_len;
1204 char* p;
1205 char* p2;
1206 int l2;
1207 int len;
1209 switch (uLevel) {
1210 case 0:
1211 struct_len = 16;
1212 break;
1213 case 1:
1214 struct_len = 26;
1215 break;
1216 default:
1217 return -1;
1220 if (!buf) {
1221 len = 0;
1222 switch (uLevel) {
1223 case 1:
1224 len = strlen(service->comment)+1;
1225 break;
1228 *buflen = struct_len;
1229 *stringspace = len;
1230 return struct_len + len;
1233 len = struct_len;
1234 p = *buf;
1235 if (*buflen < struct_len) {
1236 return -1;
1238 if (stringbuf) {
1239 p2 = *stringbuf;
1240 l2 = *stringspace;
1241 } else {
1242 p2 = p + struct_len;
1243 l2 = *buflen - struct_len;
1245 if (!baseaddr) {
1246 baseaddr = p;
1249 switch (uLevel) {
1250 case 0:
1251 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1252 break;
1254 case 1:
1255 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1256 SIVAL(p,18,service->type);
1257 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1258 len += CopyAndAdvance(&p2,service->comment,&l2);
1259 break;
1262 if (stringbuf) {
1263 *buf = p + struct_len;
1264 *buflen -= struct_len;
1265 *stringbuf = p2;
1266 *stringspace = l2;
1267 } else {
1268 *buf = p2;
1269 *buflen -= len;
1271 return len;
1275 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1277 return(strcmp(s1->name,s2->name));
1280 /****************************************************************************
1281 View list of servers available (or possibly domains). The info is
1282 extracted from lists saved by nmbd on the local host.
1283 ****************************************************************************/
1285 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1286 char *param, int tpscnt,
1287 char *data, int tdscnt,
1288 int mdrcnt, int mprcnt, char **rdata,
1289 char **rparam, int *rdata_len, int *rparam_len)
1291 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1292 char *str2 = skip_string(param,tpscnt,str1);
1293 char *p = skip_string(param,tpscnt,str2);
1294 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1295 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1296 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1297 char *p2;
1298 int data_len, fixed_len, string_len;
1299 int f_len = 0, s_len = 0;
1300 struct srv_info_struct *servers=NULL;
1301 int counted=0,total=0;
1302 int i,missed;
1303 fstring domain;
1304 BOOL domain_request;
1305 BOOL local_request;
1307 if (!str1 || !str2 || !p) {
1308 return False;
1311 /* If someone sets all the bits they don't really mean to set
1312 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1313 known servers. */
1315 if (servertype == SV_TYPE_ALL) {
1316 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1319 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1320 any other bit (they may just set this bit on it's own) they
1321 want all the locally seen servers. However this bit can be
1322 set on its own so set the requested servers to be
1323 ALL - DOMAIN_ENUM. */
1325 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1326 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1329 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1330 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1332 p += 8;
1334 if (!prefix_ok(str1,"WrLehD")) {
1335 return False;
1337 if (!check_server_info(uLevel,str2)) {
1338 return False;
1341 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1342 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1343 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1345 if (strcmp(str1, "WrLehDz") == 0) {
1346 if (skip_string(param,tpscnt,p) == NULL) {
1347 return False;
1349 pull_ascii_fstring(domain, p);
1350 } else {
1351 fstrcpy(domain, lp_workgroup());
1354 if (lp_browse_list()) {
1355 total = get_server_info(servertype,&servers,domain);
1358 data_len = fixed_len = string_len = 0;
1359 missed = 0;
1361 if (total > 0) {
1362 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1366 char *lastname=NULL;
1368 for (i=0;i<total;i++) {
1369 struct srv_info_struct *s = &servers[i];
1371 if (lastname && strequal(lastname,s->name)) {
1372 continue;
1374 lastname = s->name;
1375 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1376 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1377 s->name, s->type, s->comment, s->domain));
1379 if (data_len <= buf_len) {
1380 counted++;
1381 fixed_len += f_len;
1382 string_len += s_len;
1383 } else {
1384 missed++;
1389 *rdata_len = fixed_len + string_len;
1390 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1391 if (!*rdata) {
1392 return False;
1394 memset(*rdata,'\0',*rdata_len);
1396 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1397 p = *rdata;
1398 f_len = fixed_len;
1399 s_len = string_len;
1402 char *lastname=NULL;
1403 int count2 = counted;
1405 for (i = 0; i < total && count2;i++) {
1406 struct srv_info_struct *s = &servers[i];
1408 if (lastname && strequal(lastname,s->name)) {
1409 continue;
1411 lastname = s->name;
1412 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1413 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1414 s->name, s->type, s->comment, s->domain));
1415 count2--;
1419 *rparam_len = 8;
1420 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1421 if (!*rparam) {
1422 return False;
1424 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1425 SSVAL(*rparam,2,0);
1426 SSVAL(*rparam,4,counted);
1427 SSVAL(*rparam,6,counted+missed);
1429 SAFE_FREE(servers);
1431 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1432 domain,uLevel,counted,counted+missed));
1434 return True;
1437 /****************************************************************************
1438 command 0x34 - suspected of being a "Lookup Names" stub api
1439 ****************************************************************************/
1441 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1442 char *param, int tpscnt,
1443 char *data, int tdscnt,
1444 int mdrcnt, int mprcnt, char **rdata,
1445 char **rparam, int *rdata_len, int *rparam_len)
1447 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1448 char *str2 = skip_string(param,tpscnt,str1);
1449 char *p = skip_string(param,tpscnt,str2);
1450 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1451 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1452 int counted=0;
1453 int missed=0;
1455 if (!str1 || !str2 || !p) {
1456 return False;
1459 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1460 str1, str2, p, uLevel, buf_len));
1462 if (!prefix_ok(str1,"zWrLeh")) {
1463 return False;
1466 *rdata_len = 0;
1468 *rparam_len = 8;
1469 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1470 if (!*rparam) {
1471 return False;
1474 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1475 SSVAL(*rparam,2,0);
1476 SSVAL(*rparam,4,counted);
1477 SSVAL(*rparam,6,counted+missed);
1479 return True;
1482 /****************************************************************************
1483 get info about a share
1484 ****************************************************************************/
1486 static BOOL check_share_info(int uLevel, char* id)
1488 switch( uLevel ) {
1489 case 0:
1490 if (strcmp(id,"B13") != 0) {
1491 return False;
1493 break;
1494 case 1:
1495 if (strcmp(id,"B13BWz") != 0) {
1496 return False;
1498 break;
1499 case 2:
1500 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1501 return False;
1503 break;
1504 case 91:
1505 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1506 return False;
1508 break;
1509 default:
1510 return False;
1512 return True;
1515 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1516 char** buf, int* buflen,
1517 char** stringbuf, int* stringspace, char* baseaddr)
1519 int struct_len;
1520 char* p;
1521 char* p2;
1522 int l2;
1523 int len;
1525 switch( uLevel ) {
1526 case 0:
1527 struct_len = 13;
1528 break;
1529 case 1:
1530 struct_len = 20;
1531 break;
1532 case 2:
1533 struct_len = 40;
1534 break;
1535 case 91:
1536 struct_len = 68;
1537 break;
1538 default:
1539 return -1;
1543 if (!buf) {
1544 len = 0;
1546 if (uLevel > 0) {
1547 len += StrlenExpanded(conn,snum,lp_comment(snum));
1549 if (uLevel > 1) {
1550 len += strlen(lp_pathname(snum)) + 1;
1552 if (buflen) {
1553 *buflen = struct_len;
1555 if (stringspace) {
1556 *stringspace = len;
1558 return struct_len + len;
1561 len = struct_len;
1562 p = *buf;
1563 if ((*buflen) < struct_len) {
1564 return -1;
1567 if (stringbuf) {
1568 p2 = *stringbuf;
1569 l2 = *stringspace;
1570 } else {
1571 p2 = p + struct_len;
1572 l2 = (*buflen) - struct_len;
1575 if (!baseaddr) {
1576 baseaddr = p;
1579 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1581 if (uLevel > 0) {
1582 int type;
1584 SCVAL(p,13,0);
1585 type = STYPE_DISKTREE;
1586 if (lp_print_ok(snum)) {
1587 type = STYPE_PRINTQ;
1589 if (strequal("IPC",lp_fstype(snum))) {
1590 type = STYPE_IPC;
1592 SSVAL(p,14,type); /* device type */
1593 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1594 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1597 if (uLevel > 1) {
1598 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1599 SSVALS(p,22,-1); /* max uses */
1600 SSVAL(p,24,1); /* current uses */
1601 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1602 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1603 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1606 if (uLevel > 2) {
1607 memset(p+40,0,SHPWLEN+2);
1608 SSVAL(p,50,0);
1609 SIVAL(p,52,0);
1610 SSVAL(p,56,0);
1611 SSVAL(p,58,0);
1612 SIVAL(p,60,0);
1613 SSVAL(p,64,0);
1614 SSVAL(p,66,0);
1617 if (stringbuf) {
1618 (*buf) = p + struct_len;
1619 (*buflen) -= struct_len;
1620 (*stringbuf) = p2;
1621 (*stringspace) = l2;
1622 } else {
1623 (*buf) = p2;
1624 (*buflen) -= len;
1627 return len;
1630 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1631 char *param, int tpscnt,
1632 char *data, int tdscnt,
1633 int mdrcnt,int mprcnt,
1634 char **rdata,char **rparam,
1635 int *rdata_len,int *rparam_len)
1637 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1638 char *str2 = skip_string(param,tpscnt,str1);
1639 char *netname = skip_string(param,tpscnt,str2);
1640 char *p = skip_string(param,tpscnt,netname);
1641 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1642 int snum;
1644 if (!str1 || !str2 || !netname || !p) {
1645 return False;
1648 snum = find_service(netname);
1649 if (snum < 0) {
1650 return False;
1653 /* check it's a supported varient */
1654 if (!prefix_ok(str1,"zWrLh")) {
1655 return False;
1657 if (!check_share_info(uLevel,str2)) {
1658 return False;
1661 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
1662 if (!*rdata) {
1663 return False;
1665 p = *rdata;
1666 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1667 if (*rdata_len < 0) {
1668 return False;
1671 *rparam_len = 6;
1672 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1673 if (!*rparam) {
1674 return False;
1676 SSVAL(*rparam,0,NERR_Success);
1677 SSVAL(*rparam,2,0); /* converter word */
1678 SSVAL(*rparam,4,*rdata_len);
1680 return True;
1683 /****************************************************************************
1684 View the list of available shares.
1686 This function is the server side of the NetShareEnum() RAP call.
1687 It fills the return buffer with share names and share comments.
1688 Note that the return buffer normally (in all known cases) allows only
1689 twelve byte strings for share names (plus one for a nul terminator).
1690 Share names longer than 12 bytes must be skipped.
1691 ****************************************************************************/
1693 static BOOL api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1694 char *param, int tpscnt,
1695 char *data, int tdscnt,
1696 int mdrcnt,
1697 int mprcnt,
1698 char **rdata,
1699 char **rparam,
1700 int *rdata_len,
1701 int *rparam_len )
1703 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1704 char *str2 = skip_string(param,tpscnt,str1);
1705 char *p = skip_string(param,tpscnt,str2);
1706 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1707 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1708 char *p2;
1709 int count = 0;
1710 int total=0,counted=0;
1711 BOOL missed = False;
1712 int i;
1713 int data_len, fixed_len, string_len;
1714 int f_len = 0, s_len = 0;
1716 if (!str1 || !str2 || !p) {
1717 return False;
1720 if (!prefix_ok(str1,"WrLeh")) {
1721 return False;
1723 if (!check_share_info(uLevel,str2)) {
1724 return False;
1727 /* Ensure all the usershares are loaded. */
1728 become_root();
1729 count = load_usershare_shares();
1730 unbecome_root();
1732 data_len = fixed_len = string_len = 0;
1733 for (i=0;i<count;i++) {
1734 fstring servicename_dos;
1735 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1736 continue;
1738 push_ascii_fstring(servicename_dos, lp_servicename(i));
1739 /* Maximum name length = 13. */
1740 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1741 total++;
1742 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1743 if (data_len <= buf_len) {
1744 counted++;
1745 fixed_len += f_len;
1746 string_len += s_len;
1747 } else {
1748 missed = True;
1753 *rdata_len = fixed_len + string_len;
1754 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1755 if (!*rdata) {
1756 return False;
1758 memset(*rdata,0,*rdata_len);
1760 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1761 p = *rdata;
1762 f_len = fixed_len;
1763 s_len = string_len;
1765 for( i = 0; i < count; i++ ) {
1766 fstring servicename_dos;
1767 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1768 continue;
1771 push_ascii_fstring(servicename_dos, lp_servicename(i));
1772 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1773 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1774 break;
1779 *rparam_len = 8;
1780 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1781 if (!*rparam) {
1782 return False;
1784 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1785 SSVAL(*rparam,2,0);
1786 SSVAL(*rparam,4,counted);
1787 SSVAL(*rparam,6,total);
1789 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1790 counted,total,uLevel,
1791 buf_len,*rdata_len,mdrcnt));
1793 return True;
1796 /****************************************************************************
1797 Add a share
1798 ****************************************************************************/
1800 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1801 char *param, int tpscnt,
1802 char *data, int tdscnt,
1803 int mdrcnt,int mprcnt,
1804 char **rdata,char **rparam,
1805 int *rdata_len,int *rparam_len)
1807 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1808 char *str2 = skip_string(param,tpscnt,str1);
1809 char *p = skip_string(param,tpscnt,str2);
1810 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1811 fstring sharename;
1812 fstring comment;
1813 pstring pathname;
1814 char *command, *cmdname;
1815 unsigned int offset;
1816 int snum;
1817 int res = ERRunsup;
1819 if (!str1 || !str2 || !p) {
1820 return False;
1823 /* check it's a supported varient */
1824 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1825 return False;
1827 if (!check_share_info(uLevel,str2)) {
1828 return False;
1830 if (uLevel != 2) {
1831 return False;
1834 /* Do we have a string ? */
1835 if (skip_string(data,mdrcnt,data) == NULL) {
1836 return False;
1838 pull_ascii_fstring(sharename,data);
1839 snum = find_service(sharename);
1840 if (snum >= 0) { /* already exists */
1841 res = ERRfilexists;
1842 goto error_exit;
1845 if (mdrcnt < 28) {
1846 return False;
1849 /* only support disk share adds */
1850 if (SVAL(data,14)!=STYPE_DISKTREE) {
1851 return False;
1854 offset = IVAL(data, 16);
1855 if (offset >= mdrcnt) {
1856 res = ERRinvalidparam;
1857 goto error_exit;
1860 /* Do we have a string ? */
1861 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1862 return False;
1864 pull_ascii_fstring(comment, offset? (data+offset) : "");
1866 offset = IVAL(data, 26);
1868 if (offset >= mdrcnt) {
1869 res = ERRinvalidparam;
1870 goto error_exit;
1873 /* Do we have a string ? */
1874 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1875 return False;
1877 pull_ascii_pstring(pathname, offset? (data+offset) : "");
1879 string_replace(sharename, '"', ' ');
1880 string_replace(pathname, '"', ' ');
1881 string_replace(comment, '"', ' ');
1883 cmdname = lp_add_share_cmd();
1885 if (!cmdname || *cmdname == '\0') {
1886 return False;
1889 asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1890 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1892 if (command) {
1893 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1895 if ((res = smbrun(command, NULL)) != 0) {
1896 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1897 SAFE_FREE(command);
1898 res = ERRnoaccess;
1899 goto error_exit;
1900 } else {
1901 SAFE_FREE(command);
1902 message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
1904 } else {
1905 return False;
1908 *rparam_len = 6;
1909 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1910 if (!*rparam) {
1911 return False;
1913 SSVAL(*rparam,0,NERR_Success);
1914 SSVAL(*rparam,2,0); /* converter word */
1915 SSVAL(*rparam,4,*rdata_len);
1916 *rdata_len = 0;
1918 return True;
1920 error_exit:
1922 *rparam_len = 4;
1923 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1924 if (!*rparam) {
1925 return False;
1927 *rdata_len = 0;
1928 SSVAL(*rparam,0,res);
1929 SSVAL(*rparam,2,0);
1930 return True;
1933 /****************************************************************************
1934 view list of groups available
1935 ****************************************************************************/
1937 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
1938 char *param, int tpscnt,
1939 char *data, int tdscnt,
1940 int mdrcnt,int mprcnt,
1941 char **rdata,char **rparam,
1942 int *rdata_len,int *rparam_len)
1944 int i;
1945 int errflags=0;
1946 int resume_context, cli_buf_size;
1947 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1948 char *str2 = skip_string(param,tpscnt,str1);
1949 char *p = skip_string(param,tpscnt,str2);
1951 struct pdb_search *search;
1952 struct samr_displayentry *entries;
1954 int num_entries;
1956 if (!str1 || !str2 || !p) {
1957 return False;
1960 if (strcmp(str1,"WrLeh") != 0) {
1961 return False;
1964 /* parameters
1965 * W-> resume context (number of users to skip)
1966 * r -> return parameter pointer to receive buffer
1967 * L -> length of receive buffer
1968 * e -> return parameter number of entries
1969 * h -> return parameter total number of users
1972 if (strcmp("B21",str2) != 0) {
1973 return False;
1976 /* get list of domain groups SID_DOMAIN_GRP=2 */
1977 become_root();
1978 search = pdb_search_groups();
1979 unbecome_root();
1981 if (search == NULL) {
1982 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1983 return False;
1986 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
1987 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
1988 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1989 "%d\n", resume_context, cli_buf_size));
1991 become_root();
1992 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1993 &entries);
1994 unbecome_root();
1996 *rdata_len = cli_buf_size;
1997 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1998 if (!*rdata) {
1999 return False;
2002 p = *rdata;
2004 for(i=0; i<num_entries; i++) {
2005 fstring name;
2006 fstrcpy(name, entries[i].account_name);
2007 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2008 /* truncate the name at 21 chars. */
2009 memcpy(p, name, 21);
2010 DEBUG(10,("adding entry %d group %s\n", i, p));
2011 p += 21;
2012 p += 5; /* Both NT4 and W2k3SP1 do padding here.
2013 No idea why... */
2014 } else {
2015 /* set overflow error */
2016 DEBUG(3,("overflow on entry %d group %s\n", i, name));
2017 errflags=234;
2018 break;
2022 pdb_search_destroy(search);
2024 *rdata_len = PTR_DIFF(p,*rdata);
2026 *rparam_len = 8;
2027 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2028 if (!*rparam) {
2029 return False;
2031 SSVAL(*rparam, 0, errflags);
2032 SSVAL(*rparam, 2, 0); /* converter word */
2033 SSVAL(*rparam, 4, i); /* is this right?? */
2034 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
2036 return(True);
2039 /*******************************************************************
2040 Get groups that a user is a member of.
2041 ******************************************************************/
2043 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2044 char *param, int tpscnt,
2045 char *data, int tdscnt,
2046 int mdrcnt,int mprcnt,
2047 char **rdata,char **rparam,
2048 int *rdata_len,int *rparam_len)
2050 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2051 char *str2 = skip_string(param,tpscnt,str1);
2052 char *UserName = skip_string(param,tpscnt,str2);
2053 char *p = skip_string(param,tpscnt,UserName);
2054 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2055 const char *level_string;
2056 int count=0;
2057 struct samu *sampw = NULL;
2058 BOOL ret = False;
2059 DOM_SID *sids;
2060 gid_t *gids;
2061 size_t num_groups;
2062 size_t i;
2063 NTSTATUS result;
2064 DOM_SID user_sid;
2065 enum lsa_SidType type;
2066 TALLOC_CTX *mem_ctx;
2068 if (!str1 || !str2 || !UserName || !p) {
2069 return False;
2072 *rparam_len = 8;
2073 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2074 if (!*rparam) {
2075 return False;
2078 /* check it's a supported varient */
2080 if ( strcmp(str1,"zWrLeh") != 0 )
2081 return False;
2083 switch( uLevel ) {
2084 case 0:
2085 level_string = "B21";
2086 break;
2087 default:
2088 return False;
2091 if (strcmp(level_string,str2) != 0)
2092 return False;
2094 *rdata_len = mdrcnt + 1024;
2095 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2096 if (!*rdata) {
2097 return False;
2099 SSVAL(*rparam,0,NERR_Success);
2100 SSVAL(*rparam,2,0); /* converter word */
2102 p = *rdata;
2104 mem_ctx = talloc_new(NULL);
2105 if (mem_ctx == NULL) {
2106 DEBUG(0, ("talloc_new failed\n"));
2107 return False;
2110 if ( !(sampw = samu_new(mem_ctx)) ) {
2111 DEBUG(0, ("samu_new() failed!\n"));
2112 TALLOC_FREE(mem_ctx);
2113 return False;
2116 /* Lookup the user information; This should only be one of
2117 our accounts (not remote domains) */
2119 become_root(); /* ROOT BLOCK */
2121 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2122 NULL, NULL, &user_sid, &type)) {
2123 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2124 goto done;
2127 if (type != SID_NAME_USER) {
2128 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2129 sid_type_lookup(type)));
2130 goto done;
2133 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2134 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2135 sid_string_static(&user_sid), UserName));
2136 goto done;
2139 gids = NULL;
2140 sids = NULL;
2141 num_groups = 0;
2143 result = pdb_enum_group_memberships(mem_ctx, sampw,
2144 &sids, &gids, &num_groups);
2146 if (!NT_STATUS_IS_OK(result)) {
2147 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2148 UserName));
2149 goto done;
2152 for (i=0; i<num_groups; i++) {
2154 const char *grp_name;
2156 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2157 pstrcpy(p, grp_name);
2158 p += 21;
2159 count++;
2163 *rdata_len = PTR_DIFF(p,*rdata);
2165 SSVAL(*rparam,4,count); /* is this right?? */
2166 SSVAL(*rparam,6,count); /* is this right?? */
2168 ret = True;
2170 done:
2171 unbecome_root(); /* END ROOT BLOCK */
2173 TALLOC_FREE(mem_ctx);
2175 return ret;
2178 /*******************************************************************
2179 Get all users.
2180 ******************************************************************/
2182 static BOOL api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2183 char *param, int tpscnt,
2184 char *data, int tdscnt,
2185 int mdrcnt,int mprcnt,
2186 char **rdata,char **rparam,
2187 int *rdata_len,int *rparam_len)
2189 int count_sent=0;
2190 int num_users=0;
2191 int errflags=0;
2192 int i, resume_context, cli_buf_size;
2193 struct pdb_search *search;
2194 struct samr_displayentry *users;
2196 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2197 char *str2 = skip_string(param,tpscnt,str1);
2198 char *p = skip_string(param,tpscnt,str2);
2200 if (!str1 || !str2 || !p) {
2201 return False;
2204 if (strcmp(str1,"WrLeh") != 0)
2205 return False;
2206 /* parameters
2207 * W-> resume context (number of users to skip)
2208 * r -> return parameter pointer to receive buffer
2209 * L -> length of receive buffer
2210 * e -> return parameter number of entries
2211 * h -> return parameter total number of users
2214 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2215 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2216 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2217 resume_context, cli_buf_size));
2219 *rparam_len = 8;
2220 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2221 if (!*rparam) {
2222 return False;
2225 /* check it's a supported varient */
2226 if (strcmp("B21",str2) != 0)
2227 return False;
2229 *rdata_len = cli_buf_size;
2230 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2231 if (!*rdata) {
2232 return False;
2235 p = *rdata;
2237 become_root();
2238 search = pdb_search_users(ACB_NORMAL);
2239 unbecome_root();
2240 if (search == NULL) {
2241 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2242 return False;
2245 become_root();
2246 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2247 &users);
2248 unbecome_root();
2250 errflags=NERR_Success;
2252 for (i=0; i<num_users; i++) {
2253 const char *name = users[i].account_name;
2255 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2256 pstrcpy(p,name);
2257 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2258 "%s\n",count_sent,p));
2259 p += 21;
2260 count_sent++;
2261 } else {
2262 /* set overflow error */
2263 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2264 "username %s\n",count_sent,name));
2265 errflags=234;
2266 break;
2270 pdb_search_destroy(search);
2272 *rdata_len = PTR_DIFF(p,*rdata);
2274 SSVAL(*rparam,0,errflags);
2275 SSVAL(*rparam,2,0); /* converter word */
2276 SSVAL(*rparam,4,count_sent); /* is this right?? */
2277 SSVAL(*rparam,6,num_users); /* is this right?? */
2279 return True;
2282 /****************************************************************************
2283 Get the time of day info.
2284 ****************************************************************************/
2286 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2287 char *param, int tpscnt,
2288 char *data, int tdscnt,
2289 int mdrcnt,int mprcnt,
2290 char **rdata,char **rparam,
2291 int *rdata_len,int *rparam_len)
2293 struct tm *t;
2294 time_t unixdate = time(NULL);
2295 char *p;
2297 *rparam_len = 4;
2298 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2299 if (!*rparam) {
2300 return False;
2303 *rdata_len = 21;
2304 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2305 if (!*rdata) {
2306 return False;
2309 SSVAL(*rparam,0,NERR_Success);
2310 SSVAL(*rparam,2,0); /* converter word */
2312 p = *rdata;
2314 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2315 by NT in a "net time" operation,
2316 it seems to ignore the one below */
2318 /* the client expects to get localtime, not GMT, in this bit
2319 (I think, this needs testing) */
2320 t = localtime(&unixdate);
2321 if (!t) {
2322 return False;
2325 SIVAL(p,4,0); /* msecs ? */
2326 SCVAL(p,8,t->tm_hour);
2327 SCVAL(p,9,t->tm_min);
2328 SCVAL(p,10,t->tm_sec);
2329 SCVAL(p,11,0); /* hundredths of seconds */
2330 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2331 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2332 SCVAL(p,16,t->tm_mday);
2333 SCVAL(p,17,t->tm_mon + 1);
2334 SSVAL(p,18,1900+t->tm_year);
2335 SCVAL(p,20,t->tm_wday);
2337 return True;
2340 /****************************************************************************
2341 Set the user password.
2342 *****************************************************************************/
2344 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid,
2345 char *param, int tpscnt,
2346 char *data, int tdscnt,
2347 int mdrcnt,int mprcnt,
2348 char **rdata,char **rparam,
2349 int *rdata_len,int *rparam_len)
2351 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2352 char *p = NULL;
2353 fstring user;
2354 fstring pass1,pass2;
2356 /* Skip 2 strings. */
2357 p = skip_string(param,tpscnt,np);
2358 p = skip_string(param,tpscnt,p);
2360 if (!np || !p) {
2361 return False;
2364 /* Do we have a string ? */
2365 if (skip_string(param,tpscnt,p) == NULL) {
2366 return False;
2368 pull_ascii_fstring(user,p);
2370 p = skip_string(param,tpscnt,p);
2371 if (!p) {
2372 return False;
2375 memset(pass1,'\0',sizeof(pass1));
2376 memset(pass2,'\0',sizeof(pass2));
2378 * We use 31 here not 32 as we're checking
2379 * the last byte we want to access is safe.
2381 if (!is_offset_safe(param,tpscnt,p,31)) {
2382 return False;
2384 memcpy(pass1,p,16);
2385 memcpy(pass2,p+16,16);
2387 *rparam_len = 4;
2388 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2389 if (!*rparam) {
2390 return False;
2393 *rdata_len = 0;
2395 SSVAL(*rparam,0,NERR_badpass);
2396 SSVAL(*rparam,2,0); /* converter word */
2398 DEBUG(3,("Set password for <%s>\n",user));
2401 * Attempt to verify the old password against smbpasswd entries
2402 * Win98 clients send old and new password in plaintext for this call.
2406 auth_serversupplied_info *server_info = NULL;
2407 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2409 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2411 become_root();
2412 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2413 SSVAL(*rparam,0,NERR_Success);
2415 unbecome_root();
2417 TALLOC_FREE(server_info);
2419 data_blob_clear_free(&password);
2423 * If the plaintext change failed, attempt
2424 * the old encrypted method. NT will generate this
2425 * after trying the samr method. Note that this
2426 * method is done as a last resort as this
2427 * password change method loses the NT password hash
2428 * and cannot change the UNIX password as no plaintext
2429 * is received.
2432 if(SVAL(*rparam,0) != NERR_Success) {
2433 struct samu *hnd = NULL;
2435 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2436 become_root();
2437 if (change_lanman_password(hnd,(uchar *)pass2)) {
2438 SSVAL(*rparam,0,NERR_Success);
2440 unbecome_root();
2441 TALLOC_FREE(hnd);
2445 memset((char *)pass1,'\0',sizeof(fstring));
2446 memset((char *)pass2,'\0',sizeof(fstring));
2448 return(True);
2451 /****************************************************************************
2452 Set the user password (SamOEM version - gets plaintext).
2453 ****************************************************************************/
2455 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2456 char *param, int tpscnt,
2457 char *data, int tdscnt,
2458 int mdrcnt,int mprcnt,
2459 char **rdata,char **rparam,
2460 int *rdata_len,int *rparam_len)
2462 fstring user;
2463 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2464 *rparam_len = 2;
2465 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2466 if (!*rparam) {
2467 return False;
2470 if (!p) {
2471 return False;
2473 *rdata_len = 0;
2475 SSVAL(*rparam,0,NERR_badpass);
2478 * Check the parameter definition is correct.
2481 /* Do we have a string ? */
2482 if (skip_string(param,tpscnt,p) == 0) {
2483 return False;
2485 if(!strequal(p, "zsT")) {
2486 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2487 return False;
2489 p = skip_string(param, tpscnt, p);
2490 if (!p) {
2491 return False;
2494 /* Do we have a string ? */
2495 if (skip_string(param,tpscnt,p) == 0) {
2496 return False;
2498 if(!strequal(p, "B516B16")) {
2499 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2500 return False;
2502 p = skip_string(param,tpscnt,p);
2503 if (!p) {
2504 return False;
2506 /* Do we have a string ? */
2507 if (skip_string(param,tpscnt,p) == 0) {
2508 return False;
2510 p += pull_ascii_fstring(user,p);
2512 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2515 * Pass the user through the NT -> unix user mapping
2516 * function.
2519 (void)map_username(user);
2521 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2522 SSVAL(*rparam,0,NERR_Success);
2525 return(True);
2528 /****************************************************************************
2529 delete a print job
2530 Form: <W> <>
2531 ****************************************************************************/
2533 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2534 char *param, int tpscnt,
2535 char *data, int tdscnt,
2536 int mdrcnt,int mprcnt,
2537 char **rdata,char **rparam,
2538 int *rdata_len,int *rparam_len)
2540 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2541 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2542 char *str2 = skip_string(param,tpscnt,str1);
2543 char *p = skip_string(param,tpscnt,str2);
2544 uint32 jobid;
2545 int snum;
2546 fstring sharename;
2547 int errcode;
2548 WERROR werr = WERR_OK;
2550 if (!str1 || !str2 || !p) {
2551 return False;
2554 * We use 1 here not 2 as we're checking
2555 * the last byte we want to access is safe.
2557 if (!is_offset_safe(param,tpscnt,p,1)) {
2558 return False;
2560 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2561 return False;
2563 /* check it's a supported varient */
2564 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2565 return(False);
2567 *rparam_len = 4;
2568 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2569 if (!*rparam) {
2570 return False;
2572 *rdata_len = 0;
2574 if (!print_job_exists(sharename, jobid)) {
2575 errcode = NERR_JobNotFound;
2576 goto out;
2579 snum = lp_servicenumber( sharename);
2580 if (snum == -1) {
2581 errcode = NERR_DestNotFound;
2582 goto out;
2585 errcode = NERR_notsupported;
2587 switch (function) {
2588 case 81: /* delete */
2589 if (print_job_delete(&current_user, snum, jobid, &werr))
2590 errcode = NERR_Success;
2591 break;
2592 case 82: /* pause */
2593 if (print_job_pause(&current_user, snum, jobid, &werr))
2594 errcode = NERR_Success;
2595 break;
2596 case 83: /* resume */
2597 if (print_job_resume(&current_user, snum, jobid, &werr))
2598 errcode = NERR_Success;
2599 break;
2602 if (!W_ERROR_IS_OK(werr))
2603 errcode = W_ERROR_V(werr);
2605 out:
2606 SSVAL(*rparam,0,errcode);
2607 SSVAL(*rparam,2,0); /* converter word */
2609 return(True);
2612 /****************************************************************************
2613 Purge a print queue - or pause or resume it.
2614 ****************************************************************************/
2616 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2617 char *param, int tpscnt,
2618 char *data, int tdscnt,
2619 int mdrcnt,int mprcnt,
2620 char **rdata,char **rparam,
2621 int *rdata_len,int *rparam_len)
2623 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2624 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2625 char *str2 = skip_string(param,tpscnt,str1);
2626 char *QueueName = skip_string(param,tpscnt,str2);
2627 int errcode = NERR_notsupported;
2628 int snum;
2629 WERROR werr = WERR_OK;
2631 if (!str1 || !str2 || !QueueName) {
2632 return False;
2635 /* check it's a supported varient */
2636 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2637 return(False);
2639 *rparam_len = 4;
2640 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2641 if (!*rparam) {
2642 return False;
2644 *rdata_len = 0;
2646 if (skip_string(param,tpscnt,QueueName) == NULL) {
2647 return False;
2649 snum = print_queue_snum(QueueName);
2651 if (snum == -1) {
2652 errcode = NERR_JobNotFound;
2653 goto out;
2656 switch (function) {
2657 case 74: /* Pause queue */
2658 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2659 break;
2660 case 75: /* Resume queue */
2661 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2662 break;
2663 case 103: /* Purge */
2664 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2665 break;
2668 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2670 out:
2671 SSVAL(*rparam,0,errcode);
2672 SSVAL(*rparam,2,0); /* converter word */
2674 return(True);
2677 /****************************************************************************
2678 set the property of a print job (undocumented?)
2679 ? function = 0xb -> set name of print job
2680 ? function = 0x6 -> move print job up/down
2681 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2682 or <WWsTP> <WB21BB16B10zWWzDDz>
2683 ****************************************************************************/
2685 static int check_printjob_info(struct pack_desc* desc,
2686 int uLevel, char* id)
2688 desc->subformat = NULL;
2689 switch( uLevel ) {
2690 case 0: desc->format = "W"; break;
2691 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2692 case 2: desc->format = "WWzWWDDzz"; break;
2693 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2694 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2695 default:
2696 DEBUG(0,("check_printjob_info: invalid level %d\n",
2697 uLevel ));
2698 return False;
2700 if (id == NULL || strcmp(desc->format,id) != 0) {
2701 DEBUG(0,("check_printjob_info: invalid format %s\n",
2702 id ? id : "<NULL>" ));
2703 return False;
2705 return True;
2708 static BOOL api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2709 char *param, int tpscnt,
2710 char *data, int tdscnt,
2711 int mdrcnt,int mprcnt,
2712 char **rdata,char **rparam,
2713 int *rdata_len,int *rparam_len)
2715 struct pack_desc desc;
2716 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2717 char *str2 = skip_string(param,tpscnt,str1);
2718 char *p = skip_string(param,tpscnt,str2);
2719 uint32 jobid;
2720 fstring sharename;
2721 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2722 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2723 int place, errcode;
2725 if (!str1 || !str2 || !p) {
2726 return False;
2729 * We use 1 here not 2 as we're checking
2730 * the last byte we want to access is safe.
2732 if (!is_offset_safe(param,tpscnt,p,1)) {
2733 return False;
2735 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2736 return False;
2737 *rparam_len = 4;
2738 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2739 if (!*rparam) {
2740 return False;
2743 if (!share_defined(sharename)) {
2744 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2745 sharename));
2746 return False;
2749 *rdata_len = 0;
2751 /* check it's a supported varient */
2752 if ((strcmp(str1,"WWsTP")) ||
2753 (!check_printjob_info(&desc,uLevel,str2)))
2754 return(False);
2756 if (!print_job_exists(sharename, jobid)) {
2757 errcode=NERR_JobNotFound;
2758 goto out;
2761 errcode = NERR_notsupported;
2763 switch (function) {
2764 case 0x6:
2765 /* change job place in the queue,
2766 data gives the new place */
2767 place = SVAL(data,0);
2768 if (print_job_set_place(sharename, jobid, place)) {
2769 errcode=NERR_Success;
2771 break;
2773 case 0xb:
2774 /* change print job name, data gives the name */
2775 if (print_job_set_name(sharename, jobid, data)) {
2776 errcode=NERR_Success;
2778 break;
2780 default:
2781 return False;
2784 out:
2785 SSVALS(*rparam,0,errcode);
2786 SSVAL(*rparam,2,0); /* converter word */
2788 return(True);
2792 /****************************************************************************
2793 Get info about the server.
2794 ****************************************************************************/
2796 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2797 char *param, int tpscnt,
2798 char *data, int tdscnt,
2799 int mdrcnt,int mprcnt,
2800 char **rdata,char **rparam,
2801 int *rdata_len,int *rparam_len)
2803 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2804 char *str2 = skip_string(param,tpscnt,str1);
2805 char *p = skip_string(param,tpscnt,str2);
2806 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2807 char *p2;
2808 int struct_len;
2810 if (!str1 || !str2 || !p) {
2811 return False;
2814 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2816 /* check it's a supported varient */
2817 if (!prefix_ok(str1,"WrLh")) {
2818 return False;
2821 switch( uLevel ) {
2822 case 0:
2823 if (strcmp(str2,"B16") != 0) {
2824 return False;
2826 struct_len = 16;
2827 break;
2828 case 1:
2829 if (strcmp(str2,"B16BBDz") != 0) {
2830 return False;
2832 struct_len = 26;
2833 break;
2834 case 2:
2835 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2836 return False;
2838 struct_len = 134;
2839 break;
2840 case 3:
2841 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2842 return False;
2844 struct_len = 144;
2845 break;
2846 case 20:
2847 if (strcmp(str2,"DN") != 0) {
2848 return False;
2850 struct_len = 6;
2851 break;
2852 case 50:
2853 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2854 return False;
2856 struct_len = 42;
2857 break;
2858 default:
2859 return False;
2862 *rdata_len = mdrcnt;
2863 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2864 if (!*rdata) {
2865 return False;
2868 p = *rdata;
2869 p2 = p + struct_len;
2870 if (uLevel != 20) {
2871 srvstr_push(NULL, p,global_myname(),16,
2872 STR_ASCII|STR_UPPER|STR_TERMINATE);
2874 p += 16;
2875 if (uLevel > 0) {
2876 struct srv_info_struct *servers=NULL;
2877 int i,count;
2878 pstring comment;
2879 uint32 servertype= lp_default_server_announce();
2881 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2883 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2884 for (i=0;i<count;i++) {
2885 if (strequal(servers[i].name,global_myname())) {
2886 servertype = servers[i].type;
2887 push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2892 SAFE_FREE(servers);
2894 SCVAL(p,0,lp_major_announce_version());
2895 SCVAL(p,1,lp_minor_announce_version());
2896 SIVAL(p,2,servertype);
2898 if (mdrcnt == struct_len) {
2899 SIVAL(p,6,0);
2900 } else {
2901 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2902 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2903 conn->connectpath, conn->gid,
2904 get_current_username(),
2905 current_user_info.domain,
2906 comment, sizeof(comment));
2907 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2908 p2 = skip_string(*rdata,*rdata_len,p2);
2909 if (!p2) {
2910 return False;
2915 if (uLevel > 1) {
2916 return False; /* not yet implemented */
2919 *rdata_len = PTR_DIFF(p2,*rdata);
2921 *rparam_len = 6;
2922 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2923 if (!*rparam) {
2924 return False;
2926 SSVAL(*rparam,0,NERR_Success);
2927 SSVAL(*rparam,2,0); /* converter word */
2928 SSVAL(*rparam,4,*rdata_len);
2930 return True;
2933 /****************************************************************************
2934 Get info about the server.
2935 ****************************************************************************/
2937 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
2938 char *param, int tpscnt,
2939 char *data, int tdscnt,
2940 int mdrcnt,int mprcnt,
2941 char **rdata,char **rparam,
2942 int *rdata_len,int *rparam_len)
2944 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2945 char *str2 = skip_string(param,tpscnt,str1);
2946 char *p = skip_string(param,tpscnt,str2);
2947 char *p2;
2948 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
2950 if (!str1 || !str2 || !p) {
2951 return False;
2954 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2956 *rparam_len = 6;
2957 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2958 if (!*rparam) {
2959 return False;
2962 /* check it's a supported varient */
2963 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2964 return False;
2967 *rdata_len = mdrcnt + 1024;
2968 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2969 if (!*rdata) {
2970 return False;
2973 SSVAL(*rparam,0,NERR_Success);
2974 SSVAL(*rparam,2,0); /* converter word */
2976 p = *rdata;
2977 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
2978 if (!p2) {
2979 return False;
2982 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2983 pstrcpy(p2,get_local_machine_name());
2984 strupper_m(p2);
2985 p2 = skip_string(*rdata,*rdata_len,p2);
2986 if (!p2) {
2987 return False;
2989 p += 4;
2991 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2992 pstrcpy(p2,current_user_info.smb_name);
2993 p2 = skip_string(*rdata,*rdata_len,p2);
2994 if (!p2) {
2995 return False;
2997 p += 4;
2999 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3000 pstrcpy(p2,lp_workgroup());
3001 strupper_m(p2);
3002 p2 = skip_string(*rdata,*rdata_len,p2);
3003 if (!p2) {
3004 return False;
3006 p += 4;
3008 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3009 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3010 p += 2;
3012 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3013 pstrcpy(p2,lp_workgroup()); /* don't know. login domain?? */
3014 p2 = skip_string(*rdata,*rdata_len,p2);
3015 if (!p2) {
3016 return False;
3018 p += 4;
3020 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3021 pstrcpy(p2,"");
3022 p2 = skip_string(*rdata,*rdata_len,p2);
3023 if (!p2) {
3024 return False;
3026 p += 4;
3028 *rdata_len = PTR_DIFF(p2,*rdata);
3030 SSVAL(*rparam,4,*rdata_len);
3032 return True;
3035 /****************************************************************************
3036 get info about a user
3038 struct user_info_11 {
3039 char usri11_name[21]; 0-20
3040 char usri11_pad; 21
3041 char *usri11_comment; 22-25
3042 char *usri11_usr_comment; 26-29
3043 unsigned short usri11_priv; 30-31
3044 unsigned long usri11_auth_flags; 32-35
3045 long usri11_password_age; 36-39
3046 char *usri11_homedir; 40-43
3047 char *usri11_parms; 44-47
3048 long usri11_last_logon; 48-51
3049 long usri11_last_logoff; 52-55
3050 unsigned short usri11_bad_pw_count; 56-57
3051 unsigned short usri11_num_logons; 58-59
3052 char *usri11_logon_server; 60-63
3053 unsigned short usri11_country_code; 64-65
3054 char *usri11_workstations; 66-69
3055 unsigned long usri11_max_storage; 70-73
3056 unsigned short usri11_units_per_week; 74-75
3057 unsigned char *usri11_logon_hours; 76-79
3058 unsigned short usri11_code_page; 80-81
3061 where:
3063 usri11_name specifies the user name for which information is retireved
3065 usri11_pad aligns the next data structure element to a word boundary
3067 usri11_comment is a null terminated ASCII comment
3069 usri11_user_comment is a null terminated ASCII comment about the user
3071 usri11_priv specifies the level of the privilege assigned to the user.
3072 The possible values are:
3074 Name Value Description
3075 USER_PRIV_GUEST 0 Guest privilege
3076 USER_PRIV_USER 1 User privilege
3077 USER_PRV_ADMIN 2 Administrator privilege
3079 usri11_auth_flags specifies the account operator privileges. The
3080 possible values are:
3082 Name Value Description
3083 AF_OP_PRINT 0 Print operator
3086 Leach, Naik [Page 28]
3090 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3093 AF_OP_COMM 1 Communications operator
3094 AF_OP_SERVER 2 Server operator
3095 AF_OP_ACCOUNTS 3 Accounts operator
3098 usri11_password_age specifies how many seconds have elapsed since the
3099 password was last changed.
3101 usri11_home_dir points to a null terminated ASCII string that contains
3102 the path name of the user's home directory.
3104 usri11_parms points to a null terminated ASCII string that is set
3105 aside for use by applications.
3107 usri11_last_logon specifies the time when the user last logged on.
3108 This value is stored as the number of seconds elapsed since
3109 00:00:00, January 1, 1970.
3111 usri11_last_logoff specifies the time when the user last logged off.
3112 This value is stored as the number of seconds elapsed since
3113 00:00:00, January 1, 1970. A value of 0 means the last logoff
3114 time is unknown.
3116 usri11_bad_pw_count specifies the number of incorrect passwords
3117 entered since the last successful logon.
3119 usri11_log1_num_logons specifies the number of times this user has
3120 logged on. A value of -1 means the number of logons is unknown.
3122 usri11_logon_server points to a null terminated ASCII string that
3123 contains the name of the server to which logon requests are sent.
3124 A null string indicates logon requests should be sent to the
3125 domain controller.
3127 usri11_country_code specifies the country code for the user's language
3128 of choice.
3130 usri11_workstations points to a null terminated ASCII string that
3131 contains the names of workstations the user may log on from.
3132 There may be up to 8 workstations, with the names separated by
3133 commas. A null strings indicates there are no restrictions.
3135 usri11_max_storage specifies the maximum amount of disk space the user
3136 can occupy. A value of 0xffffffff indicates there are no
3137 restrictions.
3139 usri11_units_per_week specifies the equal number of time units into
3140 which a week is divided. This value must be equal to 168.
3142 usri11_logon_hours points to a 21 byte (168 bits) string that
3143 specifies the time during which the user can log on. Each bit
3144 represents one unique hour in a week. The first bit (bit 0, word
3145 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3149 Leach, Naik [Page 29]
3153 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3156 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3157 are no restrictions.
3159 usri11_code_page specifies the code page for the user's language of
3160 choice
3162 All of the pointers in this data structure need to be treated
3163 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3164 to be ignored. The converter word returned in the parameters section
3165 needs to be subtracted from the lower 16 bits to calculate an offset
3166 into the return buffer where this ASCII string resides.
3168 There is no auxiliary data in the response.
3170 ****************************************************************************/
3172 #define usri11_name 0
3173 #define usri11_pad 21
3174 #define usri11_comment 22
3175 #define usri11_usr_comment 26
3176 #define usri11_full_name 30
3177 #define usri11_priv 34
3178 #define usri11_auth_flags 36
3179 #define usri11_password_age 40
3180 #define usri11_homedir 44
3181 #define usri11_parms 48
3182 #define usri11_last_logon 52
3183 #define usri11_last_logoff 56
3184 #define usri11_bad_pw_count 60
3185 #define usri11_num_logons 62
3186 #define usri11_logon_server 64
3187 #define usri11_country_code 68
3188 #define usri11_workstations 70
3189 #define usri11_max_storage 74
3190 #define usri11_units_per_week 78
3191 #define usri11_logon_hours 80
3192 #define usri11_code_page 84
3193 #define usri11_end 86
3195 #define USER_PRIV_GUEST 0
3196 #define USER_PRIV_USER 1
3197 #define USER_PRIV_ADMIN 2
3199 #define AF_OP_PRINT 0
3200 #define AF_OP_COMM 1
3201 #define AF_OP_SERVER 2
3202 #define AF_OP_ACCOUNTS 3
3205 static BOOL api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3206 char *param, int tpscnt,
3207 char *data, int tdscnt,
3208 int mdrcnt,int mprcnt,
3209 char **rdata,char **rparam,
3210 int *rdata_len,int *rparam_len)
3212 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3213 char *str2 = skip_string(param,tpscnt,str1);
3214 char *UserName = skip_string(param,tpscnt,str2);
3215 char *p = skip_string(param,tpscnt,UserName);
3216 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3217 char *p2;
3218 const char *level_string;
3220 /* get NIS home of a previously validated user - simeon */
3221 /* With share level security vuid will always be zero.
3222 Don't depend on vuser being non-null !!. JRA */
3223 user_struct *vuser = get_valid_user_struct(vuid);
3224 if(vuser != NULL) {
3225 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3226 vuser->user.unix_name));
3229 if (!str1 || !str2 || !UserName || !p) {
3230 return False;
3233 *rparam_len = 6;
3234 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3235 if (!*rparam) {
3236 return False;
3239 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3241 /* check it's a supported variant */
3242 if (strcmp(str1,"zWrLh") != 0) {
3243 return False;
3245 switch( uLevel ) {
3246 case 0: level_string = "B21"; break;
3247 case 1: level_string = "B21BB16DWzzWz"; break;
3248 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3249 case 10: level_string = "B21Bzzz"; break;
3250 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3251 default: return False;
3254 if (strcmp(level_string,str2) != 0) {
3255 return False;
3258 *rdata_len = mdrcnt + 1024;
3259 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
3260 if (!*rdata) {
3261 return False;
3264 SSVAL(*rparam,0,NERR_Success);
3265 SSVAL(*rparam,2,0); /* converter word */
3267 p = *rdata;
3268 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3269 if (!p2) {
3270 return False;
3273 memset(p,0,21);
3274 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3276 if (uLevel > 0) {
3277 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3278 *p2 = 0;
3281 if (uLevel >= 10) {
3282 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3283 pstrcpy(p2,"Comment");
3284 p2 = skip_string(*rdata,*rdata_len,p2);
3285 if (!p2) {
3286 return False;
3289 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3290 pstrcpy(p2,"UserComment");
3291 p2 = skip_string(*rdata,*rdata_len,p2);
3292 if (!p2) {
3293 return False;
3296 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3297 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3298 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3299 p2 = skip_string(*rdata,*rdata_len,p2);
3300 if (!p2) {
3301 return False;
3305 if (uLevel == 11) {
3306 /* modelled after NTAS 3.51 reply */
3307 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3308 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3309 SIVALS(p,usri11_password_age,-1); /* password age */
3310 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3311 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3312 p2 = skip_string(*rdata,*rdata_len,p2);
3313 if (!p2) {
3314 return False;
3316 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3317 pstrcpy(p2,"");
3318 p2 = skip_string(*rdata,*rdata_len,p2);
3319 if (!p2) {
3320 return False;
3322 SIVAL(p,usri11_last_logon,0); /* last logon */
3323 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3324 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3325 SSVALS(p,usri11_num_logons,-1); /* num logons */
3326 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3327 pstrcpy(p2,"\\\\*");
3328 p2 = skip_string(*rdata,*rdata_len,p2);
3329 if (!p2) {
3330 return False;
3332 SSVAL(p,usri11_country_code,0); /* country code */
3334 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3335 pstrcpy(p2,"");
3336 p2 = skip_string(*rdata,*rdata_len,p2);
3337 if (!p2) {
3338 return False;
3341 SIVALS(p,usri11_max_storage,-1); /* max storage */
3342 SSVAL(p,usri11_units_per_week,168); /* units per week */
3343 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3345 /* a simple way to get logon hours at all times. */
3346 memset(p2,0xff,21);
3347 SCVAL(p2,21,0); /* fix zero termination */
3348 p2 = skip_string(*rdata,*rdata_len,p2);
3349 if (!p2) {
3350 return False;
3353 SSVAL(p,usri11_code_page,0); /* code page */
3356 if (uLevel == 1 || uLevel == 2) {
3357 memset(p+22,' ',16); /* password */
3358 SIVALS(p,38,-1); /* password age */
3359 SSVAL(p,42,
3360 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3361 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3362 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3363 p2 = skip_string(*rdata,*rdata_len,p2);
3364 if (!p2) {
3365 return False;
3367 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3368 *p2++ = 0;
3369 SSVAL(p,52,0); /* flags */
3370 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3371 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3372 p2 = skip_string(*rdata,*rdata_len,p2);
3373 if (!p2) {
3374 return False;
3376 if (uLevel == 2) {
3377 SIVAL(p,60,0); /* auth_flags */
3378 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3379 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3380 p2 = skip_string(*rdata,*rdata_len,p2);
3381 if (!p2) {
3382 return False;
3384 SIVAL(p,68,0); /* urs_comment */
3385 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3386 pstrcpy(p2,"");
3387 p2 = skip_string(*rdata,*rdata_len,p2);
3388 if (!p2) {
3389 return False;
3391 SIVAL(p,76,0); /* workstations */
3392 SIVAL(p,80,0); /* last_logon */
3393 SIVAL(p,84,0); /* last_logoff */
3394 SIVALS(p,88,-1); /* acct_expires */
3395 SIVALS(p,92,-1); /* max_storage */
3396 SSVAL(p,96,168); /* units_per_week */
3397 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3398 memset(p2,-1,21);
3399 p2 += 21;
3400 SSVALS(p,102,-1); /* bad_pw_count */
3401 SSVALS(p,104,-1); /* num_logons */
3402 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3404 pstring tmp;
3405 pstrcpy(tmp, "\\\\%L");
3406 standard_sub_basic("", "", tmp, sizeof(tmp));
3407 pstrcpy(p2, tmp);
3409 p2 = skip_string(*rdata,*rdata_len,p2);
3410 if (!p2) {
3411 return False;
3413 SSVAL(p,110,49); /* country_code */
3414 SSVAL(p,112,860); /* code page */
3418 *rdata_len = PTR_DIFF(p2,*rdata);
3420 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3422 return(True);
3425 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3426 char *param, int tpscnt,
3427 char *data, int tdscnt,
3428 int mdrcnt,int mprcnt,
3429 char **rdata,char **rparam,
3430 int *rdata_len,int *rparam_len)
3432 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3433 char *str2 = skip_string(param,tpscnt,str1);
3434 char *p = skip_string(param,tpscnt,str2);
3435 int uLevel;
3436 struct pack_desc desc;
3437 char* name;
3438 /* With share level security vuid will always be zero.
3439 Don't depend on vuser being non-null !!. JRA */
3440 user_struct *vuser = get_valid_user_struct(vuid);
3442 if (!str1 || !str2 || !p) {
3443 return False;
3446 if(vuser != NULL) {
3447 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3448 vuser->user.unix_name));
3451 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3452 name = get_safe_str_ptr(param,tpscnt,p,2);
3453 if (!name) {
3454 return False;
3457 memset((char *)&desc,'\0',sizeof(desc));
3459 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3461 /* check it's a supported varient */
3462 if (strcmp(str1,"OOWb54WrLh") != 0) {
3463 return False;
3465 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3466 return False;
3468 if (mdrcnt > 0) {
3469 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3470 if (!*rdata) {
3471 return False;
3475 desc.base = *rdata;
3476 desc.buflen = mdrcnt;
3477 desc.subformat = NULL;
3478 desc.format = str2;
3480 if (init_package(&desc,1,0)) {
3481 PACKI(&desc,"W",0); /* code */
3482 PACKS(&desc,"B21",name); /* eff. name */
3483 PACKS(&desc,"B",""); /* pad */
3484 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3485 PACKI(&desc,"D",0); /* auth flags XXX */
3486 PACKI(&desc,"W",0); /* num logons */
3487 PACKI(&desc,"W",0); /* bad pw count */
3488 PACKI(&desc,"D",0); /* last logon */
3489 PACKI(&desc,"D",-1); /* last logoff */
3490 PACKI(&desc,"D",-1); /* logoff time */
3491 PACKI(&desc,"D",-1); /* kickoff time */
3492 PACKI(&desc,"D",0); /* password age */
3493 PACKI(&desc,"D",0); /* password can change */
3494 PACKI(&desc,"D",-1); /* password must change */
3497 fstring mypath;
3498 fstrcpy(mypath,"\\\\");
3499 fstrcat(mypath,get_local_machine_name());
3500 strupper_m(mypath);
3501 PACKS(&desc,"z",mypath); /* computer */
3504 PACKS(&desc,"z",lp_workgroup());/* domain */
3505 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3506 PACKI(&desc,"D",0x00000000); /* reserved */
3509 *rdata_len = desc.usedlen;
3510 *rparam_len = 6;
3511 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3512 if (!*rparam) {
3513 return False;
3515 SSVALS(*rparam,0,desc.errcode);
3516 SSVAL(*rparam,2,0);
3517 SSVAL(*rparam,4,desc.neededlen);
3519 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3521 return True;
3524 /****************************************************************************
3525 api_WAccessGetUserPerms
3526 ****************************************************************************/
3528 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3529 char *param, int tpscnt,
3530 char *data, int tdscnt,
3531 int mdrcnt,int mprcnt,
3532 char **rdata,char **rparam,
3533 int *rdata_len,int *rparam_len)
3535 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3536 char *str2 = skip_string(param,tpscnt,str1);
3537 char *user = skip_string(param,tpscnt,str2);
3538 char *resource = skip_string(param,tpscnt,user);
3540 if (!str1 || !str2 || !user || !resource) {
3541 return False;
3544 if (skip_string(param,tpscnt,resource) == NULL) {
3545 return False;
3547 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3549 /* check it's a supported varient */
3550 if (strcmp(str1,"zzh") != 0) {
3551 return False;
3553 if (strcmp(str2,"") != 0) {
3554 return False;
3557 *rparam_len = 6;
3558 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3559 if (!*rparam) {
3560 return False;
3562 SSVALS(*rparam,0,0); /* errorcode */
3563 SSVAL(*rparam,2,0); /* converter word */
3564 SSVAL(*rparam,4,0x7f); /* permission flags */
3566 return True;
3569 /****************************************************************************
3570 api_WPrintJobEnumerate
3571 ****************************************************************************/
3573 static BOOL api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3574 char *param, int tpscnt,
3575 char *data, int tdscnt,
3576 int mdrcnt,int mprcnt,
3577 char **rdata,char **rparam,
3578 int *rdata_len,int *rparam_len)
3580 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3581 char *str2 = skip_string(param,tpscnt,str1);
3582 char *p = skip_string(param,tpscnt,str2);
3583 int uLevel;
3584 int count;
3585 int i;
3586 int snum;
3587 fstring sharename;
3588 uint32 jobid;
3589 struct pack_desc desc;
3590 print_queue_struct *queue=NULL;
3591 print_status_struct status;
3592 char *tmpdata=NULL;
3594 if (!str1 || !str2 || !p) {
3595 return False;
3598 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3600 memset((char *)&desc,'\0',sizeof(desc));
3601 memset((char *)&status,'\0',sizeof(status));
3603 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3605 /* check it's a supported varient */
3606 if (strcmp(str1,"WWrLh") != 0) {
3607 return False;
3609 if (!check_printjob_info(&desc,uLevel,str2)) {
3610 return False;
3613 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3614 return False;
3617 snum = lp_servicenumber( sharename);
3618 if (snum < 0 || !VALID_SNUM(snum)) {
3619 return(False);
3622 count = print_queue_status(snum,&queue,&status);
3623 for (i = 0; i < count; i++) {
3624 if (queue[i].job == jobid) {
3625 break;
3629 if (mdrcnt > 0) {
3630 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3631 if (!*rdata) {
3632 return False;
3634 desc.base = *rdata;
3635 desc.buflen = mdrcnt;
3636 } else {
3638 * Don't return data but need to get correct length
3639 * init_package will return wrong size if buflen=0
3641 desc.buflen = getlen(desc.format);
3642 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3645 if (init_package(&desc,1,0)) {
3646 if (i < count) {
3647 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3648 *rdata_len = desc.usedlen;
3649 } else {
3650 desc.errcode = NERR_JobNotFound;
3651 *rdata_len = 0;
3655 *rparam_len = 6;
3656 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3657 if (!*rparam) {
3658 return False;
3660 SSVALS(*rparam,0,desc.errcode);
3661 SSVAL(*rparam,2,0);
3662 SSVAL(*rparam,4,desc.neededlen);
3664 SAFE_FREE(queue);
3665 SAFE_FREE(tmpdata);
3667 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3669 return True;
3672 static BOOL api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3673 char *param, int tpscnt,
3674 char *data, int tdscnt,
3675 int mdrcnt,int mprcnt,
3676 char **rdata,char **rparam,
3677 int *rdata_len,int *rparam_len)
3679 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3680 char *str2 = skip_string(param,tpscnt,str1);
3681 char *p = skip_string(param,tpscnt,str2);
3682 char *name = p;
3683 int uLevel;
3684 int count;
3685 int i, succnt=0;
3686 int snum;
3687 struct pack_desc desc;
3688 print_queue_struct *queue=NULL;
3689 print_status_struct status;
3691 if (!str1 || !str2 || !p) {
3692 return False;
3695 memset((char *)&desc,'\0',sizeof(desc));
3696 memset((char *)&status,'\0',sizeof(status));
3698 p = skip_string(param,tpscnt,p);
3699 if (!p) {
3700 return False;
3702 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3704 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3706 /* check it's a supported variant */
3707 if (strcmp(str1,"zWrLeh") != 0) {
3708 return False;
3711 if (uLevel > 2) {
3712 return False; /* defined only for uLevel 0,1,2 */
3715 if (!check_printjob_info(&desc,uLevel,str2)) {
3716 return False;
3719 snum = find_service(name);
3720 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3721 return False;
3724 count = print_queue_status(snum,&queue,&status);
3725 if (mdrcnt > 0) {
3726 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3727 if (!*rdata) {
3728 return False;
3731 desc.base = *rdata;
3732 desc.buflen = mdrcnt;
3734 if (init_package(&desc,count,0)) {
3735 succnt = 0;
3736 for (i = 0; i < count; i++) {
3737 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3738 if (desc.errcode == NERR_Success) {
3739 succnt = i+1;
3744 *rdata_len = desc.usedlen;
3746 *rparam_len = 8;
3747 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3748 if (!*rparam) {
3749 return False;
3751 SSVALS(*rparam,0,desc.errcode);
3752 SSVAL(*rparam,2,0);
3753 SSVAL(*rparam,4,succnt);
3754 SSVAL(*rparam,6,count);
3756 SAFE_FREE(queue);
3758 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3760 return True;
3763 static int check_printdest_info(struct pack_desc* desc,
3764 int uLevel, char* id)
3766 desc->subformat = NULL;
3767 switch( uLevel ) {
3768 case 0:
3769 desc->format = "B9";
3770 break;
3771 case 1:
3772 desc->format = "B9B21WWzW";
3773 break;
3774 case 2:
3775 desc->format = "z";
3776 break;
3777 case 3:
3778 desc->format = "zzzWWzzzWW";
3779 break;
3780 default:
3781 DEBUG(0,("check_printdest_info: invalid level %d\n",
3782 uLevel));
3783 return False;
3785 if (id == NULL || strcmp(desc->format,id) != 0) {
3786 DEBUG(0,("check_printdest_info: invalid string %s\n",
3787 id ? id : "<NULL>" ));
3788 return False;
3790 return True;
3793 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3794 struct pack_desc* desc)
3796 char buf[100];
3798 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3799 buf[sizeof(buf)-1] = 0;
3800 strupper_m(buf);
3802 if (uLevel <= 1) {
3803 PACKS(desc,"B9",buf); /* szName */
3804 if (uLevel == 1) {
3805 PACKS(desc,"B21",""); /* szUserName */
3806 PACKI(desc,"W",0); /* uJobId */
3807 PACKI(desc,"W",0); /* fsStatus */
3808 PACKS(desc,"z",""); /* pszStatus */
3809 PACKI(desc,"W",0); /* time */
3813 if (uLevel == 2 || uLevel == 3) {
3814 PACKS(desc,"z",buf); /* pszPrinterName */
3815 if (uLevel == 3) {
3816 PACKS(desc,"z",""); /* pszUserName */
3817 PACKS(desc,"z",""); /* pszLogAddr */
3818 PACKI(desc,"W",0); /* uJobId */
3819 PACKI(desc,"W",0); /* fsStatus */
3820 PACKS(desc,"z",""); /* pszStatus */
3821 PACKS(desc,"z",""); /* pszComment */
3822 PACKS(desc,"z","NULL"); /* pszDrivers */
3823 PACKI(desc,"W",0); /* time */
3824 PACKI(desc,"W",0); /* pad1 */
3829 static BOOL api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3830 char *param, int tpscnt,
3831 char *data, int tdscnt,
3832 int mdrcnt,int mprcnt,
3833 char **rdata,char **rparam,
3834 int *rdata_len,int *rparam_len)
3836 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3837 char *str2 = skip_string(param,tpscnt,str1);
3838 char *p = skip_string(param,tpscnt,str2);
3839 char* PrinterName = p;
3840 int uLevel;
3841 struct pack_desc desc;
3842 int snum;
3843 char *tmpdata=NULL;
3845 if (!str1 || !str2 || !p) {
3846 return False;
3849 memset((char *)&desc,'\0',sizeof(desc));
3851 p = skip_string(param,tpscnt,p);
3852 if (!p) {
3853 return False;
3855 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3857 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3859 /* check it's a supported varient */
3860 if (strcmp(str1,"zWrLh") != 0) {
3861 return False;
3863 if (!check_printdest_info(&desc,uLevel,str2)) {
3864 return False;
3867 snum = find_service(PrinterName);
3868 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3869 *rdata_len = 0;
3870 desc.errcode = NERR_DestNotFound;
3871 desc.neededlen = 0;
3872 } else {
3873 if (mdrcnt > 0) {
3874 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3875 if (!*rdata) {
3876 return False;
3878 desc.base = *rdata;
3879 desc.buflen = mdrcnt;
3880 } else {
3882 * Don't return data but need to get correct length
3883 * init_package will return wrong size if buflen=0
3885 desc.buflen = getlen(desc.format);
3886 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3888 if (init_package(&desc,1,0)) {
3889 fill_printdest_info(conn,snum,uLevel,&desc);
3891 *rdata_len = desc.usedlen;
3894 *rparam_len = 6;
3895 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3896 if (!*rparam) {
3897 return False;
3899 SSVALS(*rparam,0,desc.errcode);
3900 SSVAL(*rparam,2,0);
3901 SSVAL(*rparam,4,desc.neededlen);
3903 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3904 SAFE_FREE(tmpdata);
3906 return True;
3909 static BOOL api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
3910 char *param, int tpscnt,
3911 char *data, int tdscnt,
3912 int mdrcnt,int mprcnt,
3913 char **rdata,char **rparam,
3914 int *rdata_len,int *rparam_len)
3916 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3917 char *str2 = skip_string(param,tpscnt,str1);
3918 char *p = skip_string(param,tpscnt,str2);
3919 int uLevel;
3920 int queuecnt;
3921 int i, n, succnt=0;
3922 struct pack_desc desc;
3923 int services = lp_numservices();
3925 if (!str1 || !str2 || !p) {
3926 return False;
3929 memset((char *)&desc,'\0',sizeof(desc));
3931 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3933 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3935 /* check it's a supported varient */
3936 if (strcmp(str1,"WrLeh") != 0) {
3937 return False;
3939 if (!check_printdest_info(&desc,uLevel,str2)) {
3940 return False;
3943 queuecnt = 0;
3944 for (i = 0; i < services; i++) {
3945 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3946 queuecnt++;
3950 if (mdrcnt > 0) {
3951 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3952 if (!*rdata) {
3953 return False;
3957 desc.base = *rdata;
3958 desc.buflen = mdrcnt;
3959 if (init_package(&desc,queuecnt,0)) {
3960 succnt = 0;
3961 n = 0;
3962 for (i = 0; i < services; i++) {
3963 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3964 fill_printdest_info(conn,i,uLevel,&desc);
3965 n++;
3966 if (desc.errcode == NERR_Success) {
3967 succnt = n;
3973 *rdata_len = desc.usedlen;
3975 *rparam_len = 8;
3976 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3977 if (!*rparam) {
3978 return False;
3980 SSVALS(*rparam,0,desc.errcode);
3981 SSVAL(*rparam,2,0);
3982 SSVAL(*rparam,4,succnt);
3983 SSVAL(*rparam,6,queuecnt);
3985 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3987 return True;
3990 static BOOL api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
3991 char *param, int tpscnt,
3992 char *data, int tdscnt,
3993 int mdrcnt,int mprcnt,
3994 char **rdata,char **rparam,
3995 int *rdata_len,int *rparam_len)
3997 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3998 char *str2 = skip_string(param,tpscnt,str1);
3999 char *p = skip_string(param,tpscnt,str2);
4000 int uLevel;
4001 int succnt;
4002 struct pack_desc desc;
4004 if (!str1 || !str2 || !p) {
4005 return False;
4008 memset((char *)&desc,'\0',sizeof(desc));
4010 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4012 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4014 /* check it's a supported varient */
4015 if (strcmp(str1,"WrLeh") != 0) {
4016 return False;
4018 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4019 return False;
4022 if (mdrcnt > 0) {
4023 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4024 if (!*rdata) {
4025 return False;
4028 desc.base = *rdata;
4029 desc.buflen = mdrcnt;
4030 if (init_package(&desc,1,0)) {
4031 PACKS(&desc,"B41","NULL");
4034 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4036 *rdata_len = desc.usedlen;
4038 *rparam_len = 8;
4039 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4040 if (!*rparam) {
4041 return False;
4043 SSVALS(*rparam,0,desc.errcode);
4044 SSVAL(*rparam,2,0);
4045 SSVAL(*rparam,4,succnt);
4046 SSVAL(*rparam,6,1);
4048 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4050 return True;
4053 static BOOL api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4054 char *param, int tpscnt,
4055 char *data, int tdscnt,
4056 int mdrcnt,int mprcnt,
4057 char **rdata,char **rparam,
4058 int *rdata_len,int *rparam_len)
4060 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4061 char *str2 = skip_string(param,tpscnt,str1);
4062 char *p = skip_string(param,tpscnt,str2);
4063 int uLevel;
4064 int succnt;
4065 struct pack_desc desc;
4067 if (!str1 || !str2 || !p) {
4068 return False;
4070 memset((char *)&desc,'\0',sizeof(desc));
4072 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4074 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4076 /* check it's a supported varient */
4077 if (strcmp(str1,"WrLeh") != 0) {
4078 return False;
4080 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4081 return False;
4084 if (mdrcnt > 0) {
4085 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4086 if (!*rdata) {
4087 return False;
4090 desc.base = *rdata;
4091 desc.buflen = mdrcnt;
4092 desc.format = str2;
4093 if (init_package(&desc,1,0)) {
4094 PACKS(&desc,"B13","lpd");
4097 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4099 *rdata_len = desc.usedlen;
4101 *rparam_len = 8;
4102 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4103 if (!*rparam) {
4104 return False;
4106 SSVALS(*rparam,0,desc.errcode);
4107 SSVAL(*rparam,2,0);
4108 SSVAL(*rparam,4,succnt);
4109 SSVAL(*rparam,6,1);
4111 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4113 return True;
4116 static BOOL api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4117 char *param, int tpscnt,
4118 char *data, int tdscnt,
4119 int mdrcnt,int mprcnt,
4120 char **rdata,char **rparam,
4121 int *rdata_len,int *rparam_len)
4123 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4124 char *str2 = skip_string(param,tpscnt,str1);
4125 char *p = skip_string(param,tpscnt,str2);
4126 int uLevel;
4127 int succnt;
4128 struct pack_desc desc;
4130 if (!str1 || !str2 || !p) {
4131 return False;
4134 memset((char *)&desc,'\0',sizeof(desc));
4136 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4138 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4140 /* check it's a supported varient */
4141 if (strcmp(str1,"WrLeh") != 0) {
4142 return False;
4144 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4145 return False;
4148 if (mdrcnt > 0) {
4149 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4150 if (!*rdata) {
4151 return False;
4154 memset((char *)&desc,'\0',sizeof(desc));
4155 desc.base = *rdata;
4156 desc.buflen = mdrcnt;
4157 desc.format = str2;
4158 if (init_package(&desc,1,0)) {
4159 PACKS(&desc,"B13","lp0");
4162 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4164 *rdata_len = desc.usedlen;
4166 *rparam_len = 8;
4167 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4168 if (!*rparam) {
4169 return False;
4171 SSVALS(*rparam,0,desc.errcode);
4172 SSVAL(*rparam,2,0);
4173 SSVAL(*rparam,4,succnt);
4174 SSVAL(*rparam,6,1);
4176 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4178 return True;
4181 /****************************************************************************
4182 List open sessions
4183 ****************************************************************************/
4185 static BOOL api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4186 char *param, int tpscnt,
4187 char *data, int tdscnt,
4188 int mdrcnt,int mprcnt,
4189 char **rdata,char **rparam,
4190 int *rdata_len,int *rparam_len)
4193 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4194 char *str2 = skip_string(param,tpscnt,str1);
4195 char *p = skip_string(param,tpscnt,str2);
4196 int uLevel;
4197 struct pack_desc desc;
4198 struct sessionid *session_list = NULL;
4199 int i, num_sessions;
4201 if (!str1 || !str2 || !p) {
4202 return False;
4205 memset((char *)&desc,'\0',sizeof(desc));
4207 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4209 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4210 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4211 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4213 /* check it's a supported varient */
4214 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4215 return False;
4217 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4218 return False;
4221 num_sessions = list_sessions(&session_list);
4223 if (mdrcnt > 0) {
4224 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4225 if (!*rdata) {
4226 SAFE_FREE(session_list);
4227 return False;
4230 memset((char *)&desc,'\0',sizeof(desc));
4231 desc.base = *rdata;
4232 desc.buflen = mdrcnt;
4233 desc.format = str2;
4234 if (!init_package(&desc,num_sessions,0)) {
4235 SAFE_FREE(session_list);
4236 return False;
4239 for(i=0; i<num_sessions; i++) {
4240 PACKS(&desc, "z", session_list[i].remote_machine);
4241 PACKS(&desc, "z", session_list[i].username);
4242 PACKI(&desc, "W", 1); /* num conns */
4243 PACKI(&desc, "W", 0); /* num opens */
4244 PACKI(&desc, "W", 1); /* num users */
4245 PACKI(&desc, "D", 0); /* session time */
4246 PACKI(&desc, "D", 0); /* idle time */
4247 PACKI(&desc, "D", 0); /* flags */
4248 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4251 *rdata_len = desc.usedlen;
4253 *rparam_len = 8;
4254 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4255 if (!*rparam) {
4256 SAFE_FREE(session_list);
4257 return False;
4259 SSVALS(*rparam,0,desc.errcode);
4260 SSVAL(*rparam,2,0); /* converter */
4261 SSVAL(*rparam,4,num_sessions); /* count */
4263 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4265 SAFE_FREE(session_list);
4266 return True;
4270 /****************************************************************************
4271 The buffer was too small.
4272 ****************************************************************************/
4274 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4275 int mdrcnt, int mprcnt,
4276 char **rdata, char **rparam,
4277 int *rdata_len, int *rparam_len)
4279 *rparam_len = MIN(*rparam_len,mprcnt);
4280 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4281 if (!*rparam) {
4282 return False;
4285 *rdata_len = 0;
4287 SSVAL(*rparam,0,NERR_BufTooSmall);
4289 DEBUG(3,("Supplied buffer too small in API command\n"));
4291 return True;
4294 /****************************************************************************
4295 The request is not supported.
4296 ****************************************************************************/
4298 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
4299 char *param, int tpscnt,
4300 char *data, int tdscnt,
4301 int mdrcnt, int mprcnt,
4302 char **rdata, char **rparam,
4303 int *rdata_len, int *rparam_len)
4305 *rparam_len = 4;
4306 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4307 if (!*rparam) {
4308 return False;
4311 *rdata_len = 0;
4313 SSVAL(*rparam,0,NERR_notsupported);
4314 SSVAL(*rparam,2,0); /* converter word */
4316 DEBUG(3,("Unsupported API command\n"));
4318 return True;
4321 static const struct {
4322 const char *name;
4323 int id;
4324 BOOL (*fn)(connection_struct *, uint16,
4325 char *, int,
4326 char *, int,
4327 int,int,char **,char **,int *,int *);
4328 BOOL auth_user; /* Deny anonymous access? */
4329 } api_commands[] = {
4330 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4331 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4332 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4333 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4334 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4335 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4336 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4337 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4338 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4339 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4340 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4341 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4342 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4343 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4344 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4345 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4346 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4347 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4348 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4349 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4350 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4351 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4352 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4353 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4354 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4355 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4356 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4357 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4358 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4359 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4360 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4361 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4362 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4363 {NULL, -1, api_Unsupported}
4364 /* The following RAP calls are not implemented by Samba:
4366 RAP_WFileEnum2 - anon not OK
4371 /****************************************************************************
4372 Handle remote api calls
4373 ****************************************************************************/
4375 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
4376 int tdscnt,int tpscnt,int mdrcnt,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(outbuf, rparam, rparam_len, rdata, rdata_len, False);
4472 SAFE_FREE(rdata);
4473 SAFE_FREE(rparam);
4474 return -1;