r22044: Remove the only skip_string(...,2) caller
[Samba/gbeck.git] / source3 / smbd / lanman.c
blob1f38f65f3ed7e4a0aaf148aef5188d28b0192df7
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 This file handles the named pipe and mailslot calls
26 in the SMBtrans protocol
29 #include "includes.h"
31 extern struct current_user current_user;
32 extern userdom_struct current_user_info;
34 #ifdef CHECK_TYPES
35 #undef CHECK_TYPES
36 #endif
37 #define CHECK_TYPES 0
39 #define NERR_Success 0
40 #define NERR_badpass 86
41 #define NERR_notsupported 50
43 #define NERR_BASE (2100)
44 #define NERR_BufTooSmall (NERR_BASE+23)
45 #define NERR_JobNotFound (NERR_BASE+51)
46 #define NERR_DestNotFound (NERR_BASE+52)
48 #define ACCESS_READ 0x01
49 #define ACCESS_WRITE 0x02
50 #define ACCESS_CREATE 0x04
52 #define SHPWLEN 8 /* share password length */
54 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
55 char *param, int tpscnt,
56 char *data, int tdscnt,
57 int mdrcnt, int mprcnt,
58 char **rdata, char **rparam,
59 int *rdata_len, int *rparam_len);
61 static BOOL api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
62 int mdrcnt, int mprcnt,
63 char **rdata, char **rparam,
64 int *rdata_len, int *rparam_len);
67 static int CopyExpanded(connection_struct *conn,
68 int snum, char **dst, char *src, int *n)
70 pstring buf;
71 int l;
73 if (!src || !dst || !n || !(*dst)) {
74 return 0;
77 StrnCpy(buf,src,sizeof(buf)/2);
78 pstring_sub(buf,"%S",lp_servicename(snum));
79 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
80 conn->connectpath, conn->gid,
81 get_current_username(),
82 current_user_info.domain,
83 buf, sizeof(buf));
84 l = push_ascii(*dst,buf,*n, STR_TERMINATE);
85 (*dst) += l;
86 (*n) -= l;
87 return l;
90 static int CopyAndAdvance(char **dst, char *src, int *n)
92 int l;
93 if (!src || !dst || !n || !(*dst)) {
94 return 0;
96 l = push_ascii(*dst,src,*n, STR_TERMINATE);
97 (*dst) += l;
98 (*n) -= l;
99 return l;
102 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
104 pstring buf;
105 if (!s) {
106 return 0;
108 StrnCpy(buf,s,sizeof(buf)/2);
109 pstring_sub(buf,"%S",lp_servicename(snum));
110 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
111 conn->connectpath, conn->gid,
112 get_current_username(),
113 current_user_info.domain,
114 buf, sizeof(buf));
115 return strlen(buf) + 1;
118 static char *Expand(connection_struct *conn, int snum, char *s)
120 static pstring buf;
121 if (!s) {
122 return NULL;
124 StrnCpy(buf,s,sizeof(buf)/2);
125 pstring_sub(buf,"%S",lp_servicename(snum));
126 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
127 conn->connectpath, conn->gid,
128 get_current_username(),
129 current_user_info.domain,
130 buf, sizeof(buf));
131 return &buf[0];
134 /*******************************************************************
135 Check a API string for validity when we only need to check the prefix.
136 ******************************************************************/
138 static BOOL prefix_ok(const char *str, const char *prefix)
140 return(strncmp(str,prefix,strlen(prefix)) == 0);
143 struct pack_desc {
144 const char *format; /* formatstring for structure */
145 const char *subformat; /* subformat for structure */
146 char *base; /* baseaddress of buffer */
147 int buflen; /* remaining size for fixed part; on init: length of base */
148 int subcount; /* count of substructures */
149 char *structbuf; /* pointer into buffer for remaining fixed part */
150 int stringlen; /* remaining size for variable part */
151 char *stringbuf; /* pointer into buffer for remaining variable part */
152 int neededlen; /* total needed size */
153 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
154 const char *curpos; /* current position; pointer into format or subformat */
155 int errcode;
158 static int get_counter(const char **p)
160 int i, n;
161 if (!p || !(*p)) {
162 return 1;
164 if (!isdigit((int)**p)) {
165 return 1;
167 for (n = 0;;) {
168 i = **p;
169 if (isdigit(i)) {
170 n = 10 * n + (i - '0');
171 } else {
172 return n;
174 (*p)++;
178 static int getlen(const char *p)
180 int n = 0;
181 if (!p) {
182 return 0;
185 while (*p) {
186 switch( *p++ ) {
187 case 'W': /* word (2 byte) */
188 n += 2;
189 break;
190 case 'K': /* status word? (2 byte) */
191 n += 2;
192 break;
193 case 'N': /* count of substructures (word) at end */
194 n += 2;
195 break;
196 case 'D': /* double word (4 byte) */
197 case 'z': /* offset to zero terminated string (4 byte) */
198 case 'l': /* offset to user data (4 byte) */
199 n += 4;
200 break;
201 case 'b': /* offset to data (with counter) (4 byte) */
202 n += 4;
203 get_counter(&p);
204 break;
205 case 'B': /* byte (with optional counter) */
206 n += get_counter(&p);
207 break;
210 return n;
213 static BOOL init_package(struct pack_desc *p, int count, int subcount)
215 int n = p->buflen;
216 int i;
218 if (!p->format || !p->base) {
219 return False;
222 i = count * getlen(p->format);
223 if (p->subformat) {
224 i += subcount * getlen(p->subformat);
226 p->structbuf = p->base;
227 p->neededlen = 0;
228 p->usedlen = 0;
229 p->subcount = 0;
230 p->curpos = p->format;
231 if (i > n) {
232 p->neededlen = i;
233 i = n = 0;
234 #if 0
236 * This is the old error code we used. Aparently
237 * WinNT/2k systems return ERRbuftoosmall (2123) and
238 * OS/2 needs this. I'm leaving this here so we can revert
239 * if needed. JRA.
241 p->errcode = ERRmoredata;
242 #else
243 p->errcode = ERRbuftoosmall;
244 #endif
245 } else {
246 p->errcode = NERR_Success;
248 p->buflen = i;
249 n -= i;
250 p->stringbuf = p->base + i;
251 p->stringlen = n;
252 return (p->errcode == NERR_Success);
255 static int package(struct pack_desc *p, ...)
257 va_list args;
258 int needed=0, stringneeded;
259 const char *str=NULL;
260 int is_string=0, stringused;
261 int32 temp;
263 va_start(args,p);
265 if (!*p->curpos) {
266 if (!p->subcount) {
267 p->curpos = p->format;
268 } else {
269 p->curpos = p->subformat;
270 p->subcount--;
273 #if CHECK_TYPES
274 str = va_arg(args,char*);
275 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
276 #endif
277 stringneeded = -1;
279 if (!p->curpos) {
280 va_end(args);
281 return 0;
284 switch( *p->curpos++ ) {
285 case 'W': /* word (2 byte) */
286 needed = 2;
287 temp = va_arg(args,int);
288 if (p->buflen >= needed) {
289 SSVAL(p->structbuf,0,temp);
291 break;
292 case 'K': /* status word? (2 byte) */
293 needed = 2;
294 temp = va_arg(args,int);
295 if (p->buflen >= needed) {
296 SSVAL(p->structbuf,0,temp);
298 break;
299 case 'N': /* count of substructures (word) at end */
300 needed = 2;
301 p->subcount = va_arg(args,int);
302 if (p->buflen >= needed) {
303 SSVAL(p->structbuf,0,p->subcount);
305 break;
306 case 'D': /* double word (4 byte) */
307 needed = 4;
308 temp = va_arg(args,int);
309 if (p->buflen >= needed) {
310 SIVAL(p->structbuf,0,temp);
312 break;
313 case 'B': /* byte (with optional counter) */
314 needed = get_counter(&p->curpos);
316 char *s = va_arg(args,char*);
317 if (p->buflen >= needed) {
318 StrnCpy(p->structbuf,s?s:"",needed-1);
321 break;
322 case 'z': /* offset to zero terminated string (4 byte) */
323 str = va_arg(args,char*);
324 stringneeded = (str ? strlen(str)+1 : 0);
325 is_string = 1;
326 break;
327 case 'l': /* offset to user data (4 byte) */
328 str = va_arg(args,char*);
329 stringneeded = va_arg(args,int);
330 is_string = 0;
331 break;
332 case 'b': /* offset to data (with counter) (4 byte) */
333 str = va_arg(args,char*);
334 stringneeded = get_counter(&p->curpos);
335 is_string = 0;
336 break;
339 va_end(args);
340 if (stringneeded >= 0) {
341 needed = 4;
342 if (p->buflen >= needed) {
343 stringused = stringneeded;
344 if (stringused > p->stringlen) {
345 stringused = (is_string ? p->stringlen : 0);
346 if (p->errcode == NERR_Success) {
347 p->errcode = ERRmoredata;
350 if (!stringused) {
351 SIVAL(p->structbuf,0,0);
352 } else {
353 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
354 memcpy(p->stringbuf,str?str:"",stringused);
355 if (is_string) {
356 p->stringbuf[stringused-1] = '\0';
358 p->stringbuf += stringused;
359 p->stringlen -= stringused;
360 p->usedlen += stringused;
363 p->neededlen += stringneeded;
366 p->neededlen += needed;
367 if (p->buflen >= needed) {
368 p->structbuf += needed;
369 p->buflen -= needed;
370 p->usedlen += needed;
371 } else {
372 if (p->errcode == NERR_Success) {
373 p->errcode = ERRmoredata;
376 return 1;
379 #if CHECK_TYPES
380 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
381 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
382 #else
383 #define PACK(desc,t,v) package(desc,v)
384 #define PACKl(desc,t,v,l) package(desc,v,l)
385 #endif
387 static void PACKI(struct pack_desc* desc, const char *t,int v)
389 PACK(desc,t,v);
392 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
394 PACK(desc,t,v);
397 /****************************************************************************
398 Get a print queue.
399 ****************************************************************************/
401 static void PackDriverData(struct pack_desc* desc)
403 char drivdata[4+4+32];
404 SIVAL(drivdata,0,sizeof drivdata); /* cb */
405 SIVAL(drivdata,4,1000); /* lVersion */
406 memset(drivdata+8,0,32); /* szDeviceName */
407 push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
408 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
411 static int check_printq_info(struct pack_desc* desc,
412 unsigned int uLevel, char *id1, char *id2)
414 desc->subformat = NULL;
415 switch( uLevel ) {
416 case 0:
417 desc->format = "B13";
418 break;
419 case 1:
420 desc->format = "B13BWWWzzzzzWW";
421 break;
422 case 2:
423 desc->format = "B13BWWWzzzzzWN";
424 desc->subformat = "WB21BB16B10zWWzDDz";
425 break;
426 case 3:
427 desc->format = "zWWWWzzzzWWzzl";
428 break;
429 case 4:
430 desc->format = "zWWWWzzzzWNzzl";
431 desc->subformat = "WWzWWDDzz";
432 break;
433 case 5:
434 desc->format = "z";
435 break;
436 case 51:
437 desc->format = "K";
438 break;
439 case 52:
440 desc->format = "WzzzzzzzzN";
441 desc->subformat = "z";
442 break;
443 default:
444 return False;
446 if (strcmp(desc->format,id1) != 0) {
447 return False;
449 if (desc->subformat && strcmp(desc->subformat,id2) != 0) {
450 return False;
452 return True;
456 #define RAP_JOB_STATUS_QUEUED 0
457 #define RAP_JOB_STATUS_PAUSED 1
458 #define RAP_JOB_STATUS_SPOOLING 2
459 #define RAP_JOB_STATUS_PRINTING 3
460 #define RAP_JOB_STATUS_PRINTED 4
462 #define RAP_QUEUE_STATUS_PAUSED 1
463 #define RAP_QUEUE_STATUS_ERROR 2
465 /* turn a print job status into a on the wire status
467 static int printj_status(int v)
469 switch (v) {
470 case LPQ_QUEUED:
471 return RAP_JOB_STATUS_QUEUED;
472 case LPQ_PAUSED:
473 return RAP_JOB_STATUS_PAUSED;
474 case LPQ_SPOOLING:
475 return RAP_JOB_STATUS_SPOOLING;
476 case LPQ_PRINTING:
477 return RAP_JOB_STATUS_PRINTING;
479 return 0;
482 /* turn a print queue status into a on the wire status
484 static int printq_status(int v)
486 switch (v) {
487 case LPQ_QUEUED:
488 return 0;
489 case LPQ_PAUSED:
490 return RAP_QUEUE_STATUS_PAUSED;
492 return RAP_QUEUE_STATUS_ERROR;
495 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
496 struct pack_desc *desc,
497 print_queue_struct *queue, int n)
499 time_t t = queue->time;
501 /* the client expects localtime */
502 t -= get_time_zone(t);
504 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
505 if (uLevel == 1) {
506 PACKS(desc,"B21",queue->fs_user); /* szUserName */
507 PACKS(desc,"B",""); /* pad */
508 PACKS(desc,"B16",""); /* szNotifyName */
509 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
510 PACKS(desc,"z",""); /* pszParms */
511 PACKI(desc,"W",n+1); /* uPosition */
512 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
513 PACKS(desc,"z",""); /* pszStatus */
514 PACKI(desc,"D",t); /* ulSubmitted */
515 PACKI(desc,"D",queue->size); /* ulSize */
516 PACKS(desc,"z",queue->fs_file); /* pszComment */
518 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
519 PACKI(desc,"W",queue->priority); /* uPriority */
520 PACKS(desc,"z",queue->fs_user); /* pszUserName */
521 PACKI(desc,"W",n+1); /* uPosition */
522 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
523 PACKI(desc,"D",t); /* ulSubmitted */
524 PACKI(desc,"D",queue->size); /* ulSize */
525 PACKS(desc,"z","Samba"); /* pszComment */
526 PACKS(desc,"z",queue->fs_file); /* pszDocument */
527 if (uLevel == 3) {
528 PACKS(desc,"z",""); /* pszNotifyName */
529 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
530 PACKS(desc,"z",""); /* pszParms */
531 PACKS(desc,"z",""); /* pszStatus */
532 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
533 PACKS(desc,"z","lpd"); /* pszQProcName */
534 PACKS(desc,"z",""); /* pszQProcParms */
535 PACKS(desc,"z","NULL"); /* pszDriverName */
536 PackDriverData(desc); /* pDriverData */
537 PACKS(desc,"z",""); /* pszPrinterName */
538 } else if (uLevel == 4) { /* OS2 */
539 PACKS(desc,"z",""); /* pszSpoolFileName */
540 PACKS(desc,"z",""); /* pszPortName */
541 PACKS(desc,"z",""); /* pszStatus */
542 PACKI(desc,"D",0); /* ulPagesSpooled */
543 PACKI(desc,"D",0); /* ulPagesSent */
544 PACKI(desc,"D",0); /* ulPagesPrinted */
545 PACKI(desc,"D",0); /* ulTimePrinted */
546 PACKI(desc,"D",0); /* ulExtendJobStatus */
547 PACKI(desc,"D",0); /* ulStartPage */
548 PACKI(desc,"D",0); /* ulEndPage */
553 /********************************************************************
554 Return a driver name given an snum.
555 Returns True if from tdb, False otherwise.
556 ********************************************************************/
558 static BOOL get_driver_name(int snum, pstring drivername)
560 NT_PRINTER_INFO_LEVEL *info = NULL;
561 BOOL in_tdb = False;
563 get_a_printer (NULL, &info, 2, lp_servicename(snum));
564 if (info != NULL) {
565 pstrcpy( drivername, info->info_2->drivername);
566 in_tdb = True;
567 free_a_printer(&info, 2);
570 return in_tdb;
573 /********************************************************************
574 Respond to the DosPrintQInfo command with a level of 52
575 This is used to get printer driver information for Win9x clients
576 ********************************************************************/
577 static void fill_printq_info_52(connection_struct *conn, int snum,
578 struct pack_desc* desc, int count )
580 int i;
581 fstring location;
582 NT_PRINTER_DRIVER_INFO_LEVEL driver;
583 NT_PRINTER_INFO_LEVEL *printer = NULL;
585 ZERO_STRUCT(driver);
587 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
588 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
589 lp_servicename(snum)));
590 goto err;
593 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
594 "Windows 4.0", 0)) )
596 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
597 printer->info_2->drivername));
598 goto err;
601 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
602 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
603 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
605 PACKI(desc, "W", 0x0400); /* don't know */
606 PACKS(desc, "z", driver.info_3->name); /* long printer name */
607 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
608 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
609 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
611 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
612 standard_sub_basic( "", "", location, sizeof(location)-1 );
613 PACKS(desc,"z", location); /* share to retrieve files */
615 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
616 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
617 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
619 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
620 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
621 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
622 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
623 DEBUG(3,("Driver Location: %s:\n",location));
624 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
625 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
626 PACKI(desc,"N",count); /* number of files to copy */
628 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
630 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
631 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
632 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
635 /* sanity check */
636 if ( i != count )
637 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
638 count, i));
640 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
642 desc->errcode=NERR_Success;
643 goto done;
645 err:
646 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
647 desc->errcode=NERR_notsupported;
649 done:
650 if ( printer )
651 free_a_printer( &printer, 2 );
653 if ( driver.info_3 )
654 free_a_printer_driver( driver, 3 );
658 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
659 struct pack_desc* desc,
660 int count, print_queue_struct* queue,
661 print_status_struct* status)
663 switch (uLevel) {
664 case 1:
665 case 2:
666 PACKS(desc,"B13",SERVICE(snum));
667 break;
668 case 3:
669 case 4:
670 case 5:
671 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
672 break;
673 case 51:
674 PACKI(desc,"K",printq_status(status->status));
675 break;
678 if (uLevel == 1 || uLevel == 2) {
679 PACKS(desc,"B",""); /* alignment */
680 PACKI(desc,"W",5); /* priority */
681 PACKI(desc,"W",0); /* start time */
682 PACKI(desc,"W",0); /* until time */
683 PACKS(desc,"z",""); /* pSepFile */
684 PACKS(desc,"z","lpd"); /* pPrProc */
685 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
686 PACKS(desc,"z",""); /* pParms */
687 if (snum < 0) {
688 PACKS(desc,"z","UNKNOWN PRINTER");
689 PACKI(desc,"W",LPSTAT_ERROR);
691 else if (!status || !status->message[0]) {
692 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
693 PACKI(desc,"W",LPSTAT_OK); /* status */
694 } else {
695 PACKS(desc,"z",status->message);
696 PACKI(desc,"W",printq_status(status->status)); /* status */
698 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
701 if (uLevel == 3 || uLevel == 4) {
702 pstring drivername;
704 PACKI(desc,"W",5); /* uPriority */
705 PACKI(desc,"W",0); /* uStarttime */
706 PACKI(desc,"W",0); /* uUntiltime */
707 PACKI(desc,"W",5); /* pad1 */
708 PACKS(desc,"z",""); /* pszSepFile */
709 PACKS(desc,"z","WinPrint"); /* pszPrProc */
710 PACKS(desc,"z",NULL); /* pszParms */
711 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
712 /* "don't ask" that it's done this way to fix corrupted
713 Win9X/ME printer comments. */
714 if (!status) {
715 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
716 } else {
717 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
719 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
720 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
721 get_driver_name(snum,drivername);
722 PACKS(desc,"z",drivername); /* pszDriverName */
723 PackDriverData(desc); /* pDriverData */
726 if (uLevel == 2 || uLevel == 4) {
727 int i;
728 for (i=0;i<count;i++)
729 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
732 if (uLevel==52)
733 fill_printq_info_52( conn, snum, desc, count );
736 /* This function returns the number of files for a given driver */
737 static int get_printerdrivernumber(int snum)
739 int result = 0;
740 NT_PRINTER_DRIVER_INFO_LEVEL driver;
741 NT_PRINTER_INFO_LEVEL *printer = NULL;
743 ZERO_STRUCT(driver);
745 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
746 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
747 lp_servicename(snum)));
748 goto done;
751 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
752 "Windows 4.0", 0)) )
754 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
755 printer->info_2->drivername));
756 goto done;
759 /* count the number of files */
760 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
761 result++;
763 done:
764 if ( printer )
765 free_a_printer( &printer, 2 );
767 if ( driver.info_3 )
768 free_a_printer_driver( driver, 3 );
770 return result;
773 static BOOL api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
774 char *param, int tpscnt,
775 char *data, int tdscnt,
776 int mdrcnt,int mprcnt,
777 char **rdata,char **rparam,
778 int *rdata_len,int *rparam_len)
780 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
781 char *str2 = skip_string(param,tpscnt,str1,1);
782 char *p = skip_string(param,tpscnt,str2,1);
783 char *QueueName = p;
784 unsigned int uLevel;
785 int count=0;
786 int snum;
787 char *str3;
788 struct pack_desc desc;
789 print_queue_struct *queue=NULL;
790 print_status_struct status;
791 char* tmpdata=NULL;
793 if (!str1 || !str2 || !p) {
794 return False;
796 memset((char *)&status,'\0',sizeof(status));
797 memset((char *)&desc,'\0',sizeof(desc));
799 p = skip_string(param,tpscnt,p,1);
800 if (!p) {
801 return False;
803 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
804 str3 = get_safe_str_ptr(param,tpscnt,p,4);
805 if (!str3) {
806 return False;
809 /* remove any trailing username */
810 if ((p = strchr_m(QueueName,'%')))
811 *p = 0;
813 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
815 /* check it's a supported varient */
816 if (!prefix_ok(str1,"zWrLh"))
817 return False;
818 if (!check_printq_info(&desc,uLevel,str2,str3)) {
820 * Patch from Scott Moomaw <scott@bridgewater.edu>
821 * to return the 'invalid info level' error if an
822 * unknown level was requested.
824 *rdata_len = 0;
825 *rparam_len = 6;
826 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
827 if (!*rparam) {
828 return False;
830 SSVALS(*rparam,0,ERRunknownlevel);
831 SSVAL(*rparam,2,0);
832 SSVAL(*rparam,4,0);
833 return(True);
836 snum = find_service(QueueName);
837 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
838 return False;
840 if (uLevel==52) {
841 count = get_printerdrivernumber(snum);
842 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
843 } else {
844 count = print_queue_status(snum, &queue,&status);
847 if (mdrcnt > 0) {
848 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
849 if (!*rdata) {
850 return False;
852 desc.base = *rdata;
853 desc.buflen = mdrcnt;
854 } else {
856 * Don't return data but need to get correct length
857 * init_package will return wrong size if buflen=0
859 desc.buflen = getlen(desc.format);
860 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
863 if (init_package(&desc,1,count)) {
864 desc.subcount = count;
865 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
868 *rdata_len = desc.usedlen;
871 * We must set the return code to ERRbuftoosmall
872 * in order to support lanman style printing with Win NT/2k
873 * clients --jerry
875 if (!mdrcnt && lp_disable_spoolss())
876 desc.errcode = ERRbuftoosmall;
878 *rdata_len = desc.usedlen;
879 *rparam_len = 6;
880 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
881 if (!*rparam) {
882 return False;
884 SSVALS(*rparam,0,desc.errcode);
885 SSVAL(*rparam,2,0);
886 SSVAL(*rparam,4,desc.neededlen);
888 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
890 SAFE_FREE(queue);
891 SAFE_FREE(tmpdata);
893 return(True);
896 /****************************************************************************
897 View list of all print jobs on all queues.
898 ****************************************************************************/
900 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
901 char *param, int tpscnt,
902 char *data, int tdscnt,
903 int mdrcnt, int mprcnt,
904 char **rdata, char** rparam,
905 int *rdata_len, int *rparam_len)
907 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
908 char *output_format1 = skip_string(param,tpscnt,param_format,1);
909 char *p = skip_string(param,tpscnt,output_format1,1);
910 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
911 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
912 int services = lp_numservices();
913 int i, n;
914 struct pack_desc desc;
915 print_queue_struct **queue = NULL;
916 print_status_struct *status = NULL;
917 int *subcntarr = NULL;
918 int queuecnt = 0, subcnt = 0, succnt = 0;
920 if (!param_format || !output_format1 || !p || !output_format2) {
921 return False;
924 memset((char *)&desc,'\0',sizeof(desc));
926 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
928 if (!prefix_ok(param_format,"WrLeh")) {
929 return False;
931 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
933 * Patch from Scott Moomaw <scott@bridgewater.edu>
934 * to return the 'invalid info level' error if an
935 * unknown level was requested.
937 *rdata_len = 0;
938 *rparam_len = 6;
939 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
940 if (!*rparam) {
941 return False;
943 SSVALS(*rparam,0,ERRunknownlevel);
944 SSVAL(*rparam,2,0);
945 SSVAL(*rparam,4,0);
946 return(True);
949 for (i = 0; i < services; i++) {
950 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
951 queuecnt++;
955 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
956 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
957 goto err;
959 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
960 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
961 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
962 goto err;
964 memset(status,0,queuecnt*sizeof(print_status_struct));
965 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
966 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
967 goto err;
970 subcnt = 0;
971 n = 0;
972 for (i = 0; i < services; i++) {
973 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
974 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
975 subcnt += subcntarr[n];
976 n++;
980 if (mdrcnt > 0) {
981 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
982 if (!*rdata) {
983 goto err;
986 desc.base = *rdata;
987 desc.buflen = mdrcnt;
989 if (init_package(&desc,queuecnt,subcnt)) {
990 n = 0;
991 succnt = 0;
992 for (i = 0; i < services; i++) {
993 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
994 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
995 n++;
996 if (desc.errcode == NERR_Success) {
997 succnt = n;
1003 SAFE_FREE(subcntarr);
1005 *rdata_len = desc.usedlen;
1006 *rparam_len = 8;
1007 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1008 if (!*rparam) {
1009 goto err;
1011 SSVALS(*rparam,0,desc.errcode);
1012 SSVAL(*rparam,2,0);
1013 SSVAL(*rparam,4,succnt);
1014 SSVAL(*rparam,6,queuecnt);
1016 for (i = 0; i < queuecnt; i++) {
1017 if (queue) {
1018 SAFE_FREE(queue[i]);
1022 SAFE_FREE(queue);
1023 SAFE_FREE(status);
1025 return True;
1027 err:
1029 SAFE_FREE(subcntarr);
1030 for (i = 0; i < queuecnt; i++) {
1031 if (queue) {
1032 SAFE_FREE(queue[i]);
1035 SAFE_FREE(queue);
1036 SAFE_FREE(status);
1038 return False;
1041 /****************************************************************************
1042 Get info level for a server list query.
1043 ****************************************************************************/
1045 static BOOL check_server_info(int uLevel, char* id)
1047 switch( uLevel ) {
1048 case 0:
1049 if (strcmp(id,"B16") != 0) {
1050 return False;
1052 break;
1053 case 1:
1054 if (strcmp(id,"B16BBDz") != 0) {
1055 return False;
1057 break;
1058 default:
1059 return False;
1061 return True;
1064 struct srv_info_struct {
1065 fstring name;
1066 uint32 type;
1067 fstring comment;
1068 fstring domain;
1069 BOOL server_added;
1072 /*******************************************************************
1073 Get server info lists from the files saved by nmbd. Return the
1074 number of entries.
1075 ******************************************************************/
1077 static int get_server_info(uint32 servertype,
1078 struct srv_info_struct **servers,
1079 const char *domain)
1081 int count=0;
1082 int alloced=0;
1083 char **lines;
1084 BOOL local_list_only;
1085 int i;
1087 lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1088 if (!lines) {
1089 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1090 return 0;
1093 /* request for everything is code for request all servers */
1094 if (servertype == SV_TYPE_ALL) {
1095 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1098 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1100 DEBUG(4,("Servertype search: %8x\n",servertype));
1102 for (i=0;lines[i];i++) {
1103 fstring stype;
1104 struct srv_info_struct *s;
1105 const char *ptr = lines[i];
1106 BOOL ok = True;
1108 if (!*ptr) {
1109 continue;
1112 if (count == alloced) {
1113 alloced += 10;
1114 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1115 if (!*servers) {
1116 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1117 file_lines_free(lines);
1118 return 0;
1120 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1122 s = &(*servers)[count];
1124 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1125 continue;
1127 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1128 continue;
1130 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1131 continue;
1133 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1134 /* this allows us to cope with an old nmbd */
1135 fstrcpy(s->domain,lp_workgroup());
1138 if (sscanf(stype,"%X",&s->type) != 1) {
1139 DEBUG(4,("r:host file "));
1140 ok = False;
1143 /* Filter the servers/domains we return based on what was asked for. */
1145 /* Check to see if we are being asked for a local list only. */
1146 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1147 DEBUG(4,("r: local list only"));
1148 ok = False;
1151 /* doesn't match up: don't want it */
1152 if (!(servertype & s->type)) {
1153 DEBUG(4,("r:serv type "));
1154 ok = False;
1157 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1158 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1159 DEBUG(4,("s: dom mismatch "));
1160 ok = False;
1163 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1164 ok = False;
1167 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1168 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1170 if (ok) {
1171 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1172 s->name, s->type, s->comment, s->domain));
1173 s->server_added = True;
1174 count++;
1175 } else {
1176 DEBUG(4,("%20s %8x %25s %15s\n",
1177 s->name, s->type, s->comment, s->domain));
1181 file_lines_free(lines);
1182 return count;
1185 /*******************************************************************
1186 Fill in a server info structure.
1187 ******************************************************************/
1189 static int fill_srv_info(struct srv_info_struct *service,
1190 int uLevel, char **buf, int *buflen,
1191 char **stringbuf, int *stringspace, char *baseaddr)
1193 int struct_len;
1194 char* p;
1195 char* p2;
1196 int l2;
1197 int len;
1199 switch (uLevel) {
1200 case 0:
1201 struct_len = 16;
1202 break;
1203 case 1:
1204 struct_len = 26;
1205 break;
1206 default:
1207 return -1;
1210 if (!buf) {
1211 len = 0;
1212 switch (uLevel) {
1213 case 1:
1214 len = strlen(service->comment)+1;
1215 break;
1218 *buflen = struct_len;
1219 *stringspace = len;
1220 return struct_len + len;
1223 len = struct_len;
1224 p = *buf;
1225 if (*buflen < struct_len) {
1226 return -1;
1228 if (stringbuf) {
1229 p2 = *stringbuf;
1230 l2 = *stringspace;
1231 } else {
1232 p2 = p + struct_len;
1233 l2 = *buflen - struct_len;
1235 if (!baseaddr) {
1236 baseaddr = p;
1239 switch (uLevel) {
1240 case 0:
1241 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1242 break;
1244 case 1:
1245 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1246 SIVAL(p,18,service->type);
1247 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1248 len += CopyAndAdvance(&p2,service->comment,&l2);
1249 break;
1252 if (stringbuf) {
1253 *buf = p + struct_len;
1254 *buflen -= struct_len;
1255 *stringbuf = p2;
1256 *stringspace = l2;
1257 } else {
1258 *buf = p2;
1259 *buflen -= len;
1261 return len;
1265 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1267 return(strcmp(s1->name,s2->name));
1270 /****************************************************************************
1271 View list of servers available (or possibly domains). The info is
1272 extracted from lists saved by nmbd on the local host.
1273 ****************************************************************************/
1275 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1276 char *param, int tpscnt,
1277 char *data, int tdscnt,
1278 int mdrcnt, int mprcnt, char **rdata,
1279 char **rparam, int *rdata_len, int *rparam_len)
1281 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1282 char *str2 = skip_string(param,tpscnt,str1,1);
1283 char *p = skip_string(param,tpscnt,str2,1);
1284 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1285 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1286 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1287 char *p2;
1288 int data_len, fixed_len, string_len;
1289 int f_len = 0, s_len = 0;
1290 struct srv_info_struct *servers=NULL;
1291 int counted=0,total=0;
1292 int i,missed;
1293 fstring domain;
1294 BOOL domain_request;
1295 BOOL local_request;
1297 if (!str1 || !str2 || !p) {
1298 return False;
1301 /* If someone sets all the bits they don't really mean to set
1302 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1303 known servers. */
1305 if (servertype == SV_TYPE_ALL) {
1306 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1309 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1310 any other bit (they may just set this bit on it's own) they
1311 want all the locally seen servers. However this bit can be
1312 set on its own so set the requested servers to be
1313 ALL - DOMAIN_ENUM. */
1315 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1316 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1319 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1320 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1322 p += 8;
1324 if (!prefix_ok(str1,"WrLehD")) {
1325 return False;
1327 if (!check_server_info(uLevel,str2)) {
1328 return False;
1331 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1332 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1333 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1335 if (strcmp(str1, "WrLehDz") == 0) {
1336 if (skip_string(param,tpscnt,p,1) == NULL) {
1337 return False;
1339 pull_ascii_fstring(domain, p);
1340 } else {
1341 fstrcpy(domain, lp_workgroup());
1344 if (lp_browse_list()) {
1345 total = get_server_info(servertype,&servers,domain);
1348 data_len = fixed_len = string_len = 0;
1349 missed = 0;
1351 if (total > 0) {
1352 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1356 char *lastname=NULL;
1358 for (i=0;i<total;i++) {
1359 struct srv_info_struct *s = &servers[i];
1361 if (lastname && strequal(lastname,s->name)) {
1362 continue;
1364 lastname = s->name;
1365 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1366 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1367 s->name, s->type, s->comment, s->domain));
1369 if (data_len <= buf_len) {
1370 counted++;
1371 fixed_len += f_len;
1372 string_len += s_len;
1373 } else {
1374 missed++;
1379 *rdata_len = fixed_len + string_len;
1380 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1381 if (!*rdata) {
1382 return False;
1384 memset(*rdata,'\0',*rdata_len);
1386 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1387 p = *rdata;
1388 f_len = fixed_len;
1389 s_len = string_len;
1392 char *lastname=NULL;
1393 int count2 = counted;
1395 for (i = 0; i < total && count2;i++) {
1396 struct srv_info_struct *s = &servers[i];
1398 if (lastname && strequal(lastname,s->name)) {
1399 continue;
1401 lastname = s->name;
1402 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1403 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1404 s->name, s->type, s->comment, s->domain));
1405 count2--;
1409 *rparam_len = 8;
1410 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1411 if (!*rparam) {
1412 return False;
1414 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1415 SSVAL(*rparam,2,0);
1416 SSVAL(*rparam,4,counted);
1417 SSVAL(*rparam,6,counted+missed);
1419 SAFE_FREE(servers);
1421 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1422 domain,uLevel,counted,counted+missed));
1424 return True;
1427 /****************************************************************************
1428 command 0x34 - suspected of being a "Lookup Names" stub api
1429 ****************************************************************************/
1431 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1432 char *param, int tpscnt,
1433 char *data, int tdscnt,
1434 int mdrcnt, int mprcnt, char **rdata,
1435 char **rparam, int *rdata_len, int *rparam_len)
1437 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1438 char *str2 = skip_string(param,tpscnt,str1,1);
1439 char *p = skip_string(param,tpscnt,str2,1);
1440 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1441 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1442 int counted=0;
1443 int missed=0;
1445 if (!str1 || !str2 || !p) {
1446 return False;
1449 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1450 str1, str2, p, uLevel, buf_len));
1452 if (!prefix_ok(str1,"zWrLeh")) {
1453 return False;
1456 *rdata_len = 0;
1458 *rparam_len = 8;
1459 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1460 if (!*rparam) {
1461 return False;
1464 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1465 SSVAL(*rparam,2,0);
1466 SSVAL(*rparam,4,counted);
1467 SSVAL(*rparam,6,counted+missed);
1469 return True;
1472 /****************************************************************************
1473 get info about a share
1474 ****************************************************************************/
1476 static BOOL check_share_info(int uLevel, char* id)
1478 switch( uLevel ) {
1479 case 0:
1480 if (strcmp(id,"B13") != 0) {
1481 return False;
1483 break;
1484 case 1:
1485 if (strcmp(id,"B13BWz") != 0) {
1486 return False;
1488 break;
1489 case 2:
1490 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1491 return False;
1493 break;
1494 case 91:
1495 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1496 return False;
1498 break;
1499 default:
1500 return False;
1502 return True;
1505 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1506 char** buf, int* buflen,
1507 char** stringbuf, int* stringspace, char* baseaddr)
1509 int struct_len;
1510 char* p;
1511 char* p2;
1512 int l2;
1513 int len;
1515 switch( uLevel ) {
1516 case 0:
1517 struct_len = 13;
1518 break;
1519 case 1:
1520 struct_len = 20;
1521 break;
1522 case 2:
1523 struct_len = 40;
1524 break;
1525 case 91:
1526 struct_len = 68;
1527 break;
1528 default:
1529 return -1;
1533 if (!buf) {
1534 len = 0;
1536 if (uLevel > 0) {
1537 len += StrlenExpanded(conn,snum,lp_comment(snum));
1539 if (uLevel > 1) {
1540 len += strlen(lp_pathname(snum)) + 1;
1542 if (buflen) {
1543 *buflen = struct_len;
1545 if (stringspace) {
1546 *stringspace = len;
1548 return struct_len + len;
1551 len = struct_len;
1552 p = *buf;
1553 if ((*buflen) < struct_len) {
1554 return -1;
1557 if (stringbuf) {
1558 p2 = *stringbuf;
1559 l2 = *stringspace;
1560 } else {
1561 p2 = p + struct_len;
1562 l2 = (*buflen) - struct_len;
1565 if (!baseaddr) {
1566 baseaddr = p;
1569 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1571 if (uLevel > 0) {
1572 int type;
1574 SCVAL(p,13,0);
1575 type = STYPE_DISKTREE;
1576 if (lp_print_ok(snum)) {
1577 type = STYPE_PRINTQ;
1579 if (strequal("IPC",lp_fstype(snum))) {
1580 type = STYPE_IPC;
1582 SSVAL(p,14,type); /* device type */
1583 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1584 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1587 if (uLevel > 1) {
1588 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1589 SSVALS(p,22,-1); /* max uses */
1590 SSVAL(p,24,1); /* current uses */
1591 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1592 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1593 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1596 if (uLevel > 2) {
1597 memset(p+40,0,SHPWLEN+2);
1598 SSVAL(p,50,0);
1599 SIVAL(p,52,0);
1600 SSVAL(p,56,0);
1601 SSVAL(p,58,0);
1602 SIVAL(p,60,0);
1603 SSVAL(p,64,0);
1604 SSVAL(p,66,0);
1607 if (stringbuf) {
1608 (*buf) = p + struct_len;
1609 (*buflen) -= struct_len;
1610 (*stringbuf) = p2;
1611 (*stringspace) = l2;
1612 } else {
1613 (*buf) = p2;
1614 (*buflen) -= len;
1617 return len;
1620 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1621 char *param, int tpscnt,
1622 char *data, int tdscnt,
1623 int mdrcnt,int mprcnt,
1624 char **rdata,char **rparam,
1625 int *rdata_len,int *rparam_len)
1627 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1628 char *str2 = skip_string(param,tpscnt,str1,1);
1629 char *netname = skip_string(param,tpscnt,str2,1);
1630 char *p = skip_string(param,tpscnt,netname,1);
1631 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1632 int snum;
1634 if (!str1 || !str2 || !netname || !p) {
1635 return False;
1638 snum = find_service(netname);
1639 if (snum < 0) {
1640 return False;
1643 /* check it's a supported varient */
1644 if (!prefix_ok(str1,"zWrLh")) {
1645 return False;
1647 if (!check_share_info(uLevel,str2)) {
1648 return False;
1651 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
1652 if (!*rdata) {
1653 return False;
1655 p = *rdata;
1656 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1657 if (*rdata_len < 0) {
1658 return False;
1661 *rparam_len = 6;
1662 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1663 if (!*rparam) {
1664 return False;
1666 SSVAL(*rparam,0,NERR_Success);
1667 SSVAL(*rparam,2,0); /* converter word */
1668 SSVAL(*rparam,4,*rdata_len);
1670 return True;
1673 /****************************************************************************
1674 View the list of available shares.
1676 This function is the server side of the NetShareEnum() RAP call.
1677 It fills the return buffer with share names and share comments.
1678 Note that the return buffer normally (in all known cases) allows only
1679 twelve byte strings for share names (plus one for a nul terminator).
1680 Share names longer than 12 bytes must be skipped.
1681 ****************************************************************************/
1683 static BOOL api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1684 char *param, int tpscnt,
1685 char *data, int tdscnt,
1686 int mdrcnt,
1687 int mprcnt,
1688 char **rdata,
1689 char **rparam,
1690 int *rdata_len,
1691 int *rparam_len )
1693 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1694 char *str2 = skip_string(param,tpscnt,str1,1);
1695 char *p = skip_string(param,tpscnt,str2,1);
1696 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1697 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1698 char *p2;
1699 int count = 0;
1700 int total=0,counted=0;
1701 BOOL missed = False;
1702 int i;
1703 int data_len, fixed_len, string_len;
1704 int f_len = 0, s_len = 0;
1706 if (!str1 || !str2 || !p) {
1707 return False;
1710 if (!prefix_ok(str1,"WrLeh")) {
1711 return False;
1713 if (!check_share_info(uLevel,str2)) {
1714 return False;
1717 /* Ensure all the usershares are loaded. */
1718 become_root();
1719 load_registry_shares();
1720 count = load_usershare_shares();
1721 unbecome_root();
1723 data_len = fixed_len = string_len = 0;
1724 for (i=0;i<count;i++) {
1725 fstring servicename_dos;
1726 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1727 continue;
1729 push_ascii_fstring(servicename_dos, lp_servicename(i));
1730 /* Maximum name length = 13. */
1731 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1732 total++;
1733 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1734 if (data_len <= buf_len) {
1735 counted++;
1736 fixed_len += f_len;
1737 string_len += s_len;
1738 } else {
1739 missed = True;
1744 *rdata_len = fixed_len + string_len;
1745 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1746 if (!*rdata) {
1747 return False;
1749 memset(*rdata,0,*rdata_len);
1751 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1752 p = *rdata;
1753 f_len = fixed_len;
1754 s_len = string_len;
1756 for( i = 0; i < count; i++ ) {
1757 fstring servicename_dos;
1758 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1759 continue;
1762 push_ascii_fstring(servicename_dos, lp_servicename(i));
1763 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1764 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1765 break;
1770 *rparam_len = 8;
1771 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1772 if (!*rparam) {
1773 return False;
1775 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1776 SSVAL(*rparam,2,0);
1777 SSVAL(*rparam,4,counted);
1778 SSVAL(*rparam,6,total);
1780 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1781 counted,total,uLevel,
1782 buf_len,*rdata_len,mdrcnt));
1784 return True;
1787 /****************************************************************************
1788 Add a share
1789 ****************************************************************************/
1791 static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1792 char *param, int tpscnt,
1793 char *data, int tdscnt,
1794 int mdrcnt,int mprcnt,
1795 char **rdata,char **rparam,
1796 int *rdata_len,int *rparam_len)
1798 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1799 char *str2 = skip_string(param,tpscnt,str1,1);
1800 char *p = skip_string(param,tpscnt,str2,1);
1801 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1802 fstring sharename;
1803 fstring comment;
1804 pstring pathname;
1805 char *command, *cmdname;
1806 unsigned int offset;
1807 int snum;
1808 int res = ERRunsup;
1810 if (!str1 || !str2 || !p) {
1811 return False;
1814 /* check it's a supported varient */
1815 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1816 return False;
1818 if (!check_share_info(uLevel,str2)) {
1819 return False;
1821 if (uLevel != 2) {
1822 return False;
1825 /* Do we have a string ? */
1826 if (skip_string(data,mdrcnt,data,1) == NULL) {
1827 return False;
1829 pull_ascii_fstring(sharename,data);
1830 snum = find_service(sharename);
1831 if (snum >= 0) { /* already exists */
1832 res = ERRfilexists;
1833 goto error_exit;
1836 if (mdrcnt < 28) {
1837 return False;
1840 /* only support disk share adds */
1841 if (SVAL(data,14)!=STYPE_DISKTREE) {
1842 return False;
1845 offset = IVAL(data, 16);
1846 if (offset >= mdrcnt) {
1847 res = ERRinvalidparam;
1848 goto error_exit;
1851 /* Do we have a string ? */
1852 if (skip_string(data,mdrcnt,data+offset,1) == NULL) {
1853 return False;
1855 pull_ascii_fstring(comment, offset? (data+offset) : "");
1857 offset = IVAL(data, 26);
1859 if (offset >= mdrcnt) {
1860 res = ERRinvalidparam;
1861 goto error_exit;
1864 /* Do we have a string ? */
1865 if (skip_string(data,mdrcnt,data+offset,1) == NULL) {
1866 return False;
1868 pull_ascii_pstring(pathname, offset? (data+offset) : "");
1870 string_replace(sharename, '"', ' ');
1871 string_replace(pathname, '"', ' ');
1872 string_replace(comment, '"', ' ');
1874 cmdname = lp_add_share_cmd();
1876 if (!cmdname || *cmdname == '\0') {
1877 return False;
1880 asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1881 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1883 if (command) {
1884 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1886 if ((res = smbrun(command, NULL)) != 0) {
1887 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1888 SAFE_FREE(command);
1889 res = ERRnoaccess;
1890 goto error_exit;
1891 } else {
1892 SAFE_FREE(command);
1893 message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
1895 } else {
1896 return False;
1899 *rparam_len = 6;
1900 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1901 if (!*rparam) {
1902 return False;
1904 SSVAL(*rparam,0,NERR_Success);
1905 SSVAL(*rparam,2,0); /* converter word */
1906 SSVAL(*rparam,4,*rdata_len);
1907 *rdata_len = 0;
1909 return True;
1911 error_exit:
1913 *rparam_len = 4;
1914 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1915 if (!*rparam) {
1916 return False;
1918 *rdata_len = 0;
1919 SSVAL(*rparam,0,res);
1920 SSVAL(*rparam,2,0);
1921 return True;
1924 /****************************************************************************
1925 view list of groups available
1926 ****************************************************************************/
1928 static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
1929 char *param, int tpscnt,
1930 char *data, int tdscnt,
1931 int mdrcnt,int mprcnt,
1932 char **rdata,char **rparam,
1933 int *rdata_len,int *rparam_len)
1935 int i;
1936 int errflags=0;
1937 int resume_context, cli_buf_size;
1938 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1939 char *str2 = skip_string(param,tpscnt,str1,1);
1940 char *p = skip_string(param,tpscnt,str2,1);
1942 struct pdb_search *search;
1943 struct samr_displayentry *entries;
1945 int num_entries;
1947 if (!str1 || !str2 || !p) {
1948 return False;
1951 if (strcmp(str1,"WrLeh") != 0) {
1952 return False;
1955 /* parameters
1956 * W-> resume context (number of users to skip)
1957 * r -> return parameter pointer to receive buffer
1958 * L -> length of receive buffer
1959 * e -> return parameter number of entries
1960 * h -> return parameter total number of users
1963 if (strcmp("B21",str2) != 0) {
1964 return False;
1967 /* get list of domain groups SID_DOMAIN_GRP=2 */
1968 become_root();
1969 search = pdb_search_groups();
1970 unbecome_root();
1972 if (search == NULL) {
1973 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1974 return False;
1977 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
1978 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
1979 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1980 "%d\n", resume_context, cli_buf_size));
1982 become_root();
1983 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1984 &entries);
1985 unbecome_root();
1987 *rdata_len = cli_buf_size;
1988 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1989 if (!*rdata) {
1990 return False;
1993 p = *rdata;
1995 for(i=0; i<num_entries; i++) {
1996 fstring name;
1997 fstrcpy(name, entries[i].account_name);
1998 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
1999 /* truncate the name at 21 chars. */
2000 memcpy(p, name, 21);
2001 DEBUG(10,("adding entry %d group %s\n", i, p));
2002 p += 21;
2003 p += 5; /* Both NT4 and W2k3SP1 do padding here.
2004 No idea why... */
2005 } else {
2006 /* set overflow error */
2007 DEBUG(3,("overflow on entry %d group %s\n", i, name));
2008 errflags=234;
2009 break;
2013 pdb_search_destroy(search);
2015 *rdata_len = PTR_DIFF(p,*rdata);
2017 *rparam_len = 8;
2018 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2019 if (!*rparam) {
2020 return False;
2022 SSVAL(*rparam, 0, errflags);
2023 SSVAL(*rparam, 2, 0); /* converter word */
2024 SSVAL(*rparam, 4, i); /* is this right?? */
2025 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
2027 return(True);
2030 /*******************************************************************
2031 Get groups that a user is a member of.
2032 ******************************************************************/
2034 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2035 char *param, int tpscnt,
2036 char *data, int tdscnt,
2037 int mdrcnt,int mprcnt,
2038 char **rdata,char **rparam,
2039 int *rdata_len,int *rparam_len)
2041 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2042 char *str2 = skip_string(param,tpscnt,str1,1);
2043 char *UserName = skip_string(param,tpscnt,str2,1);
2044 char *p = skip_string(param,tpscnt,UserName,1);
2045 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2046 const char *level_string;
2047 int count=0;
2048 struct samu *sampw = NULL;
2049 BOOL ret = False;
2050 DOM_SID *sids;
2051 gid_t *gids;
2052 size_t num_groups;
2053 size_t i;
2054 NTSTATUS result;
2055 DOM_SID user_sid;
2056 enum lsa_SidType type;
2057 TALLOC_CTX *mem_ctx;
2059 if (!str1 || !str2 || !UserName || !p) {
2060 return False;
2063 *rparam_len = 8;
2064 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2065 if (!*rparam) {
2066 return False;
2069 /* check it's a supported varient */
2071 if ( strcmp(str1,"zWrLeh") != 0 )
2072 return False;
2074 switch( uLevel ) {
2075 case 0:
2076 level_string = "B21";
2077 break;
2078 default:
2079 return False;
2082 if (strcmp(level_string,str2) != 0)
2083 return False;
2085 *rdata_len = mdrcnt + 1024;
2086 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2087 if (!*rdata) {
2088 return False;
2090 SSVAL(*rparam,0,NERR_Success);
2091 SSVAL(*rparam,2,0); /* converter word */
2093 p = *rdata;
2095 mem_ctx = talloc_new(NULL);
2096 if (mem_ctx == NULL) {
2097 DEBUG(0, ("talloc_new failed\n"));
2098 return False;
2101 if ( !(sampw = samu_new(mem_ctx)) ) {
2102 DEBUG(0, ("samu_new() failed!\n"));
2103 TALLOC_FREE(mem_ctx);
2104 return False;
2107 /* Lookup the user information; This should only be one of
2108 our accounts (not remote domains) */
2110 become_root(); /* ROOT BLOCK */
2112 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2113 NULL, NULL, &user_sid, &type)) {
2114 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2115 goto done;
2118 if (type != SID_NAME_USER) {
2119 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2120 sid_type_lookup(type)));
2121 goto done;
2124 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2125 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2126 sid_string_static(&user_sid), UserName));
2127 goto done;
2130 gids = NULL;
2131 sids = NULL;
2132 num_groups = 0;
2134 result = pdb_enum_group_memberships(mem_ctx, sampw,
2135 &sids, &gids, &num_groups);
2137 if (!NT_STATUS_IS_OK(result)) {
2138 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2139 UserName));
2140 goto done;
2143 for (i=0; i<num_groups; i++) {
2145 const char *grp_name;
2147 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2148 pstrcpy(p, grp_name);
2149 p += 21;
2150 count++;
2154 *rdata_len = PTR_DIFF(p,*rdata);
2156 SSVAL(*rparam,4,count); /* is this right?? */
2157 SSVAL(*rparam,6,count); /* is this right?? */
2159 ret = True;
2161 done:
2162 unbecome_root(); /* END ROOT BLOCK */
2164 TALLOC_FREE(mem_ctx);
2166 return ret;
2169 /*******************************************************************
2170 Get all users.
2171 ******************************************************************/
2173 static BOOL api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2174 char *param, int tpscnt,
2175 char *data, int tdscnt,
2176 int mdrcnt,int mprcnt,
2177 char **rdata,char **rparam,
2178 int *rdata_len,int *rparam_len)
2180 int count_sent=0;
2181 int num_users=0;
2182 int errflags=0;
2183 int i, resume_context, cli_buf_size;
2184 struct pdb_search *search;
2185 struct samr_displayentry *users;
2187 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2188 char *str2 = skip_string(param,tpscnt,str1,1);
2189 char *p = skip_string(param,tpscnt,str2,1);
2191 if (!str1 || !str2 || !p) {
2192 return False;
2195 if (strcmp(str1,"WrLeh") != 0)
2196 return False;
2197 /* parameters
2198 * W-> resume context (number of users to skip)
2199 * r -> return parameter pointer to receive buffer
2200 * L -> length of receive buffer
2201 * e -> return parameter number of entries
2202 * h -> return parameter total number of users
2205 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2206 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2207 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2208 resume_context, cli_buf_size));
2210 *rparam_len = 8;
2211 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2212 if (!*rparam) {
2213 return False;
2216 /* check it's a supported varient */
2217 if (strcmp("B21",str2) != 0)
2218 return False;
2220 *rdata_len = cli_buf_size;
2221 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2222 if (!*rdata) {
2223 return False;
2226 p = *rdata;
2228 become_root();
2229 search = pdb_search_users(ACB_NORMAL);
2230 unbecome_root();
2231 if (search == NULL) {
2232 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2233 return False;
2236 become_root();
2237 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2238 &users);
2239 unbecome_root();
2241 errflags=NERR_Success;
2243 for (i=0; i<num_users; i++) {
2244 const char *name = users[i].account_name;
2246 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2247 pstrcpy(p,name);
2248 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2249 "%s\n",count_sent,p));
2250 p += 21;
2251 count_sent++;
2252 } else {
2253 /* set overflow error */
2254 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2255 "username %s\n",count_sent,name));
2256 errflags=234;
2257 break;
2261 pdb_search_destroy(search);
2263 *rdata_len = PTR_DIFF(p,*rdata);
2265 SSVAL(*rparam,0,errflags);
2266 SSVAL(*rparam,2,0); /* converter word */
2267 SSVAL(*rparam,4,count_sent); /* is this right?? */
2268 SSVAL(*rparam,6,num_users); /* is this right?? */
2270 return True;
2273 /****************************************************************************
2274 Get the time of day info.
2275 ****************************************************************************/
2277 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2278 char *param, int tpscnt,
2279 char *data, int tdscnt,
2280 int mdrcnt,int mprcnt,
2281 char **rdata,char **rparam,
2282 int *rdata_len,int *rparam_len)
2284 struct tm *t;
2285 time_t unixdate = time(NULL);
2286 char *p;
2288 *rparam_len = 4;
2289 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2290 if (!*rparam) {
2291 return False;
2294 *rdata_len = 21;
2295 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2296 if (!*rdata) {
2297 return False;
2300 SSVAL(*rparam,0,NERR_Success);
2301 SSVAL(*rparam,2,0); /* converter word */
2303 p = *rdata;
2305 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2306 by NT in a "net time" operation,
2307 it seems to ignore the one below */
2309 /* the client expects to get localtime, not GMT, in this bit
2310 (I think, this needs testing) */
2311 t = localtime(&unixdate);
2312 if (!t) {
2313 return False;
2316 SIVAL(p,4,0); /* msecs ? */
2317 SCVAL(p,8,t->tm_hour);
2318 SCVAL(p,9,t->tm_min);
2319 SCVAL(p,10,t->tm_sec);
2320 SCVAL(p,11,0); /* hundredths of seconds */
2321 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2322 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2323 SCVAL(p,16,t->tm_mday);
2324 SCVAL(p,17,t->tm_mon + 1);
2325 SSVAL(p,18,1900+t->tm_year);
2326 SCVAL(p,20,t->tm_wday);
2328 return True;
2331 /****************************************************************************
2332 Set the user password.
2333 *****************************************************************************/
2335 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid,
2336 char *param, int tpscnt,
2337 char *data, int tdscnt,
2338 int mdrcnt,int mprcnt,
2339 char **rdata,char **rparam,
2340 int *rdata_len,int *rparam_len)
2342 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2343 char *p = skip_string(param,tpscnt,skip_string(param,tpscnt,np,1),1);
2344 fstring user;
2345 fstring pass1,pass2;
2347 if (!np || !p) {
2348 return False;
2351 /* Do we have a string ? */
2352 if (skip_string(param,tpscnt,p,1) == NULL) {
2353 return False;
2355 pull_ascii_fstring(user,p);
2357 p = skip_string(param,tpscnt,p,1);
2358 if (!p) {
2359 return False;
2362 memset(pass1,'\0',sizeof(pass1));
2363 memset(pass2,'\0',sizeof(pass2));
2364 if (!is_offset_safe(param,tpscnt,p,32)) {
2365 return False;
2367 memcpy(pass1,p,16);
2368 memcpy(pass2,p+16,16);
2370 *rparam_len = 4;
2371 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2372 if (!*rparam) {
2373 return False;
2376 *rdata_len = 0;
2378 SSVAL(*rparam,0,NERR_badpass);
2379 SSVAL(*rparam,2,0); /* converter word */
2381 DEBUG(3,("Set password for <%s>\n",user));
2384 * Attempt to verify the old password against smbpasswd entries
2385 * Win98 clients send old and new password in plaintext for this call.
2389 auth_serversupplied_info *server_info = NULL;
2390 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2392 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2394 become_root();
2395 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2396 SSVAL(*rparam,0,NERR_Success);
2398 unbecome_root();
2400 TALLOC_FREE(server_info);
2402 data_blob_clear_free(&password);
2406 * If the plaintext change failed, attempt
2407 * the old encrypted method. NT will generate this
2408 * after trying the samr method. Note that this
2409 * method is done as a last resort as this
2410 * password change method loses the NT password hash
2411 * and cannot change the UNIX password as no plaintext
2412 * is received.
2415 if(SVAL(*rparam,0) != NERR_Success) {
2416 struct samu *hnd = NULL;
2418 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2419 become_root();
2420 if (change_lanman_password(hnd,(uchar *)pass2)) {
2421 SSVAL(*rparam,0,NERR_Success);
2423 unbecome_root();
2424 TALLOC_FREE(hnd);
2428 memset((char *)pass1,'\0',sizeof(fstring));
2429 memset((char *)pass2,'\0',sizeof(fstring));
2431 return(True);
2434 /****************************************************************************
2435 Set the user password (SamOEM version - gets plaintext).
2436 ****************************************************************************/
2438 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2439 char *param, int tpscnt,
2440 char *data, int tdscnt,
2441 int mdrcnt,int mprcnt,
2442 char **rdata,char **rparam,
2443 int *rdata_len,int *rparam_len)
2445 fstring user;
2446 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2447 *rparam_len = 2;
2448 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2449 if (!*rparam) {
2450 return False;
2453 if (!p) {
2454 return False;
2456 *rdata_len = 0;
2458 SSVAL(*rparam,0,NERR_badpass);
2461 * Check the parameter definition is correct.
2464 /* Do we have a string ? */
2465 if (skip_string(param,tpscnt,p,1) == 0) {
2466 return False;
2468 if(!strequal(p, "zsT")) {
2469 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2470 return False;
2472 p = skip_string(param, tpscnt, p, 1);
2473 if (!p) {
2474 return False;
2477 /* Do we have a string ? */
2478 if (skip_string(param,tpscnt,p,1) == 0) {
2479 return False;
2481 if(!strequal(p, "B516B16")) {
2482 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2483 return False;
2485 p = skip_string(param,tpscnt,p,1);
2486 if (!p) {
2487 return False;
2489 /* Do we have a string ? */
2490 if (skip_string(param,tpscnt,p,1) == 0) {
2491 return False;
2493 p += pull_ascii_fstring(user,p);
2495 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2498 * Pass the user through the NT -> unix user mapping
2499 * function.
2502 (void)map_username(user);
2504 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2505 SSVAL(*rparam,0,NERR_Success);
2508 return(True);
2511 /****************************************************************************
2512 delete a print job
2513 Form: <W> <>
2514 ****************************************************************************/
2516 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2517 char *param, int tpscnt,
2518 char *data, int tdscnt,
2519 int mdrcnt,int mprcnt,
2520 char **rdata,char **rparam,
2521 int *rdata_len,int *rparam_len)
2523 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2524 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2525 char *str2 = skip_string(param,tpscnt,str1,1);
2526 char *p = skip_string(param,tpscnt,str2,1);
2527 uint32 jobid;
2528 int snum;
2529 fstring sharename;
2530 int errcode;
2531 WERROR werr = WERR_OK;
2533 if (!str1 || !str2 || !p) {
2534 return False;
2536 if (!is_offset_safe(param,tpscnt,p,2)) {
2537 return False;
2539 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2540 return False;
2542 /* check it's a supported varient */
2543 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2544 return(False);
2546 *rparam_len = 4;
2547 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2548 if (!*rparam) {
2549 return False;
2551 *rdata_len = 0;
2553 if (!print_job_exists(sharename, jobid)) {
2554 errcode = NERR_JobNotFound;
2555 goto out;
2558 snum = lp_servicenumber( sharename);
2559 if (snum == -1) {
2560 errcode = NERR_DestNotFound;
2561 goto out;
2564 errcode = NERR_notsupported;
2566 switch (function) {
2567 case 81: /* delete */
2568 if (print_job_delete(&current_user, snum, jobid, &werr))
2569 errcode = NERR_Success;
2570 break;
2571 case 82: /* pause */
2572 if (print_job_pause(&current_user, snum, jobid, &werr))
2573 errcode = NERR_Success;
2574 break;
2575 case 83: /* resume */
2576 if (print_job_resume(&current_user, snum, jobid, &werr))
2577 errcode = NERR_Success;
2578 break;
2581 if (!W_ERROR_IS_OK(werr))
2582 errcode = W_ERROR_V(werr);
2584 out:
2585 SSVAL(*rparam,0,errcode);
2586 SSVAL(*rparam,2,0); /* converter word */
2588 return(True);
2591 /****************************************************************************
2592 Purge a print queue - or pause or resume it.
2593 ****************************************************************************/
2595 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2596 char *param, int tpscnt,
2597 char *data, int tdscnt,
2598 int mdrcnt,int mprcnt,
2599 char **rdata,char **rparam,
2600 int *rdata_len,int *rparam_len)
2602 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2603 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2604 char *str2 = skip_string(param,tpscnt,str1,1);
2605 char *QueueName = skip_string(param,tpscnt,str2,1);
2606 int errcode = NERR_notsupported;
2607 int snum;
2608 WERROR werr = WERR_OK;
2610 if (!str1 || !str2 || !QueueName) {
2611 return False;
2614 /* check it's a supported varient */
2615 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2616 return(False);
2618 *rparam_len = 4;
2619 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2620 if (!*rparam) {
2621 return False;
2623 *rdata_len = 0;
2625 if (skip_string(param,tpscnt,QueueName,1) == NULL) {
2626 return False;
2628 snum = print_queue_snum(QueueName);
2630 if (snum == -1) {
2631 errcode = NERR_JobNotFound;
2632 goto out;
2635 switch (function) {
2636 case 74: /* Pause queue */
2637 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2638 break;
2639 case 75: /* Resume queue */
2640 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2641 break;
2642 case 103: /* Purge */
2643 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2644 break;
2647 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2649 out:
2650 SSVAL(*rparam,0,errcode);
2651 SSVAL(*rparam,2,0); /* converter word */
2653 return(True);
2656 /****************************************************************************
2657 set the property of a print job (undocumented?)
2658 ? function = 0xb -> set name of print job
2659 ? function = 0x6 -> move print job up/down
2660 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2661 or <WWsTP> <WB21BB16B10zWWzDDz>
2662 ****************************************************************************/
2664 static int check_printjob_info(struct pack_desc* desc,
2665 int uLevel, char* id)
2667 desc->subformat = NULL;
2668 switch( uLevel ) {
2669 case 0: desc->format = "W"; break;
2670 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2671 case 2: desc->format = "WWzWWDDzz"; break;
2672 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2673 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2674 default: return False;
2676 if (strcmp(desc->format,id) != 0) return False;
2677 return True;
2680 static BOOL api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2681 char *param, int tpscnt,
2682 char *data, int tdscnt,
2683 int mdrcnt,int mprcnt,
2684 char **rdata,char **rparam,
2685 int *rdata_len,int *rparam_len)
2687 struct pack_desc desc;
2688 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2689 char *str2 = skip_string(param,tpscnt,str1,1);
2690 char *p = skip_string(param,tpscnt,str2,1);
2691 uint32 jobid;
2692 fstring sharename;
2693 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2694 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2695 int place, errcode;
2697 if (!str1 || !str2 || !p) {
2698 return False;
2700 if (!is_offset_safe(param,tpscnt,p,2)) {
2701 return False;
2703 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2704 return False;
2705 *rparam_len = 4;
2706 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2707 if (!*rparam) {
2708 return False;
2711 if (!share_defined(sharename)) {
2712 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2713 sharename));
2714 return False;
2717 *rdata_len = 0;
2719 /* check it's a supported varient */
2720 if ((strcmp(str1,"WWsTP")) ||
2721 (!check_printjob_info(&desc,uLevel,str2)))
2722 return(False);
2724 if (!print_job_exists(sharename, jobid)) {
2725 errcode=NERR_JobNotFound;
2726 goto out;
2729 errcode = NERR_notsupported;
2731 switch (function) {
2732 case 0x6:
2733 /* change job place in the queue,
2734 data gives the new place */
2735 place = SVAL(data,0);
2736 if (print_job_set_place(sharename, jobid, place)) {
2737 errcode=NERR_Success;
2739 break;
2741 case 0xb:
2742 /* change print job name, data gives the name */
2743 if (print_job_set_name(sharename, jobid, data)) {
2744 errcode=NERR_Success;
2746 break;
2748 default:
2749 return False;
2752 out:
2753 SSVALS(*rparam,0,errcode);
2754 SSVAL(*rparam,2,0); /* converter word */
2756 return(True);
2760 /****************************************************************************
2761 Get info about the server.
2762 ****************************************************************************/
2764 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2765 char *param, int tpscnt,
2766 char *data, int tdscnt,
2767 int mdrcnt,int mprcnt,
2768 char **rdata,char **rparam,
2769 int *rdata_len,int *rparam_len)
2771 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2772 char *str2 = skip_string(param,tpscnt,str1,1);
2773 char *p = skip_string(param,tpscnt,str2,1);
2774 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2775 char *p2;
2776 int struct_len;
2778 if (!str1 || !str2 || !p) {
2779 return False;
2782 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2784 /* check it's a supported varient */
2785 if (!prefix_ok(str1,"WrLh")) {
2786 return False;
2789 switch( uLevel ) {
2790 case 0:
2791 if (strcmp(str2,"B16") != 0) {
2792 return False;
2794 struct_len = 16;
2795 break;
2796 case 1:
2797 if (strcmp(str2,"B16BBDz") != 0) {
2798 return False;
2800 struct_len = 26;
2801 break;
2802 case 2:
2803 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2804 return False;
2806 struct_len = 134;
2807 break;
2808 case 3:
2809 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2810 return False;
2812 struct_len = 144;
2813 break;
2814 case 20:
2815 if (strcmp(str2,"DN") != 0) {
2816 return False;
2818 struct_len = 6;
2819 break;
2820 case 50:
2821 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2822 return False;
2824 struct_len = 42;
2825 break;
2826 default:
2827 return False;
2830 *rdata_len = mdrcnt;
2831 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2832 if (!*rdata) {
2833 return False;
2836 p = *rdata;
2837 p2 = p + struct_len;
2838 if (uLevel != 20) {
2839 srvstr_push(NULL, p,global_myname(),16,
2840 STR_ASCII|STR_UPPER|STR_TERMINATE);
2842 p += 16;
2843 if (uLevel > 0) {
2844 struct srv_info_struct *servers=NULL;
2845 int i,count;
2846 pstring comment;
2847 uint32 servertype= lp_default_server_announce();
2849 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2851 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2852 for (i=0;i<count;i++) {
2853 if (strequal(servers[i].name,global_myname())) {
2854 servertype = servers[i].type;
2855 push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2860 SAFE_FREE(servers);
2862 SCVAL(p,0,lp_major_announce_version());
2863 SCVAL(p,1,lp_minor_announce_version());
2864 SIVAL(p,2,servertype);
2866 if (mdrcnt == struct_len) {
2867 SIVAL(p,6,0);
2868 } else {
2869 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2870 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2871 conn->connectpath, conn->gid,
2872 get_current_username(),
2873 current_user_info.domain,
2874 comment, sizeof(comment));
2875 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2876 p2 = skip_string(*rdata,*rdata_len,p2,1);
2877 if (!p2) {
2878 return False;
2883 if (uLevel > 1) {
2884 return False; /* not yet implemented */
2887 *rdata_len = PTR_DIFF(p2,*rdata);
2889 *rparam_len = 6;
2890 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2891 if (!*rparam) {
2892 return False;
2894 SSVAL(*rparam,0,NERR_Success);
2895 SSVAL(*rparam,2,0); /* converter word */
2896 SSVAL(*rparam,4,*rdata_len);
2898 return True;
2901 /****************************************************************************
2902 Get info about the server.
2903 ****************************************************************************/
2905 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
2906 char *param, int tpscnt,
2907 char *data, int tdscnt,
2908 int mdrcnt,int mprcnt,
2909 char **rdata,char **rparam,
2910 int *rdata_len,int *rparam_len)
2912 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2913 char *str2 = skip_string(param,tpscnt,str1,1);
2914 char *p = skip_string(param,tpscnt,str2,1);
2915 char *p2;
2916 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
2918 if (!str1 || !str2 || !p) {
2919 return False;
2922 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2924 *rparam_len = 6;
2925 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2926 if (!*rparam) {
2927 return False;
2930 /* check it's a supported varient */
2931 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2932 return False;
2935 *rdata_len = mdrcnt + 1024;
2936 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2937 if (!*rdata) {
2938 return False;
2941 SSVAL(*rparam,0,NERR_Success);
2942 SSVAL(*rparam,2,0); /* converter word */
2944 p = *rdata;
2945 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
2946 if (!p2) {
2947 return False;
2950 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2951 pstrcpy(p2,get_local_machine_name());
2952 strupper_m(p2);
2953 p2 = skip_string(*rdata,*rdata_len,p2,1);
2954 if (!p2) {
2955 return False;
2957 p += 4;
2959 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2960 pstrcpy(p2,current_user_info.smb_name);
2961 p2 = skip_string(*rdata,*rdata_len,p2,1);
2962 if (!p2) {
2963 return False;
2965 p += 4;
2967 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2968 pstrcpy(p2,lp_workgroup());
2969 strupper_m(p2);
2970 p2 = skip_string(*rdata,*rdata_len,p2,1);
2971 if (!p2) {
2972 return False;
2974 p += 4;
2976 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2977 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2978 p += 2;
2980 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2981 pstrcpy(p2,lp_workgroup()); /* don't know. login domain?? */
2982 p2 = skip_string(*rdata,*rdata_len,p2,1);
2983 if (!p2) {
2984 return False;
2986 p += 4;
2988 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2989 pstrcpy(p2,"");
2990 p2 = skip_string(*rdata,*rdata_len,p2,1);
2991 if (!p2) {
2992 return False;
2994 p += 4;
2996 *rdata_len = PTR_DIFF(p2,*rdata);
2998 SSVAL(*rparam,4,*rdata_len);
3000 return True;
3003 /****************************************************************************
3004 get info about a user
3006 struct user_info_11 {
3007 char usri11_name[21]; 0-20
3008 char usri11_pad; 21
3009 char *usri11_comment; 22-25
3010 char *usri11_usr_comment; 26-29
3011 unsigned short usri11_priv; 30-31
3012 unsigned long usri11_auth_flags; 32-35
3013 long usri11_password_age; 36-39
3014 char *usri11_homedir; 40-43
3015 char *usri11_parms; 44-47
3016 long usri11_last_logon; 48-51
3017 long usri11_last_logoff; 52-55
3018 unsigned short usri11_bad_pw_count; 56-57
3019 unsigned short usri11_num_logons; 58-59
3020 char *usri11_logon_server; 60-63
3021 unsigned short usri11_country_code; 64-65
3022 char *usri11_workstations; 66-69
3023 unsigned long usri11_max_storage; 70-73
3024 unsigned short usri11_units_per_week; 74-75
3025 unsigned char *usri11_logon_hours; 76-79
3026 unsigned short usri11_code_page; 80-81
3029 where:
3031 usri11_name specifies the user name for which information is retireved
3033 usri11_pad aligns the next data structure element to a word boundary
3035 usri11_comment is a null terminated ASCII comment
3037 usri11_user_comment is a null terminated ASCII comment about the user
3039 usri11_priv specifies the level of the privilege assigned to the user.
3040 The possible values are:
3042 Name Value Description
3043 USER_PRIV_GUEST 0 Guest privilege
3044 USER_PRIV_USER 1 User privilege
3045 USER_PRV_ADMIN 2 Administrator privilege
3047 usri11_auth_flags specifies the account operator privileges. The
3048 possible values are:
3050 Name Value Description
3051 AF_OP_PRINT 0 Print operator
3054 Leach, Naik [Page 28]
3058 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3061 AF_OP_COMM 1 Communications operator
3062 AF_OP_SERVER 2 Server operator
3063 AF_OP_ACCOUNTS 3 Accounts operator
3066 usri11_password_age specifies how many seconds have elapsed since the
3067 password was last changed.
3069 usri11_home_dir points to a null terminated ASCII string that contains
3070 the path name of the user's home directory.
3072 usri11_parms points to a null terminated ASCII string that is set
3073 aside for use by applications.
3075 usri11_last_logon specifies the time when the user last logged on.
3076 This value is stored as the number of seconds elapsed since
3077 00:00:00, January 1, 1970.
3079 usri11_last_logoff specifies the time when the user last logged off.
3080 This value is stored as the number of seconds elapsed since
3081 00:00:00, January 1, 1970. A value of 0 means the last logoff
3082 time is unknown.
3084 usri11_bad_pw_count specifies the number of incorrect passwords
3085 entered since the last successful logon.
3087 usri11_log1_num_logons specifies the number of times this user has
3088 logged on. A value of -1 means the number of logons is unknown.
3090 usri11_logon_server points to a null terminated ASCII string that
3091 contains the name of the server to which logon requests are sent.
3092 A null string indicates logon requests should be sent to the
3093 domain controller.
3095 usri11_country_code specifies the country code for the user's language
3096 of choice.
3098 usri11_workstations points to a null terminated ASCII string that
3099 contains the names of workstations the user may log on from.
3100 There may be up to 8 workstations, with the names separated by
3101 commas. A null strings indicates there are no restrictions.
3103 usri11_max_storage specifies the maximum amount of disk space the user
3104 can occupy. A value of 0xffffffff indicates there are no
3105 restrictions.
3107 usri11_units_per_week specifies the equal number of time units into
3108 which a week is divided. This value must be equal to 168.
3110 usri11_logon_hours points to a 21 byte (168 bits) string that
3111 specifies the time during which the user can log on. Each bit
3112 represents one unique hour in a week. The first bit (bit 0, word
3113 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3117 Leach, Naik [Page 29]
3121 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3124 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3125 are no restrictions.
3127 usri11_code_page specifies the code page for the user's language of
3128 choice
3130 All of the pointers in this data structure need to be treated
3131 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3132 to be ignored. The converter word returned in the parameters section
3133 needs to be subtracted from the lower 16 bits to calculate an offset
3134 into the return buffer where this ASCII string resides.
3136 There is no auxiliary data in the response.
3138 ****************************************************************************/
3140 #define usri11_name 0
3141 #define usri11_pad 21
3142 #define usri11_comment 22
3143 #define usri11_usr_comment 26
3144 #define usri11_full_name 30
3145 #define usri11_priv 34
3146 #define usri11_auth_flags 36
3147 #define usri11_password_age 40
3148 #define usri11_homedir 44
3149 #define usri11_parms 48
3150 #define usri11_last_logon 52
3151 #define usri11_last_logoff 56
3152 #define usri11_bad_pw_count 60
3153 #define usri11_num_logons 62
3154 #define usri11_logon_server 64
3155 #define usri11_country_code 68
3156 #define usri11_workstations 70
3157 #define usri11_max_storage 74
3158 #define usri11_units_per_week 78
3159 #define usri11_logon_hours 80
3160 #define usri11_code_page 84
3161 #define usri11_end 86
3163 #define USER_PRIV_GUEST 0
3164 #define USER_PRIV_USER 1
3165 #define USER_PRIV_ADMIN 2
3167 #define AF_OP_PRINT 0
3168 #define AF_OP_COMM 1
3169 #define AF_OP_SERVER 2
3170 #define AF_OP_ACCOUNTS 3
3173 static BOOL api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3174 char *param, int tpscnt,
3175 char *data, int tdscnt,
3176 int mdrcnt,int mprcnt,
3177 char **rdata,char **rparam,
3178 int *rdata_len,int *rparam_len)
3180 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3181 char *str2 = skip_string(param,tpscnt,str1,1);
3182 char *UserName = skip_string(param,tpscnt,str2,1);
3183 char *p = skip_string(param,tpscnt,UserName,1);
3184 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3185 char *p2;
3186 const char *level_string;
3188 /* get NIS home of a previously validated user - simeon */
3189 /* With share level security vuid will always be zero.
3190 Don't depend on vuser being non-null !!. JRA */
3191 user_struct *vuser = get_valid_user_struct(vuid);
3192 if(vuser != NULL) {
3193 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3194 vuser->user.unix_name));
3197 if (!str1 || !str2 || !UserName || !p) {
3198 return False;
3201 *rparam_len = 6;
3202 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3203 if (!*rparam) {
3204 return False;
3207 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3209 /* check it's a supported variant */
3210 if (strcmp(str1,"zWrLh") != 0) {
3211 return False;
3213 switch( uLevel ) {
3214 case 0: level_string = "B21"; break;
3215 case 1: level_string = "B21BB16DWzzWz"; break;
3216 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3217 case 10: level_string = "B21Bzzz"; break;
3218 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3219 default: return False;
3222 if (strcmp(level_string,str2) != 0) {
3223 return False;
3226 *rdata_len = mdrcnt + 1024;
3227 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
3228 if (!*rdata) {
3229 return False;
3232 SSVAL(*rparam,0,NERR_Success);
3233 SSVAL(*rparam,2,0); /* converter word */
3235 p = *rdata;
3236 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3237 if (!p2) {
3238 return False;
3241 memset(p,0,21);
3242 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3244 if (uLevel > 0) {
3245 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3246 *p2 = 0;
3249 if (uLevel >= 10) {
3250 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3251 pstrcpy(p2,"Comment");
3252 p2 = skip_string(*rdata,*rdata_len,p2,1);
3253 if (!p2) {
3254 return False;
3257 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3258 pstrcpy(p2,"UserComment");
3259 p2 = skip_string(*rdata,*rdata_len,p2,1);
3260 if (!p2) {
3261 return False;
3264 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3265 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3266 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3267 p2 = skip_string(*rdata,*rdata_len,p2,1);
3268 if (!p2) {
3269 return False;
3273 if (uLevel == 11) {
3274 /* modelled after NTAS 3.51 reply */
3275 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3276 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3277 SIVALS(p,usri11_password_age,-1); /* password age */
3278 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3279 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3280 p2 = skip_string(*rdata,*rdata_len,p2,1);
3281 if (!p2) {
3282 return False;
3284 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3285 pstrcpy(p2,"");
3286 p2 = skip_string(*rdata,*rdata_len,p2,1);
3287 if (!p2) {
3288 return False;
3290 SIVAL(p,usri11_last_logon,0); /* last logon */
3291 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3292 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3293 SSVALS(p,usri11_num_logons,-1); /* num logons */
3294 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3295 pstrcpy(p2,"\\\\*");
3296 p2 = skip_string(*rdata,*rdata_len,p2,1);
3297 if (!p2) {
3298 return False;
3300 SSVAL(p,usri11_country_code,0); /* country code */
3302 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3303 pstrcpy(p2,"");
3304 p2 = skip_string(*rdata,*rdata_len,p2,1);
3305 if (!p2) {
3306 return False;
3309 SIVALS(p,usri11_max_storage,-1); /* max storage */
3310 SSVAL(p,usri11_units_per_week,168); /* units per week */
3311 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3313 /* a simple way to get logon hours at all times. */
3314 memset(p2,0xff,21);
3315 SCVAL(p2,21,0); /* fix zero termination */
3316 p2 = skip_string(*rdata,*rdata_len,p2,1);
3317 if (!p2) {
3318 return False;
3321 SSVAL(p,usri11_code_page,0); /* code page */
3324 if (uLevel == 1 || uLevel == 2) {
3325 memset(p+22,' ',16); /* password */
3326 SIVALS(p,38,-1); /* password age */
3327 SSVAL(p,42,
3328 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3329 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3330 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3331 p2 = skip_string(*rdata,*rdata_len,p2,1);
3332 if (!p2) {
3333 return False;
3335 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3336 *p2++ = 0;
3337 SSVAL(p,52,0); /* flags */
3338 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3339 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3340 p2 = skip_string(*rdata,*rdata_len,p2,1);
3341 if (!p2) {
3342 return False;
3344 if (uLevel == 2) {
3345 SIVAL(p,60,0); /* auth_flags */
3346 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3347 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3348 p2 = skip_string(*rdata,*rdata_len,p2,1);
3349 if (!p2) {
3350 return False;
3352 SIVAL(p,68,0); /* urs_comment */
3353 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3354 pstrcpy(p2,"");
3355 p2 = skip_string(*rdata,*rdata_len,p2,1);
3356 if (!p2) {
3357 return False;
3359 SIVAL(p,76,0); /* workstations */
3360 SIVAL(p,80,0); /* last_logon */
3361 SIVAL(p,84,0); /* last_logoff */
3362 SIVALS(p,88,-1); /* acct_expires */
3363 SIVALS(p,92,-1); /* max_storage */
3364 SSVAL(p,96,168); /* units_per_week */
3365 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3366 memset(p2,-1,21);
3367 p2 += 21;
3368 SSVALS(p,102,-1); /* bad_pw_count */
3369 SSVALS(p,104,-1); /* num_logons */
3370 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3372 pstring tmp;
3373 pstrcpy(tmp, "\\\\%L");
3374 standard_sub_basic("", "", tmp, sizeof(tmp));
3375 pstrcpy(p2, tmp);
3377 p2 = skip_string(*rdata,*rdata_len,p2,1);
3378 if (!p2) {
3379 return False;
3381 SSVAL(p,110,49); /* country_code */
3382 SSVAL(p,112,860); /* code page */
3386 *rdata_len = PTR_DIFF(p2,*rdata);
3388 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3390 return(True);
3393 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3394 char *param, int tpscnt,
3395 char *data, int tdscnt,
3396 int mdrcnt,int mprcnt,
3397 char **rdata,char **rparam,
3398 int *rdata_len,int *rparam_len)
3400 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3401 char *str2 = skip_string(param,tpscnt,str1,1);
3402 char *p = skip_string(param,tpscnt,str2,1);
3403 int uLevel;
3404 struct pack_desc desc;
3405 char* name;
3406 /* With share level security vuid will always be zero.
3407 Don't depend on vuser being non-null !!. JRA */
3408 user_struct *vuser = get_valid_user_struct(vuid);
3410 if (!str1 || !str2 || !p) {
3411 return False;
3414 if(vuser != NULL) {
3415 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3416 vuser->user.unix_name));
3419 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3420 name = get_safe_str_ptr(param,tpscnt,p,2);
3421 if (!name) {
3422 return False;
3425 memset((char *)&desc,'\0',sizeof(desc));
3427 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3429 /* check it's a supported varient */
3430 if (strcmp(str1,"OOWb54WrLh") != 0) {
3431 return False;
3433 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3434 return False;
3436 if (mdrcnt > 0) {
3437 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3438 if (!*rdata) {
3439 return False;
3443 desc.base = *rdata;
3444 desc.buflen = mdrcnt;
3445 desc.subformat = NULL;
3446 desc.format = str2;
3448 if (init_package(&desc,1,0)) {
3449 PACKI(&desc,"W",0); /* code */
3450 PACKS(&desc,"B21",name); /* eff. name */
3451 PACKS(&desc,"B",""); /* pad */
3452 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3453 PACKI(&desc,"D",0); /* auth flags XXX */
3454 PACKI(&desc,"W",0); /* num logons */
3455 PACKI(&desc,"W",0); /* bad pw count */
3456 PACKI(&desc,"D",0); /* last logon */
3457 PACKI(&desc,"D",-1); /* last logoff */
3458 PACKI(&desc,"D",-1); /* logoff time */
3459 PACKI(&desc,"D",-1); /* kickoff time */
3460 PACKI(&desc,"D",0); /* password age */
3461 PACKI(&desc,"D",0); /* password can change */
3462 PACKI(&desc,"D",-1); /* password must change */
3465 fstring mypath;
3466 fstrcpy(mypath,"\\\\");
3467 fstrcat(mypath,get_local_machine_name());
3468 strupper_m(mypath);
3469 PACKS(&desc,"z",mypath); /* computer */
3472 PACKS(&desc,"z",lp_workgroup());/* domain */
3473 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3474 PACKI(&desc,"D",0x00000000); /* reserved */
3477 *rdata_len = desc.usedlen;
3478 *rparam_len = 6;
3479 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3480 if (!*rparam) {
3481 return False;
3483 SSVALS(*rparam,0,desc.errcode);
3484 SSVAL(*rparam,2,0);
3485 SSVAL(*rparam,4,desc.neededlen);
3487 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3489 return True;
3492 /****************************************************************************
3493 api_WAccessGetUserPerms
3494 ****************************************************************************/
3496 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3497 char *param, int tpscnt,
3498 char *data, int tdscnt,
3499 int mdrcnt,int mprcnt,
3500 char **rdata,char **rparam,
3501 int *rdata_len,int *rparam_len)
3503 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3504 char *str2 = skip_string(param,tpscnt,str1,1);
3505 char *user = skip_string(param,tpscnt,str2,1);
3506 char *resource = skip_string(param,tpscnt,user,1);
3508 if (!str1 || !str2 || !user || !resource) {
3509 return False;
3512 if (skip_string(param,tpscnt,resource,1) == NULL) {
3513 return False;
3515 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3517 /* check it's a supported varient */
3518 if (strcmp(str1,"zzh") != 0) {
3519 return False;
3521 if (strcmp(str2,"") != 0) {
3522 return False;
3525 *rparam_len = 6;
3526 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3527 if (!*rparam) {
3528 return False;
3530 SSVALS(*rparam,0,0); /* errorcode */
3531 SSVAL(*rparam,2,0); /* converter word */
3532 SSVAL(*rparam,4,0x7f); /* permission flags */
3534 return True;
3537 /****************************************************************************
3538 api_WPrintJobEnumerate
3539 ****************************************************************************/
3541 static BOOL api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3542 char *param, int tpscnt,
3543 char *data, int tdscnt,
3544 int mdrcnt,int mprcnt,
3545 char **rdata,char **rparam,
3546 int *rdata_len,int *rparam_len)
3548 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3549 char *str2 = skip_string(param,tpscnt,str1,1);
3550 char *p = skip_string(param,tpscnt,str2,1);
3551 int uLevel;
3552 int count;
3553 int i;
3554 int snum;
3555 fstring sharename;
3556 uint32 jobid;
3557 struct pack_desc desc;
3558 print_queue_struct *queue=NULL;
3559 print_status_struct status;
3560 char *tmpdata=NULL;
3562 if (!str1 || !str2 || !p) {
3563 return False;
3566 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3568 memset((char *)&desc,'\0',sizeof(desc));
3569 memset((char *)&status,'\0',sizeof(status));
3571 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3573 /* check it's a supported varient */
3574 if (strcmp(str1,"WWrLh") != 0) {
3575 return False;
3577 if (!check_printjob_info(&desc,uLevel,str2)) {
3578 return False;
3581 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3582 return False;
3585 snum = lp_servicenumber( sharename);
3586 if (snum < 0 || !VALID_SNUM(snum)) {
3587 return(False);
3590 count = print_queue_status(snum,&queue,&status);
3591 for (i = 0; i < count; i++) {
3592 if (queue[i].job == jobid) {
3593 break;
3597 if (mdrcnt > 0) {
3598 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3599 if (!*rdata) {
3600 return False;
3602 desc.base = *rdata;
3603 desc.buflen = mdrcnt;
3604 } else {
3606 * Don't return data but need to get correct length
3607 * init_package will return wrong size if buflen=0
3609 desc.buflen = getlen(desc.format);
3610 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3613 if (init_package(&desc,1,0)) {
3614 if (i < count) {
3615 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3616 *rdata_len = desc.usedlen;
3617 } else {
3618 desc.errcode = NERR_JobNotFound;
3619 *rdata_len = 0;
3623 *rparam_len = 6;
3624 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3625 if (!*rparam) {
3626 return False;
3628 SSVALS(*rparam,0,desc.errcode);
3629 SSVAL(*rparam,2,0);
3630 SSVAL(*rparam,4,desc.neededlen);
3632 SAFE_FREE(queue);
3633 SAFE_FREE(tmpdata);
3635 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3637 return True;
3640 static BOOL api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3641 char *param, int tpscnt,
3642 char *data, int tdscnt,
3643 int mdrcnt,int mprcnt,
3644 char **rdata,char **rparam,
3645 int *rdata_len,int *rparam_len)
3647 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3648 char *str2 = skip_string(param,tpscnt,str1,1);
3649 char *p = skip_string(param,tpscnt,str2,1);
3650 char *name = p;
3651 int uLevel;
3652 int count;
3653 int i, succnt=0;
3654 int snum;
3655 struct pack_desc desc;
3656 print_queue_struct *queue=NULL;
3657 print_status_struct status;
3659 if (!str1 || !str2 || !p) {
3660 return False;
3663 memset((char *)&desc,'\0',sizeof(desc));
3664 memset((char *)&status,'\0',sizeof(status));
3666 p = skip_string(param,tpscnt,p,1);
3667 if (!p) {
3668 return False;
3670 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3672 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3674 /* check it's a supported variant */
3675 if (strcmp(str1,"zWrLeh") != 0) {
3676 return False;
3679 if (uLevel > 2) {
3680 return False; /* defined only for uLevel 0,1,2 */
3683 if (!check_printjob_info(&desc,uLevel,str2)) {
3684 return False;
3687 snum = find_service(name);
3688 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3689 return False;
3692 count = print_queue_status(snum,&queue,&status);
3693 if (mdrcnt > 0) {
3694 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3695 if (!*rdata) {
3696 return False;
3699 desc.base = *rdata;
3700 desc.buflen = mdrcnt;
3702 if (init_package(&desc,count,0)) {
3703 succnt = 0;
3704 for (i = 0; i < count; i++) {
3705 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3706 if (desc.errcode == NERR_Success) {
3707 succnt = i+1;
3712 *rdata_len = desc.usedlen;
3714 *rparam_len = 8;
3715 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3716 if (!*rparam) {
3717 return False;
3719 SSVALS(*rparam,0,desc.errcode);
3720 SSVAL(*rparam,2,0);
3721 SSVAL(*rparam,4,succnt);
3722 SSVAL(*rparam,6,count);
3724 SAFE_FREE(queue);
3726 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3728 return True;
3731 static int check_printdest_info(struct pack_desc* desc,
3732 int uLevel, char* id)
3734 desc->subformat = NULL;
3735 switch( uLevel ) {
3736 case 0:
3737 desc->format = "B9";
3738 break;
3739 case 1:
3740 desc->format = "B9B21WWzW";
3741 break;
3742 case 2:
3743 desc->format = "z";
3744 break;
3745 case 3:
3746 desc->format = "zzzWWzzzWW";
3747 break;
3748 default:
3749 return False;
3751 if (strcmp(desc->format,id) != 0) {
3752 return False;
3754 return True;
3757 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3758 struct pack_desc* desc)
3760 char buf[100];
3762 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3763 buf[sizeof(buf)-1] = 0;
3764 strupper_m(buf);
3766 if (uLevel <= 1) {
3767 PACKS(desc,"B9",buf); /* szName */
3768 if (uLevel == 1) {
3769 PACKS(desc,"B21",""); /* szUserName */
3770 PACKI(desc,"W",0); /* uJobId */
3771 PACKI(desc,"W",0); /* fsStatus */
3772 PACKS(desc,"z",""); /* pszStatus */
3773 PACKI(desc,"W",0); /* time */
3777 if (uLevel == 2 || uLevel == 3) {
3778 PACKS(desc,"z",buf); /* pszPrinterName */
3779 if (uLevel == 3) {
3780 PACKS(desc,"z",""); /* pszUserName */
3781 PACKS(desc,"z",""); /* pszLogAddr */
3782 PACKI(desc,"W",0); /* uJobId */
3783 PACKI(desc,"W",0); /* fsStatus */
3784 PACKS(desc,"z",""); /* pszStatus */
3785 PACKS(desc,"z",""); /* pszComment */
3786 PACKS(desc,"z","NULL"); /* pszDrivers */
3787 PACKI(desc,"W",0); /* time */
3788 PACKI(desc,"W",0); /* pad1 */
3793 static BOOL api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3794 char *param, int tpscnt,
3795 char *data, int tdscnt,
3796 int mdrcnt,int mprcnt,
3797 char **rdata,char **rparam,
3798 int *rdata_len,int *rparam_len)
3800 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3801 char *str2 = skip_string(param,tpscnt,str1,1);
3802 char *p = skip_string(param,tpscnt,str2,1);
3803 char* PrinterName = p;
3804 int uLevel;
3805 struct pack_desc desc;
3806 int snum;
3807 char *tmpdata=NULL;
3809 if (!str1 || !str2 || !p) {
3810 return False;
3813 memset((char *)&desc,'\0',sizeof(desc));
3815 p = skip_string(param,tpscnt,p,1);
3816 if (!p) {
3817 return False;
3819 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3821 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3823 /* check it's a supported varient */
3824 if (strcmp(str1,"zWrLh") != 0) {
3825 return False;
3827 if (!check_printdest_info(&desc,uLevel,str2)) {
3828 return False;
3831 snum = find_service(PrinterName);
3832 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3833 *rdata_len = 0;
3834 desc.errcode = NERR_DestNotFound;
3835 desc.neededlen = 0;
3836 } else {
3837 if (mdrcnt > 0) {
3838 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3839 if (!*rdata) {
3840 return False;
3842 desc.base = *rdata;
3843 desc.buflen = mdrcnt;
3844 } else {
3846 * Don't return data but need to get correct length
3847 * init_package will return wrong size if buflen=0
3849 desc.buflen = getlen(desc.format);
3850 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3852 if (init_package(&desc,1,0)) {
3853 fill_printdest_info(conn,snum,uLevel,&desc);
3855 *rdata_len = desc.usedlen;
3858 *rparam_len = 6;
3859 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3860 if (!*rparam) {
3861 return False;
3863 SSVALS(*rparam,0,desc.errcode);
3864 SSVAL(*rparam,2,0);
3865 SSVAL(*rparam,4,desc.neededlen);
3867 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3868 SAFE_FREE(tmpdata);
3870 return True;
3873 static BOOL api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
3874 char *param, int tpscnt,
3875 char *data, int tdscnt,
3876 int mdrcnt,int mprcnt,
3877 char **rdata,char **rparam,
3878 int *rdata_len,int *rparam_len)
3880 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3881 char *str2 = skip_string(param,tpscnt,str1,1);
3882 char *p = skip_string(param,tpscnt,str2,1);
3883 int uLevel;
3884 int queuecnt;
3885 int i, n, succnt=0;
3886 struct pack_desc desc;
3887 int services = lp_numservices();
3889 if (!str1 || !str2 || !p) {
3890 return False;
3893 memset((char *)&desc,'\0',sizeof(desc));
3895 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3897 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3899 /* check it's a supported varient */
3900 if (strcmp(str1,"WrLeh") != 0) {
3901 return False;
3903 if (!check_printdest_info(&desc,uLevel,str2)) {
3904 return False;
3907 queuecnt = 0;
3908 for (i = 0; i < services; i++) {
3909 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3910 queuecnt++;
3914 if (mdrcnt > 0) {
3915 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3916 if (!*rdata) {
3917 return False;
3921 desc.base = *rdata;
3922 desc.buflen = mdrcnt;
3923 if (init_package(&desc,queuecnt,0)) {
3924 succnt = 0;
3925 n = 0;
3926 for (i = 0; i < services; i++) {
3927 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3928 fill_printdest_info(conn,i,uLevel,&desc);
3929 n++;
3930 if (desc.errcode == NERR_Success) {
3931 succnt = n;
3937 *rdata_len = desc.usedlen;
3939 *rparam_len = 8;
3940 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3941 if (!*rparam) {
3942 return False;
3944 SSVALS(*rparam,0,desc.errcode);
3945 SSVAL(*rparam,2,0);
3946 SSVAL(*rparam,4,succnt);
3947 SSVAL(*rparam,6,queuecnt);
3949 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3951 return True;
3954 static BOOL api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
3955 char *param, int tpscnt,
3956 char *data, int tdscnt,
3957 int mdrcnt,int mprcnt,
3958 char **rdata,char **rparam,
3959 int *rdata_len,int *rparam_len)
3961 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3962 char *str2 = skip_string(param,tpscnt,str1,1);
3963 char *p = skip_string(param,tpscnt,str2,1);
3964 int uLevel;
3965 int succnt;
3966 struct pack_desc desc;
3968 if (!str1 || !str2 || !p) {
3969 return False;
3972 memset((char *)&desc,'\0',sizeof(desc));
3974 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3976 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3978 /* check it's a supported varient */
3979 if (strcmp(str1,"WrLeh") != 0) {
3980 return False;
3982 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
3983 return False;
3986 if (mdrcnt > 0) {
3987 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3988 if (!*rdata) {
3989 return False;
3992 desc.base = *rdata;
3993 desc.buflen = mdrcnt;
3994 if (init_package(&desc,1,0)) {
3995 PACKS(&desc,"B41","NULL");
3998 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4000 *rdata_len = desc.usedlen;
4002 *rparam_len = 8;
4003 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4004 if (!*rparam) {
4005 return False;
4007 SSVALS(*rparam,0,desc.errcode);
4008 SSVAL(*rparam,2,0);
4009 SSVAL(*rparam,4,succnt);
4010 SSVAL(*rparam,6,1);
4012 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4014 return True;
4017 static BOOL api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4018 char *param, int tpscnt,
4019 char *data, int tdscnt,
4020 int mdrcnt,int mprcnt,
4021 char **rdata,char **rparam,
4022 int *rdata_len,int *rparam_len)
4024 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4025 char *str2 = skip_string(param,tpscnt,str1,1);
4026 char *p = skip_string(param,tpscnt,str2,1);
4027 int uLevel;
4028 int succnt;
4029 struct pack_desc desc;
4031 if (!str1 || !str2 || !p) {
4032 return False;
4034 memset((char *)&desc,'\0',sizeof(desc));
4036 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4038 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4040 /* check it's a supported varient */
4041 if (strcmp(str1,"WrLeh") != 0) {
4042 return False;
4044 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4045 return False;
4048 if (mdrcnt > 0) {
4049 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4050 if (!*rdata) {
4051 return False;
4054 desc.base = *rdata;
4055 desc.buflen = mdrcnt;
4056 desc.format = str2;
4057 if (init_package(&desc,1,0)) {
4058 PACKS(&desc,"B13","lpd");
4061 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4063 *rdata_len = desc.usedlen;
4065 *rparam_len = 8;
4066 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4067 if (!*rparam) {
4068 return False;
4070 SSVALS(*rparam,0,desc.errcode);
4071 SSVAL(*rparam,2,0);
4072 SSVAL(*rparam,4,succnt);
4073 SSVAL(*rparam,6,1);
4075 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4077 return True;
4080 static BOOL api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4081 char *param, int tpscnt,
4082 char *data, int tdscnt,
4083 int mdrcnt,int mprcnt,
4084 char **rdata,char **rparam,
4085 int *rdata_len,int *rparam_len)
4087 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4088 char *str2 = skip_string(param,tpscnt,str1,1);
4089 char *p = skip_string(param,tpscnt,str2,1);
4090 int uLevel;
4091 int succnt;
4092 struct pack_desc desc;
4094 if (!str1 || !str2 || !p) {
4095 return False;
4098 memset((char *)&desc,'\0',sizeof(desc));
4100 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4102 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4104 /* check it's a supported varient */
4105 if (strcmp(str1,"WrLeh") != 0) {
4106 return False;
4108 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4109 return False;
4112 if (mdrcnt > 0) {
4113 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4114 if (!*rdata) {
4115 return False;
4118 memset((char *)&desc,'\0',sizeof(desc));
4119 desc.base = *rdata;
4120 desc.buflen = mdrcnt;
4121 desc.format = str2;
4122 if (init_package(&desc,1,0)) {
4123 PACKS(&desc,"B13","lp0");
4126 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4128 *rdata_len = desc.usedlen;
4130 *rparam_len = 8;
4131 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4132 if (!*rparam) {
4133 return False;
4135 SSVALS(*rparam,0,desc.errcode);
4136 SSVAL(*rparam,2,0);
4137 SSVAL(*rparam,4,succnt);
4138 SSVAL(*rparam,6,1);
4140 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4142 return True;
4145 /****************************************************************************
4146 List open sessions
4147 ****************************************************************************/
4149 static BOOL api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4150 char *param, int tpscnt,
4151 char *data, int tdscnt,
4152 int mdrcnt,int mprcnt,
4153 char **rdata,char **rparam,
4154 int *rdata_len,int *rparam_len)
4157 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4158 char *str2 = skip_string(param,tpscnt,str1,1);
4159 char *p = skip_string(param,tpscnt,str2,1);
4160 int uLevel;
4161 struct pack_desc desc;
4162 struct sessionid *session_list;
4163 int i, num_sessions;
4165 if (!str1 || !str2 || !p) {
4166 return False;
4169 memset((char *)&desc,'\0',sizeof(desc));
4171 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4173 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4174 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4175 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4177 /* check it's a supported varient */
4178 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4179 return False;
4181 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4182 return False;
4185 num_sessions = list_sessions(&session_list);
4187 if (mdrcnt > 0) {
4188 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
4189 if (!*rdata) {
4190 return False;
4193 memset((char *)&desc,'\0',sizeof(desc));
4194 desc.base = *rdata;
4195 desc.buflen = mdrcnt;
4196 desc.format = str2;
4197 if (!init_package(&desc,num_sessions,0)) {
4198 return False;
4201 for(i=0; i<num_sessions; i++) {
4202 PACKS(&desc, "z", session_list[i].remote_machine);
4203 PACKS(&desc, "z", session_list[i].username);
4204 PACKI(&desc, "W", 1); /* num conns */
4205 PACKI(&desc, "W", 0); /* num opens */
4206 PACKI(&desc, "W", 1); /* num users */
4207 PACKI(&desc, "D", 0); /* session time */
4208 PACKI(&desc, "D", 0); /* idle time */
4209 PACKI(&desc, "D", 0); /* flags */
4210 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4213 *rdata_len = desc.usedlen;
4215 *rparam_len = 8;
4216 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4217 if (!*rparam) {
4218 return False;
4220 SSVALS(*rparam,0,desc.errcode);
4221 SSVAL(*rparam,2,0); /* converter */
4222 SSVAL(*rparam,4,num_sessions); /* count */
4224 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4226 return True;
4230 /****************************************************************************
4231 The buffer was too small.
4232 ****************************************************************************/
4234 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4235 int mdrcnt, int mprcnt,
4236 char **rdata, char **rparam,
4237 int *rdata_len, int *rparam_len)
4239 *rparam_len = MIN(*rparam_len,mprcnt);
4240 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4241 if (!*rparam) {
4242 return False;
4245 *rdata_len = 0;
4247 SSVAL(*rparam,0,NERR_BufTooSmall);
4249 DEBUG(3,("Supplied buffer too small in API command\n"));
4251 return True;
4254 /****************************************************************************
4255 The request is not supported.
4256 ****************************************************************************/
4258 static BOOL api_Unsupported(connection_struct *conn, uint16 vuid,
4259 char *param, int tpscnt,
4260 char *data, int tdscnt,
4261 int mdrcnt, int mprcnt,
4262 char **rdata, char **rparam,
4263 int *rdata_len, int *rparam_len)
4265 *rparam_len = 4;
4266 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
4267 if (!*rparam) {
4268 return False;
4271 *rdata_len = 0;
4273 SSVAL(*rparam,0,NERR_notsupported);
4274 SSVAL(*rparam,2,0); /* converter word */
4276 DEBUG(3,("Unsupported API command\n"));
4278 return True;
4281 static const struct {
4282 const char *name;
4283 int id;
4284 BOOL (*fn)(connection_struct *, uint16,
4285 char *, int,
4286 char *, int,
4287 int,int,char **,char **,int *,int *);
4288 BOOL auth_user; /* Deny anonymous access? */
4289 } api_commands[] = {
4290 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4291 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4292 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4293 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4294 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4295 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4296 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4297 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4298 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4299 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4300 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4301 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4302 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4303 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4304 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4305 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4306 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4307 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4308 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4309 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4310 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4311 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4312 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4313 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4314 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4315 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4316 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4317 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4318 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4319 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4320 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4321 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4322 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4323 {NULL, -1, api_Unsupported}
4324 /* The following RAP calls are not implemented by Samba:
4326 RAP_WFileEnum2 - anon not OK
4331 /****************************************************************************
4332 Handle remote api calls
4333 ****************************************************************************/
4335 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
4336 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
4338 int api_command;
4339 char *rdata = NULL;
4340 char *rparam = NULL;
4341 const char *name1 = NULL;
4342 const char *name2 = NULL;
4343 int rdata_len = 0;
4344 int rparam_len = 0;
4345 BOOL reply=False;
4346 int i;
4348 if (!params) {
4349 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4350 return 0;
4353 if (tpscnt < 2) {
4354 return 0;
4356 api_command = SVAL(params,0);
4357 /* Is there a string at position params+2 ? */
4358 if (skip_string(params,tpscnt,params+2,1)) {
4359 name1 = params + 2;
4360 } else {
4361 name1 = "";
4363 name2 = skip_string(params,tpscnt,params+2,1);
4364 if (!name2) {
4365 name2 = "";
4368 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4369 api_command,
4370 name1,
4371 name2,
4372 tdscnt,tpscnt,mdrcnt,mprcnt));
4374 for (i=0;api_commands[i].name;i++) {
4375 if (api_commands[i].id == api_command && api_commands[i].fn) {
4376 DEBUG(3,("Doing %s\n",api_commands[i].name));
4377 break;
4381 /* Check whether this api call can be done anonymously */
4383 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4384 user_struct *user = get_valid_user_struct(vuid);
4386 if (!user || user->guest) {
4387 return ERROR_NT(NT_STATUS_ACCESS_DENIED);
4391 rdata = (char *)SMB_MALLOC(1024);
4392 if (rdata) {
4393 memset(rdata,'\0',1024);
4396 rparam = (char *)SMB_MALLOC(1024);
4397 if (rparam) {
4398 memset(rparam,'\0',1024);
4401 if(!rdata || !rparam) {
4402 DEBUG(0,("api_reply: malloc fail !\n"));
4403 SAFE_FREE(rdata);
4404 SAFE_FREE(rparam);
4405 return -1;
4408 reply = api_commands[i].fn(conn,
4409 vuid,
4410 params,tpscnt, /* params + length */
4411 data,tdscnt, /* data + length */
4412 mdrcnt,mprcnt,
4413 &rdata,&rparam,&rdata_len,&rparam_len);
4416 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4417 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4418 &rdata,&rparam,&rdata_len,&rparam_len);
4421 /* if we get False back then it's actually unsupported */
4422 if (!reply) {
4423 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4424 &rdata,&rparam,&rdata_len,&rparam_len);
4427 /* If api_Unsupported returns false we can't return anything. */
4428 if (reply) {
4429 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
4432 SAFE_FREE(rdata);
4433 SAFE_FREE(rparam);
4434 return -1;