r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[Samba/bb.git] / source / smbd / lanman.c
bloba7fe07b314cb03fc0b44d929600255e6cedb875f
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 3 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, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
30 extern struct current_user current_user;
31 extern userdom_struct current_user_info;
33 #ifdef CHECK_TYPES
34 #undef CHECK_TYPES
35 #endif
36 #define CHECK_TYPES 0
38 #define NERR_Success 0
39 #define NERR_badpass 86
40 #define NERR_notsupported 50
42 #define NERR_BASE (2100)
43 #define NERR_BufTooSmall (NERR_BASE+23)
44 #define NERR_JobNotFound (NERR_BASE+51)
45 #define NERR_DestNotFound (NERR_BASE+52)
47 #define ACCESS_READ 0x01
48 #define ACCESS_WRITE 0x02
49 #define ACCESS_CREATE 0x04
51 #define SHPWLEN 8 /* share password length */
53 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
54 char *param, int tpscnt,
55 char *data, int tdscnt,
56 int mdrcnt, int mprcnt,
57 char **rdata, char **rparam,
58 int *rdata_len, int *rparam_len);
60 static BOOL api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
61 int mdrcnt, int mprcnt,
62 char **rdata, char **rparam,
63 int *rdata_len, int *rparam_len);
66 static int CopyExpanded(connection_struct *conn,
67 int snum, char **dst, char *src, int *n)
69 pstring buf;
70 int l;
72 if (!src || !dst || !n || !(*dst)) {
73 return 0;
76 StrnCpy(buf,src,sizeof(buf)/2);
77 pstring_sub(buf,"%S",lp_servicename(snum));
78 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
79 conn->connectpath, conn->gid,
80 get_current_username(),
81 current_user_info.domain,
82 buf, sizeof(buf));
83 l = push_ascii(*dst,buf,*n, STR_TERMINATE);
84 (*dst) += l;
85 (*n) -= l;
86 return l;
89 static int CopyAndAdvance(char **dst, char *src, int *n)
91 int l;
92 if (!src || !dst || !n || !(*dst)) {
93 return 0;
95 l = push_ascii(*dst,src,*n, STR_TERMINATE);
96 (*dst) += l;
97 (*n) -= l;
98 return l;
101 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
103 pstring buf;
104 if (!s) {
105 return 0;
107 StrnCpy(buf,s,sizeof(buf)/2);
108 pstring_sub(buf,"%S",lp_servicename(snum));
109 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
110 conn->connectpath, conn->gid,
111 get_current_username(),
112 current_user_info.domain,
113 buf, sizeof(buf));
114 return strlen(buf) + 1;
117 static char *Expand(connection_struct *conn, int snum, char *s)
119 static pstring buf;
120 if (!s) {
121 return NULL;
123 StrnCpy(buf,s,sizeof(buf)/2);
124 pstring_sub(buf,"%S",lp_servicename(snum));
125 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
126 conn->connectpath, conn->gid,
127 get_current_username(),
128 current_user_info.domain,
129 buf, sizeof(buf));
130 return &buf[0];
133 /*******************************************************************
134 Check a API string for validity when we only need to check the prefix.
135 ******************************************************************/
137 static BOOL prefix_ok(const char *str, const char *prefix)
139 return(strncmp(str,prefix,strlen(prefix)) == 0);
142 struct pack_desc {
143 const char *format; /* formatstring for structure */
144 const char *subformat; /* subformat for structure */
145 char *base; /* baseaddress of buffer */
146 int buflen; /* remaining size for fixed part; on init: length of base */
147 int subcount; /* count of substructures */
148 char *structbuf; /* pointer into buffer for remaining fixed part */
149 int stringlen; /* remaining size for variable part */
150 char *stringbuf; /* pointer into buffer for remaining variable part */
151 int neededlen; /* total needed size */
152 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
153 const char *curpos; /* current position; pointer into format or subformat */
154 int errcode;
157 static int get_counter(const char **p)
159 int i, n;
160 if (!p || !(*p)) {
161 return 1;
163 if (!isdigit((int)**p)) {
164 return 1;
166 for (n = 0;;) {
167 i = **p;
168 if (isdigit(i)) {
169 n = 10 * n + (i - '0');
170 } else {
171 return n;
173 (*p)++;
177 static int getlen(const char *p)
179 int n = 0;
180 if (!p) {
181 return 0;
184 while (*p) {
185 switch( *p++ ) {
186 case 'W': /* word (2 byte) */
187 n += 2;
188 break;
189 case 'K': /* status word? (2 byte) */
190 n += 2;
191 break;
192 case 'N': /* count of substructures (word) at end */
193 n += 2;
194 break;
195 case 'D': /* double word (4 byte) */
196 case 'z': /* offset to zero terminated string (4 byte) */
197 case 'l': /* offset to user data (4 byte) */
198 n += 4;
199 break;
200 case 'b': /* offset to data (with counter) (4 byte) */
201 n += 4;
202 get_counter(&p);
203 break;
204 case 'B': /* byte (with optional counter) */
205 n += get_counter(&p);
206 break;
209 return n;
212 static BOOL init_package(struct pack_desc *p, int count, int subcount)
214 int n = p->buflen;
215 int i;
217 if (!p->format || !p->base) {
218 return False;
221 i = count * getlen(p->format);
222 if (p->subformat) {
223 i += subcount * getlen(p->subformat);
225 p->structbuf = p->base;
226 p->neededlen = 0;
227 p->usedlen = 0;
228 p->subcount = 0;
229 p->curpos = p->format;
230 if (i > n) {
231 p->neededlen = i;
232 i = n = 0;
233 #if 0
235 * This is the old error code we used. Aparently
236 * WinNT/2k systems return ERRbuftoosmall (2123) and
237 * OS/2 needs this. I'm leaving this here so we can revert
238 * if needed. JRA.
240 p->errcode = ERRmoredata;
241 #else
242 p->errcode = ERRbuftoosmall;
243 #endif
244 } else {
245 p->errcode = NERR_Success;
247 p->buflen = i;
248 n -= i;
249 p->stringbuf = p->base + i;
250 p->stringlen = n;
251 return (p->errcode == NERR_Success);
254 static int package(struct pack_desc *p, ...)
256 va_list args;
257 int needed=0, stringneeded;
258 const char *str=NULL;
259 int is_string=0, stringused;
260 int32 temp;
262 va_start(args,p);
264 if (!*p->curpos) {
265 if (!p->subcount) {
266 p->curpos = p->format;
267 } else {
268 p->curpos = p->subformat;
269 p->subcount--;
272 #if CHECK_TYPES
273 str = va_arg(args,char*);
274 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
275 #endif
276 stringneeded = -1;
278 if (!p->curpos) {
279 va_end(args);
280 return 0;
283 switch( *p->curpos++ ) {
284 case 'W': /* word (2 byte) */
285 needed = 2;
286 temp = va_arg(args,int);
287 if (p->buflen >= needed) {
288 SSVAL(p->structbuf,0,temp);
290 break;
291 case 'K': /* status 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 'N': /* count of substructures (word) at end */
299 needed = 2;
300 p->subcount = va_arg(args,int);
301 if (p->buflen >= needed) {
302 SSVAL(p->structbuf,0,p->subcount);
304 break;
305 case 'D': /* double word (4 byte) */
306 needed = 4;
307 temp = va_arg(args,int);
308 if (p->buflen >= needed) {
309 SIVAL(p->structbuf,0,temp);
311 break;
312 case 'B': /* byte (with optional counter) */
313 needed = get_counter(&p->curpos);
315 char *s = va_arg(args,char*);
316 if (p->buflen >= needed) {
317 StrnCpy(p->structbuf,s?s:"",needed-1);
320 break;
321 case 'z': /* offset to zero terminated string (4 byte) */
322 str = va_arg(args,char*);
323 stringneeded = (str ? strlen(str)+1 : 0);
324 is_string = 1;
325 break;
326 case 'l': /* offset to user data (4 byte) */
327 str = va_arg(args,char*);
328 stringneeded = va_arg(args,int);
329 is_string = 0;
330 break;
331 case 'b': /* offset to data (with counter) (4 byte) */
332 str = va_arg(args,char*);
333 stringneeded = get_counter(&p->curpos);
334 is_string = 0;
335 break;
338 va_end(args);
339 if (stringneeded >= 0) {
340 needed = 4;
341 if (p->buflen >= needed) {
342 stringused = stringneeded;
343 if (stringused > p->stringlen) {
344 stringused = (is_string ? p->stringlen : 0);
345 if (p->errcode == NERR_Success) {
346 p->errcode = ERRmoredata;
349 if (!stringused) {
350 SIVAL(p->structbuf,0,0);
351 } else {
352 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
353 memcpy(p->stringbuf,str?str:"",stringused);
354 if (is_string) {
355 p->stringbuf[stringused-1] = '\0';
357 p->stringbuf += stringused;
358 p->stringlen -= stringused;
359 p->usedlen += stringused;
362 p->neededlen += stringneeded;
365 p->neededlen += needed;
366 if (p->buflen >= needed) {
367 p->structbuf += needed;
368 p->buflen -= needed;
369 p->usedlen += needed;
370 } else {
371 if (p->errcode == NERR_Success) {
372 p->errcode = ERRmoredata;
375 return 1;
378 #if CHECK_TYPES
379 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
380 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
381 #else
382 #define PACK(desc,t,v) package(desc,v)
383 #define PACKl(desc,t,v,l) package(desc,v,l)
384 #endif
386 static void PACKI(struct pack_desc* desc, const char *t,int v)
388 PACK(desc,t,v);
391 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
393 PACK(desc,t,v);
396 /****************************************************************************
397 Get a print queue.
398 ****************************************************************************/
400 static void PackDriverData(struct pack_desc* desc)
402 char drivdata[4+4+32];
403 SIVAL(drivdata,0,sizeof drivdata); /* cb */
404 SIVAL(drivdata,4,1000); /* lVersion */
405 memset(drivdata+8,0,32); /* szDeviceName */
406 push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
407 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
410 static int check_printq_info(struct pack_desc* desc,
411 unsigned int uLevel, char *id1, char *id2)
413 desc->subformat = NULL;
414 switch( uLevel ) {
415 case 0:
416 desc->format = "B13";
417 break;
418 case 1:
419 desc->format = "B13BWWWzzzzzWW";
420 break;
421 case 2:
422 desc->format = "B13BWWWzzzzzWN";
423 desc->subformat = "WB21BB16B10zWWzDDz";
424 break;
425 case 3:
426 desc->format = "zWWWWzzzzWWzzl";
427 break;
428 case 4:
429 desc->format = "zWWWWzzzzWNzzl";
430 desc->subformat = "WWzWWDDzz";
431 break;
432 case 5:
433 desc->format = "z";
434 break;
435 case 51:
436 desc->format = "K";
437 break;
438 case 52:
439 desc->format = "WzzzzzzzzN";
440 desc->subformat = "z";
441 break;
442 default:
443 DEBUG(0,("check_printq_info: invalid level %d\n",
444 uLevel ));
445 return False;
447 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
448 DEBUG(0,("check_printq_info: invalid format %s\n",
449 id1 ? id1 : "<NULL>" ));
450 return False;
452 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
453 DEBUG(0,("check_printq_info: invalid subformat %s\n",
454 id2 ? id2 : "<NULL>" ));
455 return False;
457 return True;
461 #define RAP_JOB_STATUS_QUEUED 0
462 #define RAP_JOB_STATUS_PAUSED 1
463 #define RAP_JOB_STATUS_SPOOLING 2
464 #define RAP_JOB_STATUS_PRINTING 3
465 #define RAP_JOB_STATUS_PRINTED 4
467 #define RAP_QUEUE_STATUS_PAUSED 1
468 #define RAP_QUEUE_STATUS_ERROR 2
470 /* turn a print job status into a on the wire status
472 static int printj_status(int v)
474 switch (v) {
475 case LPQ_QUEUED:
476 return RAP_JOB_STATUS_QUEUED;
477 case LPQ_PAUSED:
478 return RAP_JOB_STATUS_PAUSED;
479 case LPQ_SPOOLING:
480 return RAP_JOB_STATUS_SPOOLING;
481 case LPQ_PRINTING:
482 return RAP_JOB_STATUS_PRINTING;
484 return 0;
487 /* turn a print queue status into a on the wire status
489 static int printq_status(int v)
491 switch (v) {
492 case LPQ_QUEUED:
493 return 0;
494 case LPQ_PAUSED:
495 return RAP_QUEUE_STATUS_PAUSED;
497 return RAP_QUEUE_STATUS_ERROR;
500 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
501 struct pack_desc *desc,
502 print_queue_struct *queue, int n)
504 time_t t = queue->time;
506 /* the client expects localtime */
507 t -= get_time_zone(t);
509 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
510 if (uLevel == 1) {
511 PACKS(desc,"B21",queue->fs_user); /* szUserName */
512 PACKS(desc,"B",""); /* pad */
513 PACKS(desc,"B16",""); /* szNotifyName */
514 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
515 PACKS(desc,"z",""); /* pszParms */
516 PACKI(desc,"W",n+1); /* uPosition */
517 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
518 PACKS(desc,"z",""); /* pszStatus */
519 PACKI(desc,"D",t); /* ulSubmitted */
520 PACKI(desc,"D",queue->size); /* ulSize */
521 PACKS(desc,"z",queue->fs_file); /* pszComment */
523 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
524 PACKI(desc,"W",queue->priority); /* uPriority */
525 PACKS(desc,"z",queue->fs_user); /* pszUserName */
526 PACKI(desc,"W",n+1); /* uPosition */
527 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
528 PACKI(desc,"D",t); /* ulSubmitted */
529 PACKI(desc,"D",queue->size); /* ulSize */
530 PACKS(desc,"z","Samba"); /* pszComment */
531 PACKS(desc,"z",queue->fs_file); /* pszDocument */
532 if (uLevel == 3) {
533 PACKS(desc,"z",""); /* pszNotifyName */
534 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
535 PACKS(desc,"z",""); /* pszParms */
536 PACKS(desc,"z",""); /* pszStatus */
537 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
538 PACKS(desc,"z","lpd"); /* pszQProcName */
539 PACKS(desc,"z",""); /* pszQProcParms */
540 PACKS(desc,"z","NULL"); /* pszDriverName */
541 PackDriverData(desc); /* pDriverData */
542 PACKS(desc,"z",""); /* pszPrinterName */
543 } else if (uLevel == 4) { /* OS2 */
544 PACKS(desc,"z",""); /* pszSpoolFileName */
545 PACKS(desc,"z",""); /* pszPortName */
546 PACKS(desc,"z",""); /* pszStatus */
547 PACKI(desc,"D",0); /* ulPagesSpooled */
548 PACKI(desc,"D",0); /* ulPagesSent */
549 PACKI(desc,"D",0); /* ulPagesPrinted */
550 PACKI(desc,"D",0); /* ulTimePrinted */
551 PACKI(desc,"D",0); /* ulExtendJobStatus */
552 PACKI(desc,"D",0); /* ulStartPage */
553 PACKI(desc,"D",0); /* ulEndPage */
558 /********************************************************************
559 Return a driver name given an snum.
560 Returns True if from tdb, False otherwise.
561 ********************************************************************/
563 static BOOL get_driver_name(int snum, pstring drivername)
565 NT_PRINTER_INFO_LEVEL *info = NULL;
566 BOOL in_tdb = False;
568 get_a_printer (NULL, &info, 2, lp_servicename(snum));
569 if (info != NULL) {
570 pstrcpy( drivername, info->info_2->drivername);
571 in_tdb = True;
572 free_a_printer(&info, 2);
575 return in_tdb;
578 /********************************************************************
579 Respond to the DosPrintQInfo command with a level of 52
580 This is used to get printer driver information for Win9x clients
581 ********************************************************************/
582 static void fill_printq_info_52(connection_struct *conn, int snum,
583 struct pack_desc* desc, int count )
585 int i;
586 fstring location;
587 NT_PRINTER_DRIVER_INFO_LEVEL driver;
588 NT_PRINTER_INFO_LEVEL *printer = NULL;
590 ZERO_STRUCT(driver);
592 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
593 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
594 lp_servicename(snum)));
595 goto err;
598 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
599 "Windows 4.0", 0)) )
601 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
602 printer->info_2->drivername));
603 goto err;
606 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
607 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
608 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
610 PACKI(desc, "W", 0x0400); /* don't know */
611 PACKS(desc, "z", driver.info_3->name); /* long printer name */
612 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
613 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
614 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
616 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
617 standard_sub_basic( "", "", location, sizeof(location)-1 );
618 PACKS(desc,"z", location); /* share to retrieve files */
620 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
621 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
622 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
624 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
625 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
626 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
627 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
628 DEBUG(3,("Driver Location: %s:\n",location));
629 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
630 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
631 PACKI(desc,"N",count); /* number of files to copy */
633 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
635 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
636 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
637 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
640 /* sanity check */
641 if ( i != count )
642 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
643 count, i));
645 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
647 desc->errcode=NERR_Success;
648 goto done;
650 err:
651 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
652 desc->errcode=NERR_notsupported;
654 done:
655 if ( printer )
656 free_a_printer( &printer, 2 );
658 if ( driver.info_3 )
659 free_a_printer_driver( driver, 3 );
663 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
664 struct pack_desc* desc,
665 int count, print_queue_struct* queue,
666 print_status_struct* status)
668 switch (uLevel) {
669 case 1:
670 case 2:
671 PACKS(desc,"B13",SERVICE(snum));
672 break;
673 case 3:
674 case 4:
675 case 5:
676 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
677 break;
678 case 51:
679 PACKI(desc,"K",printq_status(status->status));
680 break;
683 if (uLevel == 1 || uLevel == 2) {
684 PACKS(desc,"B",""); /* alignment */
685 PACKI(desc,"W",5); /* priority */
686 PACKI(desc,"W",0); /* start time */
687 PACKI(desc,"W",0); /* until time */
688 PACKS(desc,"z",""); /* pSepFile */
689 PACKS(desc,"z","lpd"); /* pPrProc */
690 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
691 PACKS(desc,"z",""); /* pParms */
692 if (snum < 0) {
693 PACKS(desc,"z","UNKNOWN PRINTER");
694 PACKI(desc,"W",LPSTAT_ERROR);
696 else if (!status || !status->message[0]) {
697 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
698 PACKI(desc,"W",LPSTAT_OK); /* status */
699 } else {
700 PACKS(desc,"z",status->message);
701 PACKI(desc,"W",printq_status(status->status)); /* status */
703 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
706 if (uLevel == 3 || uLevel == 4) {
707 pstring drivername;
709 PACKI(desc,"W",5); /* uPriority */
710 PACKI(desc,"W",0); /* uStarttime */
711 PACKI(desc,"W",0); /* uUntiltime */
712 PACKI(desc,"W",5); /* pad1 */
713 PACKS(desc,"z",""); /* pszSepFile */
714 PACKS(desc,"z","WinPrint"); /* pszPrProc */
715 PACKS(desc,"z",NULL); /* pszParms */
716 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
717 /* "don't ask" that it's done this way to fix corrupted
718 Win9X/ME printer comments. */
719 if (!status) {
720 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
721 } else {
722 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
724 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
725 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
726 get_driver_name(snum,drivername);
727 PACKS(desc,"z",drivername); /* pszDriverName */
728 PackDriverData(desc); /* pDriverData */
731 if (uLevel == 2 || uLevel == 4) {
732 int i;
733 for (i=0;i<count;i++)
734 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
737 if (uLevel==52)
738 fill_printq_info_52( conn, snum, desc, count );
741 /* This function returns the number of files for a given driver */
742 static int get_printerdrivernumber(int snum)
744 int result = 0;
745 NT_PRINTER_DRIVER_INFO_LEVEL driver;
746 NT_PRINTER_INFO_LEVEL *printer = NULL;
748 ZERO_STRUCT(driver);
750 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
751 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
752 lp_servicename(snum)));
753 goto done;
756 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
757 "Windows 4.0", 0)) )
759 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
760 printer->info_2->drivername));
761 goto done;
764 /* count the number of files */
765 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
766 result++;
768 done:
769 if ( printer )
770 free_a_printer( &printer, 2 );
772 if ( driver.info_3 )
773 free_a_printer_driver( driver, 3 );
775 return result;
778 static BOOL api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
779 char *param, int tpscnt,
780 char *data, int tdscnt,
781 int mdrcnt,int mprcnt,
782 char **rdata,char **rparam,
783 int *rdata_len,int *rparam_len)
785 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
786 char *str2 = skip_string(param,tpscnt,str1);
787 char *p = skip_string(param,tpscnt,str2);
788 char *QueueName = p;
789 unsigned int uLevel;
790 int count=0;
791 int snum;
792 char *str3;
793 struct pack_desc desc;
794 print_queue_struct *queue=NULL;
795 print_status_struct status;
796 char* tmpdata=NULL;
798 if (!str1 || !str2 || !p) {
799 return False;
801 memset((char *)&status,'\0',sizeof(status));
802 memset((char *)&desc,'\0',sizeof(desc));
804 p = skip_string(param,tpscnt,p);
805 if (!p) {
806 return False;
808 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
809 str3 = get_safe_str_ptr(param,tpscnt,p,4);
810 /* str3 may be null here and is checked in check_printq_info(). */
812 /* remove any trailing username */
813 if ((p = strchr_m(QueueName,'%')))
814 *p = 0;
816 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
818 /* check it's a supported varient */
819 if (!prefix_ok(str1,"zWrLh"))
820 return False;
821 if (!check_printq_info(&desc,uLevel,str2,str3)) {
823 * Patch from Scott Moomaw <scott@bridgewater.edu>
824 * to return the 'invalid info level' error if an
825 * unknown level was requested.
827 *rdata_len = 0;
828 *rparam_len = 6;
829 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
830 if (!*rparam) {
831 return False;
833 SSVALS(*rparam,0,ERRunknownlevel);
834 SSVAL(*rparam,2,0);
835 SSVAL(*rparam,4,0);
836 return(True);
839 snum = find_service(QueueName);
840 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
841 return False;
843 if (uLevel==52) {
844 count = get_printerdrivernumber(snum);
845 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
846 } else {
847 count = print_queue_status(snum, &queue,&status);
850 if (mdrcnt > 0) {
851 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
852 if (!*rdata) {
853 return False;
855 desc.base = *rdata;
856 desc.buflen = mdrcnt;
857 } else {
859 * Don't return data but need to get correct length
860 * init_package will return wrong size if buflen=0
862 desc.buflen = getlen(desc.format);
863 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
866 if (init_package(&desc,1,count)) {
867 desc.subcount = count;
868 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
871 *rdata_len = desc.usedlen;
874 * We must set the return code to ERRbuftoosmall
875 * in order to support lanman style printing with Win NT/2k
876 * clients --jerry
878 if (!mdrcnt && lp_disable_spoolss())
879 desc.errcode = ERRbuftoosmall;
881 *rdata_len = desc.usedlen;
882 *rparam_len = 6;
883 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
884 if (!*rparam) {
885 return False;
887 SSVALS(*rparam,0,desc.errcode);
888 SSVAL(*rparam,2,0);
889 SSVAL(*rparam,4,desc.neededlen);
891 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
893 SAFE_FREE(queue);
894 SAFE_FREE(tmpdata);
896 return(True);
899 /****************************************************************************
900 View list of all print jobs on all queues.
901 ****************************************************************************/
903 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
904 char *param, int tpscnt,
905 char *data, int tdscnt,
906 int mdrcnt, int mprcnt,
907 char **rdata, char** rparam,
908 int *rdata_len, int *rparam_len)
910 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
911 char *output_format1 = skip_string(param,tpscnt,param_format);
912 char *p = skip_string(param,tpscnt,output_format1);
913 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
914 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
915 int services = lp_numservices();
916 int i, n;
917 struct pack_desc desc;
918 print_queue_struct **queue = NULL;
919 print_status_struct *status = NULL;
920 int *subcntarr = NULL;
921 int queuecnt = 0, subcnt = 0, succnt = 0;
923 if (!param_format || !output_format1 || !p) {
924 return False;
927 memset((char *)&desc,'\0',sizeof(desc));
929 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
931 if (!prefix_ok(param_format,"WrLeh")) {
932 return False;
934 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
936 * Patch from Scott Moomaw <scott@bridgewater.edu>
937 * to return the 'invalid info level' error if an
938 * unknown level was requested.
940 *rdata_len = 0;
941 *rparam_len = 6;
942 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
943 if (!*rparam) {
944 return False;
946 SSVALS(*rparam,0,ERRunknownlevel);
947 SSVAL(*rparam,2,0);
948 SSVAL(*rparam,4,0);
949 return(True);
952 for (i = 0; i < services; i++) {
953 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
954 queuecnt++;
958 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
959 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
960 goto err;
962 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
963 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
964 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
965 goto err;
967 memset(status,0,queuecnt*sizeof(print_status_struct));
968 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
969 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
970 goto err;
973 subcnt = 0;
974 n = 0;
975 for (i = 0; i < services; i++) {
976 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
977 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
978 subcnt += subcntarr[n];
979 n++;
983 if (mdrcnt > 0) {
984 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
985 if (!*rdata) {
986 goto err;
989 desc.base = *rdata;
990 desc.buflen = mdrcnt;
992 if (init_package(&desc,queuecnt,subcnt)) {
993 n = 0;
994 succnt = 0;
995 for (i = 0; i < services; i++) {
996 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
997 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
998 n++;
999 if (desc.errcode == NERR_Success) {
1000 succnt = n;
1006 SAFE_FREE(subcntarr);
1008 *rdata_len = desc.usedlen;
1009 *rparam_len = 8;
1010 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1011 if (!*rparam) {
1012 goto err;
1014 SSVALS(*rparam,0,desc.errcode);
1015 SSVAL(*rparam,2,0);
1016 SSVAL(*rparam,4,succnt);
1017 SSVAL(*rparam,6,queuecnt);
1019 for (i = 0; i < queuecnt; i++) {
1020 if (queue) {
1021 SAFE_FREE(queue[i]);
1025 SAFE_FREE(queue);
1026 SAFE_FREE(status);
1028 return True;
1030 err:
1032 SAFE_FREE(subcntarr);
1033 for (i = 0; i < queuecnt; i++) {
1034 if (queue) {
1035 SAFE_FREE(queue[i]);
1038 SAFE_FREE(queue);
1039 SAFE_FREE(status);
1041 return False;
1044 /****************************************************************************
1045 Get info level for a server list query.
1046 ****************************************************************************/
1048 static BOOL check_server_info(int uLevel, char* id)
1050 switch( uLevel ) {
1051 case 0:
1052 if (strcmp(id,"B16") != 0) {
1053 return False;
1055 break;
1056 case 1:
1057 if (strcmp(id,"B16BBDz") != 0) {
1058 return False;
1060 break;
1061 default:
1062 return False;
1064 return True;
1067 struct srv_info_struct {
1068 fstring name;
1069 uint32 type;
1070 fstring comment;
1071 fstring domain;
1072 BOOL server_added;
1075 /*******************************************************************
1076 Get server info lists from the files saved by nmbd. Return the
1077 number of entries.
1078 ******************************************************************/
1080 static int get_server_info(uint32 servertype,
1081 struct srv_info_struct **servers,
1082 const char *domain)
1084 int count=0;
1085 int alloced=0;
1086 char **lines;
1087 BOOL local_list_only;
1088 int i;
1090 lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1091 if (!lines) {
1092 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1093 return 0;
1096 /* request for everything is code for request all servers */
1097 if (servertype == SV_TYPE_ALL) {
1098 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1101 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1103 DEBUG(4,("Servertype search: %8x\n",servertype));
1105 for (i=0;lines[i];i++) {
1106 fstring stype;
1107 struct srv_info_struct *s;
1108 const char *ptr = lines[i];
1109 BOOL ok = True;
1111 if (!*ptr) {
1112 continue;
1115 if (count == alloced) {
1116 alloced += 10;
1117 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1118 if (!*servers) {
1119 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1120 file_lines_free(lines);
1121 return 0;
1123 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1125 s = &(*servers)[count];
1127 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1128 continue;
1130 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1131 continue;
1133 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1134 continue;
1136 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1137 /* this allows us to cope with an old nmbd */
1138 fstrcpy(s->domain,lp_workgroup());
1141 if (sscanf(stype,"%X",&s->type) != 1) {
1142 DEBUG(4,("r:host file "));
1143 ok = False;
1146 /* Filter the servers/domains we return based on what was asked for. */
1148 /* Check to see if we are being asked for a local list only. */
1149 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1150 DEBUG(4,("r: local list only"));
1151 ok = False;
1154 /* doesn't match up: don't want it */
1155 if (!(servertype & s->type)) {
1156 DEBUG(4,("r:serv type "));
1157 ok = False;
1160 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1161 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1162 DEBUG(4,("s: dom mismatch "));
1163 ok = False;
1166 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1167 ok = False;
1170 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1171 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1173 if (ok) {
1174 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1175 s->name, s->type, s->comment, s->domain));
1176 s->server_added = True;
1177 count++;
1178 } else {
1179 DEBUG(4,("%20s %8x %25s %15s\n",
1180 s->name, s->type, s->comment, s->domain));
1184 file_lines_free(lines);
1185 return count;
1188 /*******************************************************************
1189 Fill in a server info structure.
1190 ******************************************************************/
1192 static int fill_srv_info(struct srv_info_struct *service,
1193 int uLevel, char **buf, int *buflen,
1194 char **stringbuf, int *stringspace, char *baseaddr)
1196 int struct_len;
1197 char* p;
1198 char* p2;
1199 int l2;
1200 int len;
1202 switch (uLevel) {
1203 case 0:
1204 struct_len = 16;
1205 break;
1206 case 1:
1207 struct_len = 26;
1208 break;
1209 default:
1210 return -1;
1213 if (!buf) {
1214 len = 0;
1215 switch (uLevel) {
1216 case 1:
1217 len = strlen(service->comment)+1;
1218 break;
1221 *buflen = struct_len;
1222 *stringspace = len;
1223 return struct_len + len;
1226 len = struct_len;
1227 p = *buf;
1228 if (*buflen < struct_len) {
1229 return -1;
1231 if (stringbuf) {
1232 p2 = *stringbuf;
1233 l2 = *stringspace;
1234 } else {
1235 p2 = p + struct_len;
1236 l2 = *buflen - struct_len;
1238 if (!baseaddr) {
1239 baseaddr = p;
1242 switch (uLevel) {
1243 case 0:
1244 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1245 break;
1247 case 1:
1248 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1249 SIVAL(p,18,service->type);
1250 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1251 len += CopyAndAdvance(&p2,service->comment,&l2);
1252 break;
1255 if (stringbuf) {
1256 *buf = p + struct_len;
1257 *buflen -= struct_len;
1258 *stringbuf = p2;
1259 *stringspace = l2;
1260 } else {
1261 *buf = p2;
1262 *buflen -= len;
1264 return len;
1268 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1270 return(strcmp(s1->name,s2->name));
1273 /****************************************************************************
1274 View list of servers available (or possibly domains). The info is
1275 extracted from lists saved by nmbd on the local host.
1276 ****************************************************************************/
1278 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1279 char *param, int tpscnt,
1280 char *data, int tdscnt,
1281 int mdrcnt, int mprcnt, char **rdata,
1282 char **rparam, int *rdata_len, int *rparam_len)
1284 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1285 char *str2 = skip_string(param,tpscnt,str1);
1286 char *p = skip_string(param,tpscnt,str2);
1287 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1288 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1289 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1290 char *p2;
1291 int data_len, fixed_len, string_len;
1292 int f_len = 0, s_len = 0;
1293 struct srv_info_struct *servers=NULL;
1294 int counted=0,total=0;
1295 int i,missed;
1296 fstring domain;
1297 BOOL domain_request;
1298 BOOL local_request;
1300 if (!str1 || !str2 || !p) {
1301 return False;
1304 /* If someone sets all the bits they don't really mean to set
1305 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1306 known servers. */
1308 if (servertype == SV_TYPE_ALL) {
1309 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1312 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1313 any other bit (they may just set this bit on it's own) they
1314 want all the locally seen servers. However this bit can be
1315 set on its own so set the requested servers to be
1316 ALL - DOMAIN_ENUM. */
1318 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1319 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1322 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1323 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1325 p += 8;
1327 if (!prefix_ok(str1,"WrLehD")) {
1328 return False;
1330 if (!check_server_info(uLevel,str2)) {
1331 return False;
1334 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1335 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1336 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1338 if (strcmp(str1, "WrLehDz") == 0) {
1339 if (skip_string(param,tpscnt,p) == NULL) {
1340 return False;
1342 pull_ascii_fstring(domain, p);
1343 } else {
1344 fstrcpy(domain, lp_workgroup());
1347 if (lp_browse_list()) {
1348 total = get_server_info(servertype,&servers,domain);
1351 data_len = fixed_len = string_len = 0;
1352 missed = 0;
1354 if (total > 0) {
1355 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1359 char *lastname=NULL;
1361 for (i=0;i<total;i++) {
1362 struct srv_info_struct *s = &servers[i];
1364 if (lastname && strequal(lastname,s->name)) {
1365 continue;
1367 lastname = s->name;
1368 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1369 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1370 s->name, s->type, s->comment, s->domain));
1372 if (data_len <= buf_len) {
1373 counted++;
1374 fixed_len += f_len;
1375 string_len += s_len;
1376 } else {
1377 missed++;
1382 *rdata_len = fixed_len + string_len;
1383 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1384 if (!*rdata) {
1385 return False;
1387 memset(*rdata,'\0',*rdata_len);
1389 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1390 p = *rdata;
1391 f_len = fixed_len;
1392 s_len = string_len;
1395 char *lastname=NULL;
1396 int count2 = counted;
1398 for (i = 0; i < total && count2;i++) {
1399 struct srv_info_struct *s = &servers[i];
1401 if (lastname && strequal(lastname,s->name)) {
1402 continue;
1404 lastname = s->name;
1405 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1406 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1407 s->name, s->type, s->comment, s->domain));
1408 count2--;
1412 *rparam_len = 8;
1413 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1414 if (!*rparam) {
1415 return False;
1417 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1418 SSVAL(*rparam,2,0);
1419 SSVAL(*rparam,4,counted);
1420 SSVAL(*rparam,6,counted+missed);
1422 SAFE_FREE(servers);
1424 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1425 domain,uLevel,counted,counted+missed));
1427 return True;
1430 /****************************************************************************
1431 command 0x34 - suspected of being a "Lookup Names" stub api
1432 ****************************************************************************/
1434 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1435 char *param, int tpscnt,
1436 char *data, int tdscnt,
1437 int mdrcnt, int mprcnt, char **rdata,
1438 char **rparam, int *rdata_len, int *rparam_len)
1440 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1441 char *str2 = skip_string(param,tpscnt,str1);
1442 char *p = skip_string(param,tpscnt,str2);
1443 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1444 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1445 int counted=0;
1446 int missed=0;
1448 if (!str1 || !str2 || !p) {
1449 return False;
1452 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1453 str1, str2, p, uLevel, buf_len));
1455 if (!prefix_ok(str1,"zWrLeh")) {
1456 return False;
1459 *rdata_len = 0;
1461 *rparam_len = 8;
1462 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1463 if (!*rparam) {
1464 return False;
1467 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1468 SSVAL(*rparam,2,0);
1469 SSVAL(*rparam,4,counted);
1470 SSVAL(*rparam,6,counted+missed);
1472 return True;
1475 /****************************************************************************
1476 get info about a share
1477 ****************************************************************************/
1479 static BOOL check_share_info(int uLevel, char* id)
1481 switch( uLevel ) {
1482 case 0:
1483 if (strcmp(id,"B13") != 0) {
1484 return False;
1486 break;
1487 case 1:
1488 if (strcmp(id,"B13BWz") != 0) {
1489 return False;
1491 break;
1492 case 2:
1493 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1494 return False;
1496 break;
1497 case 91:
1498 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1499 return False;
1501 break;
1502 default:
1503 return False;
1505 return True;
1508 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1509 char** buf, int* buflen,
1510 char** stringbuf, int* stringspace, char* baseaddr)
1512 int struct_len;
1513 char* p;
1514 char* p2;
1515 int l2;
1516 int len;
1518 switch( uLevel ) {
1519 case 0:
1520 struct_len = 13;
1521 break;
1522 case 1:
1523 struct_len = 20;
1524 break;
1525 case 2:
1526 struct_len = 40;
1527 break;
1528 case 91:
1529 struct_len = 68;
1530 break;
1531 default:
1532 return -1;
1536 if (!buf) {
1537 len = 0;
1539 if (uLevel > 0) {
1540 len += StrlenExpanded(conn,snum,lp_comment(snum));
1542 if (uLevel > 1) {
1543 len += strlen(lp_pathname(snum)) + 1;
1545 if (buflen) {
1546 *buflen = struct_len;
1548 if (stringspace) {
1549 *stringspace = len;
1551 return struct_len + len;
1554 len = struct_len;
1555 p = *buf;
1556 if ((*buflen) < struct_len) {
1557 return -1;
1560 if (stringbuf) {
1561 p2 = *stringbuf;
1562 l2 = *stringspace;
1563 } else {
1564 p2 = p + struct_len;
1565 l2 = (*buflen) - struct_len;
1568 if (!baseaddr) {
1569 baseaddr = p;
1572 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1574 if (uLevel > 0) {
1575 int type;
1577 SCVAL(p,13,0);
1578 type = STYPE_DISKTREE;
1579 if (lp_print_ok(snum)) {
1580 type = STYPE_PRINTQ;
1582 if (strequal("IPC",lp_fstype(snum))) {
1583 type = STYPE_IPC;
1585 SSVAL(p,14,type); /* device type */
1586 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1587 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1590 if (uLevel > 1) {
1591 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1592 SSVALS(p,22,-1); /* max uses */
1593 SSVAL(p,24,1); /* current uses */
1594 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1595 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1596 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1599 if (uLevel > 2) {
1600 memset(p+40,0,SHPWLEN+2);
1601 SSVAL(p,50,0);
1602 SIVAL(p,52,0);
1603 SSVAL(p,56,0);
1604 SSVAL(p,58,0);
1605 SIVAL(p,60,0);
1606 SSVAL(p,64,0);
1607 SSVAL(p,66,0);
1610 if (stringbuf) {
1611 (*buf) = p + struct_len;
1612 (*buflen) -= struct_len;
1613 (*stringbuf) = p2;
1614 (*stringspace) = l2;
1615 } else {
1616 (*buf) = p2;
1617 (*buflen) -= len;
1620 return len;
1623 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1624 char *param, int tpscnt,
1625 char *data, int tdscnt,
1626 int mdrcnt,int mprcnt,
1627 char **rdata,char **rparam,
1628 int *rdata_len,int *rparam_len)
1630 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1631 char *str2 = skip_string(param,tpscnt,str1);
1632 char *netname = skip_string(param,tpscnt,str2);
1633 char *p = skip_string(param,tpscnt,netname);
1634 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1635 int snum;
1637 if (!str1 || !str2 || !netname || !p) {
1638 return False;
1641 snum = find_service(netname);
1642 if (snum < 0) {
1643 return False;
1646 /* check it's a supported varient */
1647 if (!prefix_ok(str1,"zWrLh")) {
1648 return False;
1650 if (!check_share_info(uLevel,str2)) {
1651 return False;
1654 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
1655 if (!*rdata) {
1656 return False;
1658 p = *rdata;
1659 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1660 if (*rdata_len < 0) {
1661 return False;
1664 *rparam_len = 6;
1665 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1666 if (!*rparam) {
1667 return False;
1669 SSVAL(*rparam,0,NERR_Success);
1670 SSVAL(*rparam,2,0); /* converter word */
1671 SSVAL(*rparam,4,*rdata_len);
1673 return True;
1676 /****************************************************************************
1677 View the list of available shares.
1679 This function is the server side of the NetShareEnum() RAP call.
1680 It fills the return buffer with share names and share comments.
1681 Note that the return buffer normally (in all known cases) allows only
1682 twelve byte strings for share names (plus one for a nul terminator).
1683 Share names longer than 12 bytes must be skipped.
1684 ****************************************************************************/
1686 static BOOL api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1687 char *param, int tpscnt,
1688 char *data, int tdscnt,
1689 int mdrcnt,
1690 int mprcnt,
1691 char **rdata,
1692 char **rparam,
1693 int *rdata_len,
1694 int *rparam_len )
1696 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1697 char *str2 = skip_string(param,tpscnt,str1);
1698 char *p = skip_string(param,tpscnt,str2);
1699 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1700 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1701 char *p2;
1702 int count = 0;
1703 int total=0,counted=0;
1704 BOOL missed = False;
1705 int i;
1706 int data_len, fixed_len, string_len;
1707 int f_len = 0, s_len = 0;
1709 if (!str1 || !str2 || !p) {
1710 return False;
1713 if (!prefix_ok(str1,"WrLeh")) {
1714 return False;
1716 if (!check_share_info(uLevel,str2)) {
1717 return False;
1720 /* Ensure all the usershares are loaded. */
1721 become_root();
1722 load_registry_shares();
1723 count = load_usershare_shares();
1724 unbecome_root();
1726 data_len = fixed_len = string_len = 0;
1727 for (i=0;i<count;i++) {
1728 fstring servicename_dos;
1729 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1730 continue;
1732 push_ascii_fstring(servicename_dos, lp_servicename(i));
1733 /* Maximum name length = 13. */
1734 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1735 total++;
1736 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1737 if (data_len <= buf_len) {
1738 counted++;
1739 fixed_len += f_len;
1740 string_len += s_len;
1741 } else {
1742 missed = True;
1747 *rdata_len = fixed_len + string_len;
1748 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1749 if (!*rdata) {
1750 return False;
1752 memset(*rdata,0,*rdata_len);
1754 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1755 p = *rdata;
1756 f_len = fixed_len;
1757 s_len = string_len;
1759 for( i = 0; i < count; i++ ) {
1760 fstring servicename_dos;
1761 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1762 continue;
1765 push_ascii_fstring(servicename_dos, lp_servicename(i));
1766 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1767 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1768 break;
1773 *rparam_len = 8;
1774 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1775 if (!*rparam) {
1776 return False;
1778 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1779 SSVAL(*rparam,2,0);
1780 SSVAL(*rparam,4,counted);
1781 SSVAL(*rparam,6,total);
1783 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1784 counted,total,uLevel,
1785 buf_len,*rdata_len,mdrcnt));
1787 return True;
1790 /****************************************************************************
1791 Add a share
1792 ****************************************************************************/
1794 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1795 char *param, int tpscnt,
1796 char *data, int tdscnt,
1797 int mdrcnt,int mprcnt,
1798 char **rdata,char **rparam,
1799 int *rdata_len,int *rparam_len)
1801 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1802 char *str2 = skip_string(param,tpscnt,str1);
1803 char *p = skip_string(param,tpscnt,str2);
1804 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1805 fstring sharename;
1806 fstring comment;
1807 pstring pathname;
1808 char *command, *cmdname;
1809 unsigned int offset;
1810 int snum;
1811 int res = ERRunsup;
1813 if (!str1 || !str2 || !p) {
1814 return False;
1817 /* check it's a supported varient */
1818 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1819 return False;
1821 if (!check_share_info(uLevel,str2)) {
1822 return False;
1824 if (uLevel != 2) {
1825 return False;
1828 /* Do we have a string ? */
1829 if (skip_string(data,mdrcnt,data) == NULL) {
1830 return False;
1832 pull_ascii_fstring(sharename,data);
1833 snum = find_service(sharename);
1834 if (snum >= 0) { /* already exists */
1835 res = ERRfilexists;
1836 goto error_exit;
1839 if (mdrcnt < 28) {
1840 return False;
1843 /* only support disk share adds */
1844 if (SVAL(data,14)!=STYPE_DISKTREE) {
1845 return False;
1848 offset = IVAL(data, 16);
1849 if (offset >= mdrcnt) {
1850 res = ERRinvalidparam;
1851 goto error_exit;
1854 /* Do we have a string ? */
1855 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1856 return False;
1858 pull_ascii_fstring(comment, offset? (data+offset) : "");
1860 offset = IVAL(data, 26);
1862 if (offset >= mdrcnt) {
1863 res = ERRinvalidparam;
1864 goto error_exit;
1867 /* Do we have a string ? */
1868 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1869 return False;
1871 pull_ascii_pstring(pathname, offset? (data+offset) : "");
1873 string_replace(sharename, '"', ' ');
1874 string_replace(pathname, '"', ' ');
1875 string_replace(comment, '"', ' ');
1877 cmdname = lp_add_share_cmd();
1879 if (!cmdname || *cmdname == '\0') {
1880 return False;
1883 asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1884 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1886 if (command) {
1887 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1889 if ((res = smbrun(command, NULL)) != 0) {
1890 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1891 SAFE_FREE(command);
1892 res = ERRnoaccess;
1893 goto error_exit;
1894 } else {
1895 SAFE_FREE(command);
1896 message_send_all(smbd_messaging_context(),
1897 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1899 } else {
1900 return False;
1903 *rparam_len = 6;
1904 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1905 if (!*rparam) {
1906 return False;
1908 SSVAL(*rparam,0,NERR_Success);
1909 SSVAL(*rparam,2,0); /* converter word */
1910 SSVAL(*rparam,4,*rdata_len);
1911 *rdata_len = 0;
1913 return True;
1915 error_exit:
1917 *rparam_len = 4;
1918 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1919 if (!*rparam) {
1920 return False;
1922 *rdata_len = 0;
1923 SSVAL(*rparam,0,res);
1924 SSVAL(*rparam,2,0);
1925 return True;
1928 /****************************************************************************
1929 view list of groups available
1930 ****************************************************************************/
1932 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
1933 char *param, int tpscnt,
1934 char *data, int tdscnt,
1935 int mdrcnt,int mprcnt,
1936 char **rdata,char **rparam,
1937 int *rdata_len,int *rparam_len)
1939 int i;
1940 int errflags=0;
1941 int resume_context, cli_buf_size;
1942 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1943 char *str2 = skip_string(param,tpscnt,str1);
1944 char *p = skip_string(param,tpscnt,str2);
1946 struct pdb_search *search;
1947 struct samr_displayentry *entries;
1949 int num_entries;
1951 if (!str1 || !str2 || !p) {
1952 return False;
1955 if (strcmp(str1,"WrLeh") != 0) {
1956 return False;
1959 /* parameters
1960 * W-> resume context (number of users to skip)
1961 * r -> return parameter pointer to receive buffer
1962 * L -> length of receive buffer
1963 * e -> return parameter number of entries
1964 * h -> return parameter total number of users
1967 if (strcmp("B21",str2) != 0) {
1968 return False;
1971 /* get list of domain groups SID_DOMAIN_GRP=2 */
1972 become_root();
1973 search = pdb_search_groups();
1974 unbecome_root();
1976 if (search == NULL) {
1977 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1978 return False;
1981 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
1982 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
1983 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1984 "%d\n", resume_context, cli_buf_size));
1986 become_root();
1987 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1988 &entries);
1989 unbecome_root();
1991 *rdata_len = cli_buf_size;
1992 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1993 if (!*rdata) {
1994 return False;
1997 p = *rdata;
1999 for(i=0; i<num_entries; i++) {
2000 fstring name;
2001 fstrcpy(name, entries[i].account_name);
2002 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2003 /* truncate the name at 21 chars. */
2004 memcpy(p, name, 21);
2005 DEBUG(10,("adding entry %d group %s\n", i, p));
2006 p += 21;
2007 p += 5; /* Both NT4 and W2k3SP1 do padding here.
2008 No idea why... */
2009 } else {
2010 /* set overflow error */
2011 DEBUG(3,("overflow on entry %d group %s\n", i, name));
2012 errflags=234;
2013 break;
2017 pdb_search_destroy(search);
2019 *rdata_len = PTR_DIFF(p,*rdata);
2021 *rparam_len = 8;
2022 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2023 if (!*rparam) {
2024 return False;
2026 SSVAL(*rparam, 0, errflags);
2027 SSVAL(*rparam, 2, 0); /* converter word */
2028 SSVAL(*rparam, 4, i); /* is this right?? */
2029 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
2031 return(True);
2034 /*******************************************************************
2035 Get groups that a user is a member of.
2036 ******************************************************************/
2038 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2039 char *param, int tpscnt,
2040 char *data, int tdscnt,
2041 int mdrcnt,int mprcnt,
2042 char **rdata,char **rparam,
2043 int *rdata_len,int *rparam_len)
2045 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2046 char *str2 = skip_string(param,tpscnt,str1);
2047 char *UserName = skip_string(param,tpscnt,str2);
2048 char *p = skip_string(param,tpscnt,UserName);
2049 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2050 const char *level_string;
2051 int count=0;
2052 struct samu *sampw = NULL;
2053 BOOL ret = False;
2054 DOM_SID *sids;
2055 gid_t *gids;
2056 size_t num_groups;
2057 size_t i;
2058 NTSTATUS result;
2059 DOM_SID user_sid;
2060 enum lsa_SidType type;
2061 TALLOC_CTX *mem_ctx;
2063 if (!str1 || !str2 || !UserName || !p) {
2064 return False;
2067 *rparam_len = 8;
2068 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2069 if (!*rparam) {
2070 return False;
2073 /* check it's a supported varient */
2075 if ( strcmp(str1,"zWrLeh") != 0 )
2076 return False;
2078 switch( uLevel ) {
2079 case 0:
2080 level_string = "B21";
2081 break;
2082 default:
2083 return False;
2086 if (strcmp(level_string,str2) != 0)
2087 return False;
2089 *rdata_len = mdrcnt + 1024;
2090 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2091 if (!*rdata) {
2092 return False;
2094 SSVAL(*rparam,0,NERR_Success);
2095 SSVAL(*rparam,2,0); /* converter word */
2097 p = *rdata;
2099 mem_ctx = talloc_new(NULL);
2100 if (mem_ctx == NULL) {
2101 DEBUG(0, ("talloc_new failed\n"));
2102 return False;
2105 if ( !(sampw = samu_new(mem_ctx)) ) {
2106 DEBUG(0, ("samu_new() failed!\n"));
2107 TALLOC_FREE(mem_ctx);
2108 return False;
2111 /* Lookup the user information; This should only be one of
2112 our accounts (not remote domains) */
2114 become_root(); /* ROOT BLOCK */
2116 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2117 NULL, NULL, &user_sid, &type)) {
2118 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2119 goto done;
2122 if (type != SID_NAME_USER) {
2123 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2124 sid_type_lookup(type)));
2125 goto done;
2128 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2129 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2130 sid_string_static(&user_sid), UserName));
2131 goto done;
2134 gids = NULL;
2135 sids = NULL;
2136 num_groups = 0;
2138 result = pdb_enum_group_memberships(mem_ctx, sampw,
2139 &sids, &gids, &num_groups);
2141 if (!NT_STATUS_IS_OK(result)) {
2142 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2143 UserName));
2144 goto done;
2147 for (i=0; i<num_groups; i++) {
2149 const char *grp_name;
2151 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2152 pstrcpy(p, grp_name);
2153 p += 21;
2154 count++;
2158 *rdata_len = PTR_DIFF(p,*rdata);
2160 SSVAL(*rparam,4,count); /* is this right?? */
2161 SSVAL(*rparam,6,count); /* is this right?? */
2163 ret = True;
2165 done:
2166 unbecome_root(); /* END ROOT BLOCK */
2168 TALLOC_FREE(mem_ctx);
2170 return ret;
2173 /*******************************************************************
2174 Get all users.
2175 ******************************************************************/
2177 static BOOL api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2178 char *param, int tpscnt,
2179 char *data, int tdscnt,
2180 int mdrcnt,int mprcnt,
2181 char **rdata,char **rparam,
2182 int *rdata_len,int *rparam_len)
2184 int count_sent=0;
2185 int num_users=0;
2186 int errflags=0;
2187 int i, resume_context, cli_buf_size;
2188 struct pdb_search *search;
2189 struct samr_displayentry *users;
2191 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2192 char *str2 = skip_string(param,tpscnt,str1);
2193 char *p = skip_string(param,tpscnt,str2);
2195 if (!str1 || !str2 || !p) {
2196 return False;
2199 if (strcmp(str1,"WrLeh") != 0)
2200 return False;
2201 /* parameters
2202 * W-> resume context (number of users to skip)
2203 * r -> return parameter pointer to receive buffer
2204 * L -> length of receive buffer
2205 * e -> return parameter number of entries
2206 * h -> return parameter total number of users
2209 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2210 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2211 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2212 resume_context, cli_buf_size));
2214 *rparam_len = 8;
2215 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2216 if (!*rparam) {
2217 return False;
2220 /* check it's a supported varient */
2221 if (strcmp("B21",str2) != 0)
2222 return False;
2224 *rdata_len = cli_buf_size;
2225 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2226 if (!*rdata) {
2227 return False;
2230 p = *rdata;
2232 become_root();
2233 search = pdb_search_users(ACB_NORMAL);
2234 unbecome_root();
2235 if (search == NULL) {
2236 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2237 return False;
2240 become_root();
2241 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2242 &users);
2243 unbecome_root();
2245 errflags=NERR_Success;
2247 for (i=0; i<num_users; i++) {
2248 const char *name = users[i].account_name;
2250 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2251 pstrcpy(p,name);
2252 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2253 "%s\n",count_sent,p));
2254 p += 21;
2255 count_sent++;
2256 } else {
2257 /* set overflow error */
2258 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2259 "username %s\n",count_sent,name));
2260 errflags=234;
2261 break;
2265 pdb_search_destroy(search);
2267 *rdata_len = PTR_DIFF(p,*rdata);
2269 SSVAL(*rparam,0,errflags);
2270 SSVAL(*rparam,2,0); /* converter word */
2271 SSVAL(*rparam,4,count_sent); /* is this right?? */
2272 SSVAL(*rparam,6,num_users); /* is this right?? */
2274 return True;
2277 /****************************************************************************
2278 Get the time of day info.
2279 ****************************************************************************/
2281 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2282 char *param, int tpscnt,
2283 char *data, int tdscnt,
2284 int mdrcnt,int mprcnt,
2285 char **rdata,char **rparam,
2286 int *rdata_len,int *rparam_len)
2288 struct tm *t;
2289 time_t unixdate = time(NULL);
2290 char *p;
2292 *rparam_len = 4;
2293 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2294 if (!*rparam) {
2295 return False;
2298 *rdata_len = 21;
2299 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2300 if (!*rdata) {
2301 return False;
2304 SSVAL(*rparam,0,NERR_Success);
2305 SSVAL(*rparam,2,0); /* converter word */
2307 p = *rdata;
2309 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2310 by NT in a "net time" operation,
2311 it seems to ignore the one below */
2313 /* the client expects to get localtime, not GMT, in this bit
2314 (I think, this needs testing) */
2315 t = localtime(&unixdate);
2316 if (!t) {
2317 return False;
2320 SIVAL(p,4,0); /* msecs ? */
2321 SCVAL(p,8,t->tm_hour);
2322 SCVAL(p,9,t->tm_min);
2323 SCVAL(p,10,t->tm_sec);
2324 SCVAL(p,11,0); /* hundredths of seconds */
2325 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2326 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2327 SCVAL(p,16,t->tm_mday);
2328 SCVAL(p,17,t->tm_mon + 1);
2329 SSVAL(p,18,1900+t->tm_year);
2330 SCVAL(p,20,t->tm_wday);
2332 return True;
2335 /****************************************************************************
2336 Set the user password.
2337 *****************************************************************************/
2339 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid,
2340 char *param, int tpscnt,
2341 char *data, int tdscnt,
2342 int mdrcnt,int mprcnt,
2343 char **rdata,char **rparam,
2344 int *rdata_len,int *rparam_len)
2346 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2347 char *p = NULL;
2348 fstring user;
2349 fstring pass1,pass2;
2351 /* Skip 2 strings. */
2352 p = skip_string(param,tpscnt,np);
2353 p = skip_string(param,tpscnt,p);
2355 if (!np || !p) {
2356 return False;
2359 /* Do we have a string ? */
2360 if (skip_string(param,tpscnt,p) == NULL) {
2361 return False;
2363 pull_ascii_fstring(user,p);
2365 p = skip_string(param,tpscnt,p);
2366 if (!p) {
2367 return False;
2370 memset(pass1,'\0',sizeof(pass1));
2371 memset(pass2,'\0',sizeof(pass2));
2373 * We use 31 here not 32 as we're checking
2374 * the last byte we want to access is safe.
2376 if (!is_offset_safe(param,tpscnt,p,31)) {
2377 return False;
2379 memcpy(pass1,p,16);
2380 memcpy(pass2,p+16,16);
2382 *rparam_len = 4;
2383 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2384 if (!*rparam) {
2385 return False;
2388 *rdata_len = 0;
2390 SSVAL(*rparam,0,NERR_badpass);
2391 SSVAL(*rparam,2,0); /* converter word */
2393 DEBUG(3,("Set password for <%s>\n",user));
2396 * Attempt to verify the old password against smbpasswd entries
2397 * Win98 clients send old and new password in plaintext for this call.
2401 auth_serversupplied_info *server_info = NULL;
2402 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2404 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2406 become_root();
2407 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2408 SSVAL(*rparam,0,NERR_Success);
2410 unbecome_root();
2412 TALLOC_FREE(server_info);
2414 data_blob_clear_free(&password);
2418 * If the plaintext change failed, attempt
2419 * the old encrypted method. NT will generate this
2420 * after trying the samr method. Note that this
2421 * method is done as a last resort as this
2422 * password change method loses the NT password hash
2423 * and cannot change the UNIX password as no plaintext
2424 * is received.
2427 if(SVAL(*rparam,0) != NERR_Success) {
2428 struct samu *hnd = NULL;
2430 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2431 become_root();
2432 if (change_lanman_password(hnd,(uchar *)pass2)) {
2433 SSVAL(*rparam,0,NERR_Success);
2435 unbecome_root();
2436 TALLOC_FREE(hnd);
2440 memset((char *)pass1,'\0',sizeof(fstring));
2441 memset((char *)pass2,'\0',sizeof(fstring));
2443 return(True);
2446 /****************************************************************************
2447 Set the user password (SamOEM version - gets plaintext).
2448 ****************************************************************************/
2450 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2451 char *param, int tpscnt,
2452 char *data, int tdscnt,
2453 int mdrcnt,int mprcnt,
2454 char **rdata,char **rparam,
2455 int *rdata_len,int *rparam_len)
2457 fstring user;
2458 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2459 *rparam_len = 2;
2460 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2461 if (!*rparam) {
2462 return False;
2465 if (!p) {
2466 return False;
2468 *rdata_len = 0;
2470 SSVAL(*rparam,0,NERR_badpass);
2473 * Check the parameter definition is correct.
2476 /* Do we have a string ? */
2477 if (skip_string(param,tpscnt,p) == 0) {
2478 return False;
2480 if(!strequal(p, "zsT")) {
2481 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2482 return False;
2484 p = skip_string(param, tpscnt, p);
2485 if (!p) {
2486 return False;
2489 /* Do we have a string ? */
2490 if (skip_string(param,tpscnt,p) == 0) {
2491 return False;
2493 if(!strequal(p, "B516B16")) {
2494 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2495 return False;
2497 p = skip_string(param,tpscnt,p);
2498 if (!p) {
2499 return False;
2501 /* Do we have a string ? */
2502 if (skip_string(param,tpscnt,p) == 0) {
2503 return False;
2505 p += pull_ascii_fstring(user,p);
2507 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2510 * Pass the user through the NT -> unix user mapping
2511 * function.
2514 (void)map_username(user);
2516 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2517 SSVAL(*rparam,0,NERR_Success);
2520 return(True);
2523 /****************************************************************************
2524 delete a print job
2525 Form: <W> <>
2526 ****************************************************************************/
2528 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2529 char *param, int tpscnt,
2530 char *data, int tdscnt,
2531 int mdrcnt,int mprcnt,
2532 char **rdata,char **rparam,
2533 int *rdata_len,int *rparam_len)
2535 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2536 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2537 char *str2 = skip_string(param,tpscnt,str1);
2538 char *p = skip_string(param,tpscnt,str2);
2539 uint32 jobid;
2540 int snum;
2541 fstring sharename;
2542 int errcode;
2543 WERROR werr = WERR_OK;
2545 if (!str1 || !str2 || !p) {
2546 return False;
2549 * We use 1 here not 2 as we're checking
2550 * the last byte we want to access is safe.
2552 if (!is_offset_safe(param,tpscnt,p,1)) {
2553 return False;
2555 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2556 return False;
2558 /* check it's a supported varient */
2559 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2560 return(False);
2562 *rparam_len = 4;
2563 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2564 if (!*rparam) {
2565 return False;
2567 *rdata_len = 0;
2569 if (!print_job_exists(sharename, jobid)) {
2570 errcode = NERR_JobNotFound;
2571 goto out;
2574 snum = lp_servicenumber( sharename);
2575 if (snum == -1) {
2576 errcode = NERR_DestNotFound;
2577 goto out;
2580 errcode = NERR_notsupported;
2582 switch (function) {
2583 case 81: /* delete */
2584 if (print_job_delete(&current_user, snum, jobid, &werr))
2585 errcode = NERR_Success;
2586 break;
2587 case 82: /* pause */
2588 if (print_job_pause(&current_user, snum, jobid, &werr))
2589 errcode = NERR_Success;
2590 break;
2591 case 83: /* resume */
2592 if (print_job_resume(&current_user, snum, jobid, &werr))
2593 errcode = NERR_Success;
2594 break;
2597 if (!W_ERROR_IS_OK(werr))
2598 errcode = W_ERROR_V(werr);
2600 out:
2601 SSVAL(*rparam,0,errcode);
2602 SSVAL(*rparam,2,0); /* converter word */
2604 return(True);
2607 /****************************************************************************
2608 Purge a print queue - or pause or resume it.
2609 ****************************************************************************/
2611 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2612 char *param, int tpscnt,
2613 char *data, int tdscnt,
2614 int mdrcnt,int mprcnt,
2615 char **rdata,char **rparam,
2616 int *rdata_len,int *rparam_len)
2618 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2619 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2620 char *str2 = skip_string(param,tpscnt,str1);
2621 char *QueueName = skip_string(param,tpscnt,str2);
2622 int errcode = NERR_notsupported;
2623 int snum;
2624 WERROR werr = WERR_OK;
2626 if (!str1 || !str2 || !QueueName) {
2627 return False;
2630 /* check it's a supported varient */
2631 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2632 return(False);
2634 *rparam_len = 4;
2635 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2636 if (!*rparam) {
2637 return False;
2639 *rdata_len = 0;
2641 if (skip_string(param,tpscnt,QueueName) == NULL) {
2642 return False;
2644 snum = print_queue_snum(QueueName);
2646 if (snum == -1) {
2647 errcode = NERR_JobNotFound;
2648 goto out;
2651 switch (function) {
2652 case 74: /* Pause queue */
2653 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2654 break;
2655 case 75: /* Resume queue */
2656 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2657 break;
2658 case 103: /* Purge */
2659 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2660 break;
2663 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2665 out:
2666 SSVAL(*rparam,0,errcode);
2667 SSVAL(*rparam,2,0); /* converter word */
2669 return(True);
2672 /****************************************************************************
2673 set the property of a print job (undocumented?)
2674 ? function = 0xb -> set name of print job
2675 ? function = 0x6 -> move print job up/down
2676 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2677 or <WWsTP> <WB21BB16B10zWWzDDz>
2678 ****************************************************************************/
2680 static int check_printjob_info(struct pack_desc* desc,
2681 int uLevel, char* id)
2683 desc->subformat = NULL;
2684 switch( uLevel ) {
2685 case 0: desc->format = "W"; break;
2686 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2687 case 2: desc->format = "WWzWWDDzz"; break;
2688 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2689 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2690 default:
2691 DEBUG(0,("check_printjob_info: invalid level %d\n",
2692 uLevel ));
2693 return False;
2695 if (id == NULL || strcmp(desc->format,id) != 0) {
2696 DEBUG(0,("check_printjob_info: invalid format %s\n",
2697 id ? id : "<NULL>" ));
2698 return False;
2700 return True;
2703 static BOOL api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2704 char *param, int tpscnt,
2705 char *data, int tdscnt,
2706 int mdrcnt,int mprcnt,
2707 char **rdata,char **rparam,
2708 int *rdata_len,int *rparam_len)
2710 struct pack_desc desc;
2711 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2712 char *str2 = skip_string(param,tpscnt,str1);
2713 char *p = skip_string(param,tpscnt,str2);
2714 uint32 jobid;
2715 fstring sharename;
2716 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2717 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2718 int place, errcode;
2720 if (!str1 || !str2 || !p) {
2721 return False;
2724 * We use 1 here not 2 as we're checking
2725 * the last byte we want to access is safe.
2727 if (!is_offset_safe(param,tpscnt,p,1)) {
2728 return False;
2730 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2731 return False;
2732 *rparam_len = 4;
2733 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2734 if (!*rparam) {
2735 return False;
2738 if (!share_defined(sharename)) {
2739 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2740 sharename));
2741 return False;
2744 *rdata_len = 0;
2746 /* check it's a supported varient */
2747 if ((strcmp(str1,"WWsTP")) ||
2748 (!check_printjob_info(&desc,uLevel,str2)))
2749 return(False);
2751 if (!print_job_exists(sharename, jobid)) {
2752 errcode=NERR_JobNotFound;
2753 goto out;
2756 errcode = NERR_notsupported;
2758 switch (function) {
2759 case 0x6:
2760 /* change job place in the queue,
2761 data gives the new place */
2762 place = SVAL(data,0);
2763 if (print_job_set_place(sharename, jobid, place)) {
2764 errcode=NERR_Success;
2766 break;
2768 case 0xb:
2769 /* change print job name, data gives the name */
2770 if (print_job_set_name(sharename, jobid, data)) {
2771 errcode=NERR_Success;
2773 break;
2775 default:
2776 return False;
2779 out:
2780 SSVALS(*rparam,0,errcode);
2781 SSVAL(*rparam,2,0); /* converter word */
2783 return(True);
2787 /****************************************************************************
2788 Get info about the server.
2789 ****************************************************************************/
2791 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2792 char *param, int tpscnt,
2793 char *data, int tdscnt,
2794 int mdrcnt,int mprcnt,
2795 char **rdata,char **rparam,
2796 int *rdata_len,int *rparam_len)
2798 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2799 char *str2 = skip_string(param,tpscnt,str1);
2800 char *p = skip_string(param,tpscnt,str2);
2801 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2802 char *p2;
2803 int struct_len;
2805 if (!str1 || !str2 || !p) {
2806 return False;
2809 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2811 /* check it's a supported varient */
2812 if (!prefix_ok(str1,"WrLh")) {
2813 return False;
2816 switch( uLevel ) {
2817 case 0:
2818 if (strcmp(str2,"B16") != 0) {
2819 return False;
2821 struct_len = 16;
2822 break;
2823 case 1:
2824 if (strcmp(str2,"B16BBDz") != 0) {
2825 return False;
2827 struct_len = 26;
2828 break;
2829 case 2:
2830 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2831 return False;
2833 struct_len = 134;
2834 break;
2835 case 3:
2836 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2837 return False;
2839 struct_len = 144;
2840 break;
2841 case 20:
2842 if (strcmp(str2,"DN") != 0) {
2843 return False;
2845 struct_len = 6;
2846 break;
2847 case 50:
2848 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2849 return False;
2851 struct_len = 42;
2852 break;
2853 default:
2854 return False;
2857 *rdata_len = mdrcnt;
2858 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2859 if (!*rdata) {
2860 return False;
2863 p = *rdata;
2864 p2 = p + struct_len;
2865 if (uLevel != 20) {
2866 srvstr_push(NULL, p,global_myname(),16,
2867 STR_ASCII|STR_UPPER|STR_TERMINATE);
2869 p += 16;
2870 if (uLevel > 0) {
2871 struct srv_info_struct *servers=NULL;
2872 int i,count;
2873 pstring comment;
2874 uint32 servertype= lp_default_server_announce();
2876 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2878 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2879 for (i=0;i<count;i++) {
2880 if (strequal(servers[i].name,global_myname())) {
2881 servertype = servers[i].type;
2882 push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2887 SAFE_FREE(servers);
2889 SCVAL(p,0,lp_major_announce_version());
2890 SCVAL(p,1,lp_minor_announce_version());
2891 SIVAL(p,2,servertype);
2893 if (mdrcnt == struct_len) {
2894 SIVAL(p,6,0);
2895 } else {
2896 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2897 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2898 conn->connectpath, conn->gid,
2899 get_current_username(),
2900 current_user_info.domain,
2901 comment, sizeof(comment));
2902 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2903 p2 = skip_string(*rdata,*rdata_len,p2);
2904 if (!p2) {
2905 return False;
2910 if (uLevel > 1) {
2911 return False; /* not yet implemented */
2914 *rdata_len = PTR_DIFF(p2,*rdata);
2916 *rparam_len = 6;
2917 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2918 if (!*rparam) {
2919 return False;
2921 SSVAL(*rparam,0,NERR_Success);
2922 SSVAL(*rparam,2,0); /* converter word */
2923 SSVAL(*rparam,4,*rdata_len);
2925 return True;
2928 /****************************************************************************
2929 Get info about the server.
2930 ****************************************************************************/
2932 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
2933 char *param, int tpscnt,
2934 char *data, int tdscnt,
2935 int mdrcnt,int mprcnt,
2936 char **rdata,char **rparam,
2937 int *rdata_len,int *rparam_len)
2939 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2940 char *str2 = skip_string(param,tpscnt,str1);
2941 char *p = skip_string(param,tpscnt,str2);
2942 char *p2;
2943 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
2945 if (!str1 || !str2 || !p) {
2946 return False;
2949 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2951 *rparam_len = 6;
2952 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2953 if (!*rparam) {
2954 return False;
2957 /* check it's a supported varient */
2958 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2959 return False;
2962 *rdata_len = mdrcnt + 1024;
2963 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2964 if (!*rdata) {
2965 return False;
2968 SSVAL(*rparam,0,NERR_Success);
2969 SSVAL(*rparam,2,0); /* converter word */
2971 p = *rdata;
2972 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
2973 if (!p2) {
2974 return False;
2977 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2978 pstrcpy(p2,get_local_machine_name());
2979 strupper_m(p2);
2980 p2 = skip_string(*rdata,*rdata_len,p2);
2981 if (!p2) {
2982 return False;
2984 p += 4;
2986 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2987 pstrcpy(p2,current_user_info.smb_name);
2988 p2 = skip_string(*rdata,*rdata_len,p2);
2989 if (!p2) {
2990 return False;
2992 p += 4;
2994 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2995 pstrcpy(p2,lp_workgroup());
2996 strupper_m(p2);
2997 p2 = skip_string(*rdata,*rdata_len,p2);
2998 if (!p2) {
2999 return False;
3001 p += 4;
3003 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3004 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3005 p += 2;
3007 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3008 pstrcpy(p2,lp_workgroup()); /* don't know. login domain?? */
3009 p2 = skip_string(*rdata,*rdata_len,p2);
3010 if (!p2) {
3011 return False;
3013 p += 4;
3015 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3016 pstrcpy(p2,"");
3017 p2 = skip_string(*rdata,*rdata_len,p2);
3018 if (!p2) {
3019 return False;
3021 p += 4;
3023 *rdata_len = PTR_DIFF(p2,*rdata);
3025 SSVAL(*rparam,4,*rdata_len);
3027 return True;
3030 /****************************************************************************
3031 get info about a user
3033 struct user_info_11 {
3034 char usri11_name[21]; 0-20
3035 char usri11_pad; 21
3036 char *usri11_comment; 22-25
3037 char *usri11_usr_comment; 26-29
3038 unsigned short usri11_priv; 30-31
3039 unsigned long usri11_auth_flags; 32-35
3040 long usri11_password_age; 36-39
3041 char *usri11_homedir; 40-43
3042 char *usri11_parms; 44-47
3043 long usri11_last_logon; 48-51
3044 long usri11_last_logoff; 52-55
3045 unsigned short usri11_bad_pw_count; 56-57
3046 unsigned short usri11_num_logons; 58-59
3047 char *usri11_logon_server; 60-63
3048 unsigned short usri11_country_code; 64-65
3049 char *usri11_workstations; 66-69
3050 unsigned long usri11_max_storage; 70-73
3051 unsigned short usri11_units_per_week; 74-75
3052 unsigned char *usri11_logon_hours; 76-79
3053 unsigned short usri11_code_page; 80-81
3056 where:
3058 usri11_name specifies the user name for which information is retireved
3060 usri11_pad aligns the next data structure element to a word boundary
3062 usri11_comment is a null terminated ASCII comment
3064 usri11_user_comment is a null terminated ASCII comment about the user
3066 usri11_priv specifies the level of the privilege assigned to the user.
3067 The possible values are:
3069 Name Value Description
3070 USER_PRIV_GUEST 0 Guest privilege
3071 USER_PRIV_USER 1 User privilege
3072 USER_PRV_ADMIN 2 Administrator privilege
3074 usri11_auth_flags specifies the account operator privileges. The
3075 possible values are:
3077 Name Value Description
3078 AF_OP_PRINT 0 Print operator
3081 Leach, Naik [Page 28]
3085 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3088 AF_OP_COMM 1 Communications operator
3089 AF_OP_SERVER 2 Server operator
3090 AF_OP_ACCOUNTS 3 Accounts operator
3093 usri11_password_age specifies how many seconds have elapsed since the
3094 password was last changed.
3096 usri11_home_dir points to a null terminated ASCII string that contains
3097 the path name of the user's home directory.
3099 usri11_parms points to a null terminated ASCII string that is set
3100 aside for use by applications.
3102 usri11_last_logon specifies the time when the user last logged on.
3103 This value is stored as the number of seconds elapsed since
3104 00:00:00, January 1, 1970.
3106 usri11_last_logoff specifies the time when the user last logged off.
3107 This value is stored as the number of seconds elapsed since
3108 00:00:00, January 1, 1970. A value of 0 means the last logoff
3109 time is unknown.
3111 usri11_bad_pw_count specifies the number of incorrect passwords
3112 entered since the last successful logon.
3114 usri11_log1_num_logons specifies the number of times this user has
3115 logged on. A value of -1 means the number of logons is unknown.
3117 usri11_logon_server points to a null terminated ASCII string that
3118 contains the name of the server to which logon requests are sent.
3119 A null string indicates logon requests should be sent to the
3120 domain controller.
3122 usri11_country_code specifies the country code for the user's language
3123 of choice.
3125 usri11_workstations points to a null terminated ASCII string that
3126 contains the names of workstations the user may log on from.
3127 There may be up to 8 workstations, with the names separated by
3128 commas. A null strings indicates there are no restrictions.
3130 usri11_max_storage specifies the maximum amount of disk space the user
3131 can occupy. A value of 0xffffffff indicates there are no
3132 restrictions.
3134 usri11_units_per_week specifies the equal number of time units into
3135 which a week is divided. This value must be equal to 168.
3137 usri11_logon_hours points to a 21 byte (168 bits) string that
3138 specifies the time during which the user can log on. Each bit
3139 represents one unique hour in a week. The first bit (bit 0, word
3140 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3144 Leach, Naik [Page 29]
3148 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3151 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3152 are no restrictions.
3154 usri11_code_page specifies the code page for the user's language of
3155 choice
3157 All of the pointers in this data structure need to be treated
3158 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3159 to be ignored. The converter word returned in the parameters section
3160 needs to be subtracted from the lower 16 bits to calculate an offset
3161 into the return buffer where this ASCII string resides.
3163 There is no auxiliary data in the response.
3165 ****************************************************************************/
3167 #define usri11_name 0
3168 #define usri11_pad 21
3169 #define usri11_comment 22
3170 #define usri11_usr_comment 26
3171 #define usri11_full_name 30
3172 #define usri11_priv 34
3173 #define usri11_auth_flags 36
3174 #define usri11_password_age 40
3175 #define usri11_homedir 44
3176 #define usri11_parms 48
3177 #define usri11_last_logon 52
3178 #define usri11_last_logoff 56
3179 #define usri11_bad_pw_count 60
3180 #define usri11_num_logons 62
3181 #define usri11_logon_server 64
3182 #define usri11_country_code 68
3183 #define usri11_workstations 70
3184 #define usri11_max_storage 74
3185 #define usri11_units_per_week 78
3186 #define usri11_logon_hours 80
3187 #define usri11_code_page 84
3188 #define usri11_end 86
3190 #define USER_PRIV_GUEST 0
3191 #define USER_PRIV_USER 1
3192 #define USER_PRIV_ADMIN 2
3194 #define AF_OP_PRINT 0
3195 #define AF_OP_COMM 1
3196 #define AF_OP_SERVER 2
3197 #define AF_OP_ACCOUNTS 3
3200 static BOOL api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3201 char *param, int tpscnt,
3202 char *data, int tdscnt,
3203 int mdrcnt,int mprcnt,
3204 char **rdata,char **rparam,
3205 int *rdata_len,int *rparam_len)
3207 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3208 char *str2 = skip_string(param,tpscnt,str1);
3209 char *UserName = skip_string(param,tpscnt,str2);
3210 char *p = skip_string(param,tpscnt,UserName);
3211 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3212 char *p2;
3213 const char *level_string;
3215 /* get NIS home of a previously validated user - simeon */
3216 /* With share level security vuid will always be zero.
3217 Don't depend on vuser being non-null !!. JRA */
3218 user_struct *vuser = get_valid_user_struct(vuid);
3219 if(vuser != NULL) {
3220 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3221 vuser->user.unix_name));
3224 if (!str1 || !str2 || !UserName || !p) {
3225 return False;
3228 *rparam_len = 6;
3229 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3230 if (!*rparam) {
3231 return False;
3234 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3236 /* check it's a supported variant */
3237 if (strcmp(str1,"zWrLh") != 0) {
3238 return False;
3240 switch( uLevel ) {
3241 case 0: level_string = "B21"; break;
3242 case 1: level_string = "B21BB16DWzzWz"; break;
3243 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3244 case 10: level_string = "B21Bzzz"; break;
3245 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3246 default: return False;
3249 if (strcmp(level_string,str2) != 0) {
3250 return False;
3253 *rdata_len = mdrcnt + 1024;
3254 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
3255 if (!*rdata) {
3256 return False;
3259 SSVAL(*rparam,0,NERR_Success);
3260 SSVAL(*rparam,2,0); /* converter word */
3262 p = *rdata;
3263 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3264 if (!p2) {
3265 return False;
3268 memset(p,0,21);
3269 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3271 if (uLevel > 0) {
3272 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3273 *p2 = 0;
3276 if (uLevel >= 10) {
3277 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3278 pstrcpy(p2,"Comment");
3279 p2 = skip_string(*rdata,*rdata_len,p2);
3280 if (!p2) {
3281 return False;
3284 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3285 pstrcpy(p2,"UserComment");
3286 p2 = skip_string(*rdata,*rdata_len,p2);
3287 if (!p2) {
3288 return False;
3291 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3292 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3293 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3294 p2 = skip_string(*rdata,*rdata_len,p2);
3295 if (!p2) {
3296 return False;
3300 if (uLevel == 11) {
3301 /* modelled after NTAS 3.51 reply */
3302 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3303 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3304 SIVALS(p,usri11_password_age,-1); /* password age */
3305 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3306 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3307 p2 = skip_string(*rdata,*rdata_len,p2);
3308 if (!p2) {
3309 return False;
3311 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3312 pstrcpy(p2,"");
3313 p2 = skip_string(*rdata,*rdata_len,p2);
3314 if (!p2) {
3315 return False;
3317 SIVAL(p,usri11_last_logon,0); /* last logon */
3318 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3319 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3320 SSVALS(p,usri11_num_logons,-1); /* num logons */
3321 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3322 pstrcpy(p2,"\\\\*");
3323 p2 = skip_string(*rdata,*rdata_len,p2);
3324 if (!p2) {
3325 return False;
3327 SSVAL(p,usri11_country_code,0); /* country code */
3329 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3330 pstrcpy(p2,"");
3331 p2 = skip_string(*rdata,*rdata_len,p2);
3332 if (!p2) {
3333 return False;
3336 SIVALS(p,usri11_max_storage,-1); /* max storage */
3337 SSVAL(p,usri11_units_per_week,168); /* units per week */
3338 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3340 /* a simple way to get logon hours at all times. */
3341 memset(p2,0xff,21);
3342 SCVAL(p2,21,0); /* fix zero termination */
3343 p2 = skip_string(*rdata,*rdata_len,p2);
3344 if (!p2) {
3345 return False;
3348 SSVAL(p,usri11_code_page,0); /* code page */
3351 if (uLevel == 1 || uLevel == 2) {
3352 memset(p+22,' ',16); /* password */
3353 SIVALS(p,38,-1); /* password age */
3354 SSVAL(p,42,
3355 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3356 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3357 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3358 p2 = skip_string(*rdata,*rdata_len,p2);
3359 if (!p2) {
3360 return False;
3362 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3363 *p2++ = 0;
3364 SSVAL(p,52,0); /* flags */
3365 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3366 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3367 p2 = skip_string(*rdata,*rdata_len,p2);
3368 if (!p2) {
3369 return False;
3371 if (uLevel == 2) {
3372 SIVAL(p,60,0); /* auth_flags */
3373 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3374 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3375 p2 = skip_string(*rdata,*rdata_len,p2);
3376 if (!p2) {
3377 return False;
3379 SIVAL(p,68,0); /* urs_comment */
3380 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3381 pstrcpy(p2,"");
3382 p2 = skip_string(*rdata,*rdata_len,p2);
3383 if (!p2) {
3384 return False;
3386 SIVAL(p,76,0); /* workstations */
3387 SIVAL(p,80,0); /* last_logon */
3388 SIVAL(p,84,0); /* last_logoff */
3389 SIVALS(p,88,-1); /* acct_expires */
3390 SIVALS(p,92,-1); /* max_storage */
3391 SSVAL(p,96,168); /* units_per_week */
3392 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3393 memset(p2,-1,21);
3394 p2 += 21;
3395 SSVALS(p,102,-1); /* bad_pw_count */
3396 SSVALS(p,104,-1); /* num_logons */
3397 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3399 pstring tmp;
3400 pstrcpy(tmp, "\\\\%L");
3401 standard_sub_basic("", "", tmp, sizeof(tmp));
3402 pstrcpy(p2, tmp);
3404 p2 = skip_string(*rdata,*rdata_len,p2);
3405 if (!p2) {
3406 return False;
3408 SSVAL(p,110,49); /* country_code */
3409 SSVAL(p,112,860); /* code page */
3413 *rdata_len = PTR_DIFF(p2,*rdata);
3415 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3417 return(True);
3420 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3421 char *param, int tpscnt,
3422 char *data, int tdscnt,
3423 int mdrcnt,int mprcnt,
3424 char **rdata,char **rparam,
3425 int *rdata_len,int *rparam_len)
3427 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3428 char *str2 = skip_string(param,tpscnt,str1);
3429 char *p = skip_string(param,tpscnt,str2);
3430 int uLevel;
3431 struct pack_desc desc;
3432 char* name;
3433 /* With share level security vuid will always be zero.
3434 Don't depend on vuser being non-null !!. JRA */
3435 user_struct *vuser = get_valid_user_struct(vuid);
3437 if (!str1 || !str2 || !p) {
3438 return False;
3441 if(vuser != NULL) {
3442 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3443 vuser->user.unix_name));
3446 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3447 name = get_safe_str_ptr(param,tpscnt,p,2);
3448 if (!name) {
3449 return False;
3452 memset((char *)&desc,'\0',sizeof(desc));
3454 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3456 /* check it's a supported varient */
3457 if (strcmp(str1,"OOWb54WrLh") != 0) {
3458 return False;
3460 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3461 return False;
3463 if (mdrcnt > 0) {
3464 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3465 if (!*rdata) {
3466 return False;
3470 desc.base = *rdata;
3471 desc.buflen = mdrcnt;
3472 desc.subformat = NULL;
3473 desc.format = str2;
3475 if (init_package(&desc,1,0)) {
3476 PACKI(&desc,"W",0); /* code */
3477 PACKS(&desc,"B21",name); /* eff. name */
3478 PACKS(&desc,"B",""); /* pad */
3479 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3480 PACKI(&desc,"D",0); /* auth flags XXX */
3481 PACKI(&desc,"W",0); /* num logons */
3482 PACKI(&desc,"W",0); /* bad pw count */
3483 PACKI(&desc,"D",0); /* last logon */
3484 PACKI(&desc,"D",-1); /* last logoff */
3485 PACKI(&desc,"D",-1); /* logoff time */
3486 PACKI(&desc,"D",-1); /* kickoff time */
3487 PACKI(&desc,"D",0); /* password age */
3488 PACKI(&desc,"D",0); /* password can change */
3489 PACKI(&desc,"D",-1); /* password must change */
3492 fstring mypath;
3493 fstrcpy(mypath,"\\\\");
3494 fstrcat(mypath,get_local_machine_name());
3495 strupper_m(mypath);
3496 PACKS(&desc,"z",mypath); /* computer */
3499 PACKS(&desc,"z",lp_workgroup());/* domain */
3500 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3501 PACKI(&desc,"D",0x00000000); /* reserved */
3504 *rdata_len = desc.usedlen;
3505 *rparam_len = 6;
3506 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3507 if (!*rparam) {
3508 return False;
3510 SSVALS(*rparam,0,desc.errcode);
3511 SSVAL(*rparam,2,0);
3512 SSVAL(*rparam,4,desc.neededlen);
3514 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3516 return True;
3519 /****************************************************************************
3520 api_WAccessGetUserPerms
3521 ****************************************************************************/
3523 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3524 char *param, int tpscnt,
3525 char *data, int tdscnt,
3526 int mdrcnt,int mprcnt,
3527 char **rdata,char **rparam,
3528 int *rdata_len,int *rparam_len)
3530 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3531 char *str2 = skip_string(param,tpscnt,str1);
3532 char *user = skip_string(param,tpscnt,str2);
3533 char *resource = skip_string(param,tpscnt,user);
3535 if (!str1 || !str2 || !user || !resource) {
3536 return False;
3539 if (skip_string(param,tpscnt,resource) == NULL) {
3540 return False;
3542 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3544 /* check it's a supported varient */
3545 if (strcmp(str1,"zzh") != 0) {
3546 return False;
3548 if (strcmp(str2,"") != 0) {
3549 return False;
3552 *rparam_len = 6;
3553 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3554 if (!*rparam) {
3555 return False;
3557 SSVALS(*rparam,0,0); /* errorcode */
3558 SSVAL(*rparam,2,0); /* converter word */
3559 SSVAL(*rparam,4,0x7f); /* permission flags */
3561 return True;
3564 /****************************************************************************
3565 api_WPrintJobEnumerate
3566 ****************************************************************************/
3568 static BOOL api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3569 char *param, int tpscnt,
3570 char *data, int tdscnt,
3571 int mdrcnt,int mprcnt,
3572 char **rdata,char **rparam,
3573 int *rdata_len,int *rparam_len)
3575 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3576 char *str2 = skip_string(param,tpscnt,str1);
3577 char *p = skip_string(param,tpscnt,str2);
3578 int uLevel;
3579 int count;
3580 int i;
3581 int snum;
3582 fstring sharename;
3583 uint32 jobid;
3584 struct pack_desc desc;
3585 print_queue_struct *queue=NULL;
3586 print_status_struct status;
3587 char *tmpdata=NULL;
3589 if (!str1 || !str2 || !p) {
3590 return False;
3593 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3595 memset((char *)&desc,'\0',sizeof(desc));
3596 memset((char *)&status,'\0',sizeof(status));
3598 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3600 /* check it's a supported varient */
3601 if (strcmp(str1,"WWrLh") != 0) {
3602 return False;
3604 if (!check_printjob_info(&desc,uLevel,str2)) {
3605 return False;
3608 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3609 return False;
3612 snum = lp_servicenumber( sharename);
3613 if (snum < 0 || !VALID_SNUM(snum)) {
3614 return(False);
3617 count = print_queue_status(snum,&queue,&status);
3618 for (i = 0; i < count; i++) {
3619 if (queue[i].job == jobid) {
3620 break;
3624 if (mdrcnt > 0) {
3625 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3626 if (!*rdata) {
3627 return False;
3629 desc.base = *rdata;
3630 desc.buflen = mdrcnt;
3631 } else {
3633 * Don't return data but need to get correct length
3634 * init_package will return wrong size if buflen=0
3636 desc.buflen = getlen(desc.format);
3637 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3640 if (init_package(&desc,1,0)) {
3641 if (i < count) {
3642 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3643 *rdata_len = desc.usedlen;
3644 } else {
3645 desc.errcode = NERR_JobNotFound;
3646 *rdata_len = 0;
3650 *rparam_len = 6;
3651 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3652 if (!*rparam) {
3653 return False;
3655 SSVALS(*rparam,0,desc.errcode);
3656 SSVAL(*rparam,2,0);
3657 SSVAL(*rparam,4,desc.neededlen);
3659 SAFE_FREE(queue);
3660 SAFE_FREE(tmpdata);
3662 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3664 return True;
3667 static BOOL api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3668 char *param, int tpscnt,
3669 char *data, int tdscnt,
3670 int mdrcnt,int mprcnt,
3671 char **rdata,char **rparam,
3672 int *rdata_len,int *rparam_len)
3674 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3675 char *str2 = skip_string(param,tpscnt,str1);
3676 char *p = skip_string(param,tpscnt,str2);
3677 char *name = p;
3678 int uLevel;
3679 int count;
3680 int i, succnt=0;
3681 int snum;
3682 struct pack_desc desc;
3683 print_queue_struct *queue=NULL;
3684 print_status_struct status;
3686 if (!str1 || !str2 || !p) {
3687 return False;
3690 memset((char *)&desc,'\0',sizeof(desc));
3691 memset((char *)&status,'\0',sizeof(status));
3693 p = skip_string(param,tpscnt,p);
3694 if (!p) {
3695 return False;
3697 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3699 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3701 /* check it's a supported variant */
3702 if (strcmp(str1,"zWrLeh") != 0) {
3703 return False;
3706 if (uLevel > 2) {
3707 return False; /* defined only for uLevel 0,1,2 */
3710 if (!check_printjob_info(&desc,uLevel,str2)) {
3711 return False;
3714 snum = find_service(name);
3715 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3716 return False;
3719 count = print_queue_status(snum,&queue,&status);
3720 if (mdrcnt > 0) {
3721 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3722 if (!*rdata) {
3723 return False;
3726 desc.base = *rdata;
3727 desc.buflen = mdrcnt;
3729 if (init_package(&desc,count,0)) {
3730 succnt = 0;
3731 for (i = 0; i < count; i++) {
3732 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3733 if (desc.errcode == NERR_Success) {
3734 succnt = i+1;
3739 *rdata_len = desc.usedlen;
3741 *rparam_len = 8;
3742 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3743 if (!*rparam) {
3744 return False;
3746 SSVALS(*rparam,0,desc.errcode);
3747 SSVAL(*rparam,2,0);
3748 SSVAL(*rparam,4,succnt);
3749 SSVAL(*rparam,6,count);
3751 SAFE_FREE(queue);
3753 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3755 return True;
3758 static int check_printdest_info(struct pack_desc* desc,
3759 int uLevel, char* id)
3761 desc->subformat = NULL;
3762 switch( uLevel ) {
3763 case 0:
3764 desc->format = "B9";
3765 break;
3766 case 1:
3767 desc->format = "B9B21WWzW";
3768 break;
3769 case 2:
3770 desc->format = "z";
3771 break;
3772 case 3:
3773 desc->format = "zzzWWzzzWW";
3774 break;
3775 default:
3776 DEBUG(0,("check_printdest_info: invalid level %d\n",
3777 uLevel));
3778 return False;
3780 if (id == NULL || strcmp(desc->format,id) != 0) {
3781 DEBUG(0,("check_printdest_info: invalid string %s\n",
3782 id ? id : "<NULL>" ));
3783 return False;
3785 return True;
3788 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3789 struct pack_desc* desc)
3791 char buf[100];
3793 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3794 buf[sizeof(buf)-1] = 0;
3795 strupper_m(buf);
3797 if (uLevel <= 1) {
3798 PACKS(desc,"B9",buf); /* szName */
3799 if (uLevel == 1) {
3800 PACKS(desc,"B21",""); /* szUserName */
3801 PACKI(desc,"W",0); /* uJobId */
3802 PACKI(desc,"W",0); /* fsStatus */
3803 PACKS(desc,"z",""); /* pszStatus */
3804 PACKI(desc,"W",0); /* time */
3808 if (uLevel == 2 || uLevel == 3) {
3809 PACKS(desc,"z",buf); /* pszPrinterName */
3810 if (uLevel == 3) {
3811 PACKS(desc,"z",""); /* pszUserName */
3812 PACKS(desc,"z",""); /* pszLogAddr */
3813 PACKI(desc,"W",0); /* uJobId */
3814 PACKI(desc,"W",0); /* fsStatus */
3815 PACKS(desc,"z",""); /* pszStatus */
3816 PACKS(desc,"z",""); /* pszComment */
3817 PACKS(desc,"z","NULL"); /* pszDrivers */
3818 PACKI(desc,"W",0); /* time */
3819 PACKI(desc,"W",0); /* pad1 */
3824 static BOOL api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3825 char *param, int tpscnt,
3826 char *data, int tdscnt,
3827 int mdrcnt,int mprcnt,
3828 char **rdata,char **rparam,
3829 int *rdata_len,int *rparam_len)
3831 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3832 char *str2 = skip_string(param,tpscnt,str1);
3833 char *p = skip_string(param,tpscnt,str2);
3834 char* PrinterName = p;
3835 int uLevel;
3836 struct pack_desc desc;
3837 int snum;
3838 char *tmpdata=NULL;
3840 if (!str1 || !str2 || !p) {
3841 return False;
3844 memset((char *)&desc,'\0',sizeof(desc));
3846 p = skip_string(param,tpscnt,p);
3847 if (!p) {
3848 return False;
3850 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3852 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3854 /* check it's a supported varient */
3855 if (strcmp(str1,"zWrLh") != 0) {
3856 return False;
3858 if (!check_printdest_info(&desc,uLevel,str2)) {
3859 return False;
3862 snum = find_service(PrinterName);
3863 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3864 *rdata_len = 0;
3865 desc.errcode = NERR_DestNotFound;
3866 desc.neededlen = 0;
3867 } else {
3868 if (mdrcnt > 0) {
3869 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3870 if (!*rdata) {
3871 return False;
3873 desc.base = *rdata;
3874 desc.buflen = mdrcnt;
3875 } else {
3877 * Don't return data but need to get correct length
3878 * init_package will return wrong size if buflen=0
3880 desc.buflen = getlen(desc.format);
3881 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3883 if (init_package(&desc,1,0)) {
3884 fill_printdest_info(conn,snum,uLevel,&desc);
3886 *rdata_len = desc.usedlen;
3889 *rparam_len = 6;
3890 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3891 if (!*rparam) {
3892 return False;
3894 SSVALS(*rparam,0,desc.errcode);
3895 SSVAL(*rparam,2,0);
3896 SSVAL(*rparam,4,desc.neededlen);
3898 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3899 SAFE_FREE(tmpdata);
3901 return True;
3904 static BOOL api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
3905 char *param, int tpscnt,
3906 char *data, int tdscnt,
3907 int mdrcnt,int mprcnt,
3908 char **rdata,char **rparam,
3909 int *rdata_len,int *rparam_len)
3911 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3912 char *str2 = skip_string(param,tpscnt,str1);
3913 char *p = skip_string(param,tpscnt,str2);
3914 int uLevel;
3915 int queuecnt;
3916 int i, n, succnt=0;
3917 struct pack_desc desc;
3918 int services = lp_numservices();
3920 if (!str1 || !str2 || !p) {
3921 return False;
3924 memset((char *)&desc,'\0',sizeof(desc));
3926 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3928 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3930 /* check it's a supported varient */
3931 if (strcmp(str1,"WrLeh") != 0) {
3932 return False;
3934 if (!check_printdest_info(&desc,uLevel,str2)) {
3935 return False;
3938 queuecnt = 0;
3939 for (i = 0; i < services; i++) {
3940 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3941 queuecnt++;
3945 if (mdrcnt > 0) {
3946 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3947 if (!*rdata) {
3948 return False;
3952 desc.base = *rdata;
3953 desc.buflen = mdrcnt;
3954 if (init_package(&desc,queuecnt,0)) {
3955 succnt = 0;
3956 n = 0;
3957 for (i = 0; i < services; i++) {
3958 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3959 fill_printdest_info(conn,i,uLevel,&desc);
3960 n++;
3961 if (desc.errcode == NERR_Success) {
3962 succnt = n;
3968 *rdata_len = desc.usedlen;
3970 *rparam_len = 8;
3971 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3972 if (!*rparam) {
3973 return False;
3975 SSVALS(*rparam,0,desc.errcode);
3976 SSVAL(*rparam,2,0);
3977 SSVAL(*rparam,4,succnt);
3978 SSVAL(*rparam,6,queuecnt);
3980 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3982 return True;
3985 static BOOL api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
3986 char *param, int tpscnt,
3987 char *data, int tdscnt,
3988 int mdrcnt,int mprcnt,
3989 char **rdata,char **rparam,
3990 int *rdata_len,int *rparam_len)
3992 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3993 char *str2 = skip_string(param,tpscnt,str1);
3994 char *p = skip_string(param,tpscnt,str2);
3995 int uLevel;
3996 int succnt;
3997 struct pack_desc desc;
3999 if (!str1 || !str2 || !p) {
4000 return False;
4003 memset((char *)&desc,'\0',sizeof(desc));
4005 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4007 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4009 /* check it's a supported varient */
4010 if (strcmp(str1,"WrLeh") != 0) {
4011 return False;
4013 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4014 return False;
4017 if (mdrcnt > 0) {
4018 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4019 if (!*rdata) {
4020 return False;
4023 desc.base = *rdata;
4024 desc.buflen = mdrcnt;
4025 if (init_package(&desc,1,0)) {
4026 PACKS(&desc,"B41","NULL");
4029 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4031 *rdata_len = desc.usedlen;
4033 *rparam_len = 8;
4034 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4035 if (!*rparam) {
4036 return False;
4038 SSVALS(*rparam,0,desc.errcode);
4039 SSVAL(*rparam,2,0);
4040 SSVAL(*rparam,4,succnt);
4041 SSVAL(*rparam,6,1);
4043 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4045 return True;
4048 static BOOL api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4049 char *param, int tpscnt,
4050 char *data, int tdscnt,
4051 int mdrcnt,int mprcnt,
4052 char **rdata,char **rparam,
4053 int *rdata_len,int *rparam_len)
4055 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4056 char *str2 = skip_string(param,tpscnt,str1);
4057 char *p = skip_string(param,tpscnt,str2);
4058 int uLevel;
4059 int succnt;
4060 struct pack_desc desc;
4062 if (!str1 || !str2 || !p) {
4063 return False;
4065 memset((char *)&desc,'\0',sizeof(desc));
4067 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4069 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4071 /* check it's a supported varient */
4072 if (strcmp(str1,"WrLeh") != 0) {
4073 return False;
4075 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4076 return False;
4079 if (mdrcnt > 0) {
4080 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4081 if (!*rdata) {
4082 return False;
4085 desc.base = *rdata;
4086 desc.buflen = mdrcnt;
4087 desc.format = str2;
4088 if (init_package(&desc,1,0)) {
4089 PACKS(&desc,"B13","lpd");
4092 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4094 *rdata_len = desc.usedlen;
4096 *rparam_len = 8;
4097 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4098 if (!*rparam) {
4099 return False;
4101 SSVALS(*rparam,0,desc.errcode);
4102 SSVAL(*rparam,2,0);
4103 SSVAL(*rparam,4,succnt);
4104 SSVAL(*rparam,6,1);
4106 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4108 return True;
4111 static BOOL api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4112 char *param, int tpscnt,
4113 char *data, int tdscnt,
4114 int mdrcnt,int mprcnt,
4115 char **rdata,char **rparam,
4116 int *rdata_len,int *rparam_len)
4118 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4119 char *str2 = skip_string(param,tpscnt,str1);
4120 char *p = skip_string(param,tpscnt,str2);
4121 int uLevel;
4122 int succnt;
4123 struct pack_desc desc;
4125 if (!str1 || !str2 || !p) {
4126 return False;
4129 memset((char *)&desc,'\0',sizeof(desc));
4131 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4133 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4135 /* check it's a supported varient */
4136 if (strcmp(str1,"WrLeh") != 0) {
4137 return False;
4139 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4140 return False;
4143 if (mdrcnt > 0) {
4144 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4145 if (!*rdata) {
4146 return False;
4149 memset((char *)&desc,'\0',sizeof(desc));
4150 desc.base = *rdata;
4151 desc.buflen = mdrcnt;
4152 desc.format = str2;
4153 if (init_package(&desc,1,0)) {
4154 PACKS(&desc,"B13","lp0");
4157 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4159 *rdata_len = desc.usedlen;
4161 *rparam_len = 8;
4162 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4163 if (!*rparam) {
4164 return False;
4166 SSVALS(*rparam,0,desc.errcode);
4167 SSVAL(*rparam,2,0);
4168 SSVAL(*rparam,4,succnt);
4169 SSVAL(*rparam,6,1);
4171 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4173 return True;
4176 /****************************************************************************
4177 List open sessions
4178 ****************************************************************************/
4180 static BOOL api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4181 char *param, int tpscnt,
4182 char *data, int tdscnt,
4183 int mdrcnt,int mprcnt,
4184 char **rdata,char **rparam,
4185 int *rdata_len,int *rparam_len)
4188 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4189 char *str2 = skip_string(param,tpscnt,str1);
4190 char *p = skip_string(param,tpscnt,str2);
4191 int uLevel;
4192 struct pack_desc desc;
4193 struct sessionid *session_list;
4194 int i, num_sessions;
4196 if (!str1 || !str2 || !p) {
4197 return False;
4200 memset((char *)&desc,'\0',sizeof(desc));
4202 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4204 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4205 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4206 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4208 /* check it's a supported varient */
4209 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4210 return False;
4212 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4213 return False;
4216 num_sessions = list_sessions(tmp_talloc_ctx(), &session_list);
4218 if (mdrcnt > 0) {
4219 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4220 if (!*rdata) {
4221 return False;
4224 memset((char *)&desc,'\0',sizeof(desc));
4225 desc.base = *rdata;
4226 desc.buflen = mdrcnt;
4227 desc.format = str2;
4228 if (!init_package(&desc,num_sessions,0)) {
4229 return False;
4232 for(i=0; i<num_sessions; i++) {
4233 PACKS(&desc, "z", session_list[i].remote_machine);
4234 PACKS(&desc, "z", session_list[i].username);
4235 PACKI(&desc, "W", 1); /* num conns */
4236 PACKI(&desc, "W", 0); /* num opens */
4237 PACKI(&desc, "W", 1); /* num users */
4238 PACKI(&desc, "D", 0); /* session time */
4239 PACKI(&desc, "D", 0); /* idle time */
4240 PACKI(&desc, "D", 0); /* flags */
4241 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4244 *rdata_len = desc.usedlen;
4246 *rparam_len = 8;
4247 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4248 if (!*rparam) {
4249 return False;
4251 SSVALS(*rparam,0,desc.errcode);
4252 SSVAL(*rparam,2,0); /* converter */
4253 SSVAL(*rparam,4,num_sessions); /* count */
4255 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4257 return True;
4261 /****************************************************************************
4262 The buffer was too small.
4263 ****************************************************************************/
4265 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4266 int mdrcnt, int mprcnt,
4267 char **rdata, char **rparam,
4268 int *rdata_len, int *rparam_len)
4270 *rparam_len = MIN(*rparam_len,mprcnt);
4271 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4272 if (!*rparam) {
4273 return False;
4276 *rdata_len = 0;
4278 SSVAL(*rparam,0,NERR_BufTooSmall);
4280 DEBUG(3,("Supplied buffer too small in API command\n"));
4282 return True;
4285 /****************************************************************************
4286 The request is not supported.
4287 ****************************************************************************/
4289 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
4290 char *param, int tpscnt,
4291 char *data, int tdscnt,
4292 int mdrcnt, int mprcnt,
4293 char **rdata, char **rparam,
4294 int *rdata_len, int *rparam_len)
4296 *rparam_len = 4;
4297 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4298 if (!*rparam) {
4299 return False;
4302 *rdata_len = 0;
4304 SSVAL(*rparam,0,NERR_notsupported);
4305 SSVAL(*rparam,2,0); /* converter word */
4307 DEBUG(3,("Unsupported API command\n"));
4309 return True;
4312 static const struct {
4313 const char *name;
4314 int id;
4315 BOOL (*fn)(connection_struct *, uint16,
4316 char *, int,
4317 char *, int,
4318 int,int,char **,char **,int *,int *);
4319 BOOL auth_user; /* Deny anonymous access? */
4320 } api_commands[] = {
4321 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4322 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4323 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4324 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4325 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4326 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4327 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4328 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4329 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4330 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4331 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4332 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4333 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4334 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4335 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4336 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4337 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4338 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4339 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4340 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4341 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4342 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4343 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4344 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4345 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4346 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4347 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4348 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4349 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4350 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4351 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4352 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4353 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4354 {NULL, -1, api_Unsupported}
4355 /* The following RAP calls are not implemented by Samba:
4357 RAP_WFileEnum2 - anon not OK
4362 /****************************************************************************
4363 Handle remote api calls.
4364 ****************************************************************************/
4366 int api_reply(connection_struct *conn,
4367 uint16 vuid,
4368 const char *inbuf,
4369 char *outbuf,
4370 char *data,
4371 char *params,
4372 int tdscnt,
4373 int tpscnt,
4374 int mdrcnt,
4375 int mprcnt)
4377 int api_command;
4378 char *rdata = NULL;
4379 char *rparam = NULL;
4380 const char *name1 = NULL;
4381 const char *name2 = NULL;
4382 int rdata_len = 0;
4383 int rparam_len = 0;
4384 BOOL reply=False;
4385 int i;
4387 if (!params) {
4388 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4389 return 0;
4392 if (tpscnt < 2) {
4393 return 0;
4395 api_command = SVAL(params,0);
4396 /* Is there a string at position params+2 ? */
4397 if (skip_string(params,tpscnt,params+2)) {
4398 name1 = params + 2;
4399 } else {
4400 name1 = "";
4402 name2 = skip_string(params,tpscnt,params+2);
4403 if (!name2) {
4404 name2 = "";
4407 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4408 api_command,
4409 name1,
4410 name2,
4411 tdscnt,tpscnt,mdrcnt,mprcnt));
4413 for (i=0;api_commands[i].name;i++) {
4414 if (api_commands[i].id == api_command && api_commands[i].fn) {
4415 DEBUG(3,("Doing %s\n",api_commands[i].name));
4416 break;
4420 /* Check whether this api call can be done anonymously */
4422 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4423 user_struct *user = get_valid_user_struct(vuid);
4425 if (!user || user->guest) {
4426 return ERROR_NT(NT_STATUS_ACCESS_DENIED);
4430 rdata = (char *)SMB_MALLOC(1024);
4431 if (rdata) {
4432 memset(rdata,'\0',1024);
4435 rparam = (char *)SMB_MALLOC(1024);
4436 if (rparam) {
4437 memset(rparam,'\0',1024);
4440 if(!rdata || !rparam) {
4441 DEBUG(0,("api_reply: malloc fail !\n"));
4442 SAFE_FREE(rdata);
4443 SAFE_FREE(rparam);
4444 return -1;
4447 reply = api_commands[i].fn(conn,
4448 vuid,
4449 params,tpscnt, /* params + length */
4450 data,tdscnt, /* data + length */
4451 mdrcnt,mprcnt,
4452 &rdata,&rparam,&rdata_len,&rparam_len);
4455 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4456 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4457 &rdata,&rparam,&rdata_len,&rparam_len);
4460 /* if we get False back then it's actually unsupported */
4461 if (!reply) {
4462 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4463 &rdata,&rparam,&rdata_len,&rparam_len);
4466 /* If api_Unsupported returns false we can't return anything. */
4467 if (reply) {
4468 send_trans_reply(inbuf,
4469 outbuf,
4470 rparam,
4471 rparam_len,
4472 rdata,
4473 rdata_len,
4474 False);
4477 SAFE_FREE(rdata);
4478 SAFE_FREE(rparam);
4479 return -1;