s3/lanman: Workaround for KB932762.
[Samba.git] / source / smbd / lanman.c
blob936a4fdb88252a757353c7d5925d53eaa9431272
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
30 extern struct current_user current_user;
31 extern userdom_struct current_user_info;
33 #ifdef CHECK_TYPES
34 #undef CHECK_TYPES
35 #endif
36 #define CHECK_TYPES 0
38 #define NERR_Success 0
39 #define NERR_badpass 86
40 #define NERR_notsupported 50
42 #define NERR_BASE (2100)
43 #define NERR_BufTooSmall (NERR_BASE+23)
44 #define NERR_JobNotFound (NERR_BASE+51)
45 #define NERR_DestNotFound (NERR_BASE+52)
47 #define ACCESS_READ 0x01
48 #define ACCESS_WRITE 0x02
49 #define ACCESS_CREATE 0x04
51 #define SHPWLEN 8 /* share password length */
53 /* Limit size of ipc replies */
55 static char *smb_realloc_limit(void *ptr, size_t size)
57 char *val;
59 size = MAX((size),4*1024);
60 val = (char *)SMB_REALLOC(ptr,size);
61 if (val) {
62 memset(val,'\0',size);
64 return val;
67 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
68 char *param, int tpscnt,
69 char *data, int tdscnt,
70 int mdrcnt, int mprcnt,
71 char **rdata, char **rparam,
72 int *rdata_len, int *rparam_len);
74 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
75 int mdrcnt, int mprcnt,
76 char **rdata, char **rparam,
77 int *rdata_len, int *rparam_len);
80 static int CopyExpanded(connection_struct *conn,
81 int snum, char **dst, char *src, int *p_space_remaining)
83 TALLOC_CTX *ctx = talloc_tos();
84 char *buf = NULL;
85 int l;
87 if (!src || !dst || !p_space_remaining || !(*dst) ||
88 *p_space_remaining <= 0) {
89 return 0;
92 buf = talloc_strdup(ctx, src);
93 if (!buf) {
94 *p_space_remaining = 0;
95 return 0;
97 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
98 if (!buf) {
99 *p_space_remaining = 0;
100 return 0;
102 buf = talloc_sub_advanced(ctx,
103 lp_servicename(SNUM(conn)),
104 conn->user,
105 conn->connectpath,
106 conn->gid,
107 get_current_username(),
108 current_user_info.domain,
109 buf);
110 if (!buf) {
111 *p_space_remaining = 0;
112 return 0;
114 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
115 if (l == -1) {
116 return 0;
118 (*dst) += l;
119 (*p_space_remaining) -= l;
120 return l;
123 static int CopyAndAdvance(char **dst, char *src, int *n)
125 int l;
126 if (!src || !dst || !n || !(*dst)) {
127 return 0;
129 l = push_ascii(*dst,src,*n, STR_TERMINATE);
130 if (l == -1) {
131 return 0;
133 (*dst) += l;
134 (*n) -= l;
135 return l;
138 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
140 TALLOC_CTX *ctx = talloc_tos();
141 char *buf = NULL;
142 if (!s) {
143 return 0;
145 buf = talloc_strdup(ctx,s);
146 if (!buf) {
147 return 0;
149 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
150 if (!buf) {
151 return 0;
153 buf = talloc_sub_advanced(ctx,
154 lp_servicename(SNUM(conn)),
155 conn->user,
156 conn->connectpath,
157 conn->gid,
158 get_current_username(),
159 current_user_info.domain,
160 buf);
161 if (!buf) {
162 return 0;
164 return strlen(buf) + 1;
167 static char *Expand(connection_struct *conn, int snum, char *s)
169 TALLOC_CTX *ctx = talloc_tos();
170 char *buf = NULL;
172 if (!s) {
173 return NULL;
175 buf = talloc_strdup(ctx,s);
176 if (!buf) {
177 return 0;
179 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
180 if (!buf) {
181 return 0;
183 return talloc_sub_advanced(ctx,
184 lp_servicename(SNUM(conn)),
185 conn->user,
186 conn->connectpath,
187 conn->gid,
188 get_current_username(),
189 current_user_info.domain,
190 buf);
193 /*******************************************************************
194 Check a API string for validity when we only need to check the prefix.
195 ******************************************************************/
197 static bool prefix_ok(const char *str, const char *prefix)
199 return(strncmp(str,prefix,strlen(prefix)) == 0);
202 struct pack_desc {
203 const char *format; /* formatstring for structure */
204 const char *subformat; /* subformat for structure */
205 char *base; /* baseaddress of buffer */
206 int buflen; /* remaining size for fixed part; on init: length of base */
207 int subcount; /* count of substructures */
208 char *structbuf; /* pointer into buffer for remaining fixed part */
209 int stringlen; /* remaining size for variable part */
210 char *stringbuf; /* pointer into buffer for remaining variable part */
211 int neededlen; /* total needed size */
212 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
213 const char *curpos; /* current position; pointer into format or subformat */
214 int errcode;
217 static int get_counter(const char **p)
219 int i, n;
220 if (!p || !(*p)) {
221 return 1;
223 if (!isdigit((int)**p)) {
224 return 1;
226 for (n = 0;;) {
227 i = **p;
228 if (isdigit(i)) {
229 n = 10 * n + (i - '0');
230 } else {
231 return n;
233 (*p)++;
237 static int getlen(const char *p)
239 int n = 0;
240 if (!p) {
241 return 0;
244 while (*p) {
245 switch( *p++ ) {
246 case 'W': /* word (2 byte) */
247 n += 2;
248 break;
249 case 'K': /* status word? (2 byte) */
250 n += 2;
251 break;
252 case 'N': /* count of substructures (word) at end */
253 n += 2;
254 break;
255 case 'D': /* double word (4 byte) */
256 case 'z': /* offset to zero terminated string (4 byte) */
257 case 'l': /* offset to user data (4 byte) */
258 n += 4;
259 break;
260 case 'b': /* offset to data (with counter) (4 byte) */
261 n += 4;
262 get_counter(&p);
263 break;
264 case 'B': /* byte (with optional counter) */
265 n += get_counter(&p);
266 break;
269 return n;
272 static bool init_package(struct pack_desc *p, int count, int subcount)
274 int n = p->buflen;
275 int i;
277 if (!p->format || !p->base) {
278 return False;
281 i = count * getlen(p->format);
282 if (p->subformat) {
283 i += subcount * getlen(p->subformat);
285 p->structbuf = p->base;
286 p->neededlen = 0;
287 p->usedlen = 0;
288 p->subcount = 0;
289 p->curpos = p->format;
290 if (i > n) {
291 p->neededlen = i;
292 i = n = 0;
293 #if 0
295 * This is the old error code we used. Aparently
296 * WinNT/2k systems return ERRbuftoosmall (2123) and
297 * OS/2 needs this. I'm leaving this here so we can revert
298 * if needed. JRA.
300 p->errcode = ERRmoredata;
301 #else
302 p->errcode = ERRbuftoosmall;
303 #endif
304 } else {
305 p->errcode = NERR_Success;
307 p->buflen = i;
308 n -= i;
309 p->stringbuf = p->base + i;
310 p->stringlen = n;
311 return (p->errcode == NERR_Success);
314 static int package(struct pack_desc *p, ...)
316 va_list args;
317 int needed=0, stringneeded;
318 const char *str=NULL;
319 int is_string=0, stringused;
320 int32 temp;
322 va_start(args,p);
324 if (!*p->curpos) {
325 if (!p->subcount) {
326 p->curpos = p->format;
327 } else {
328 p->curpos = p->subformat;
329 p->subcount--;
332 #if CHECK_TYPES
333 str = va_arg(args,char*);
334 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
335 #endif
336 stringneeded = -1;
338 if (!p->curpos) {
339 va_end(args);
340 return 0;
343 switch( *p->curpos++ ) {
344 case 'W': /* word (2 byte) */
345 needed = 2;
346 temp = va_arg(args,int);
347 if (p->buflen >= needed) {
348 SSVAL(p->structbuf,0,temp);
350 break;
351 case 'K': /* status word? (2 byte) */
352 needed = 2;
353 temp = va_arg(args,int);
354 if (p->buflen >= needed) {
355 SSVAL(p->structbuf,0,temp);
357 break;
358 case 'N': /* count of substructures (word) at end */
359 needed = 2;
360 p->subcount = va_arg(args,int);
361 if (p->buflen >= needed) {
362 SSVAL(p->structbuf,0,p->subcount);
364 break;
365 case 'D': /* double word (4 byte) */
366 needed = 4;
367 temp = va_arg(args,int);
368 if (p->buflen >= needed) {
369 SIVAL(p->structbuf,0,temp);
371 break;
372 case 'B': /* byte (with optional counter) */
373 needed = get_counter(&p->curpos);
375 char *s = va_arg(args,char*);
376 if (p->buflen >= needed) {
377 StrnCpy(p->structbuf,s?s:"",needed-1);
380 break;
381 case 'z': /* offset to zero terminated string (4 byte) */
382 str = va_arg(args,char*);
383 stringneeded = (str ? strlen(str)+1 : 0);
384 is_string = 1;
385 break;
386 case 'l': /* offset to user data (4 byte) */
387 str = va_arg(args,char*);
388 stringneeded = va_arg(args,int);
389 is_string = 0;
390 break;
391 case 'b': /* offset to data (with counter) (4 byte) */
392 str = va_arg(args,char*);
393 stringneeded = get_counter(&p->curpos);
394 is_string = 0;
395 break;
398 va_end(args);
399 if (stringneeded >= 0) {
400 needed = 4;
401 if (p->buflen >= needed) {
402 stringused = stringneeded;
403 if (stringused > p->stringlen) {
404 stringused = (is_string ? p->stringlen : 0);
405 if (p->errcode == NERR_Success) {
406 p->errcode = ERRmoredata;
409 if (!stringused) {
410 SIVAL(p->structbuf,0,0);
411 } else {
412 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
413 memcpy(p->stringbuf,str?str:"",stringused);
414 if (is_string) {
415 p->stringbuf[stringused-1] = '\0';
417 p->stringbuf += stringused;
418 p->stringlen -= stringused;
419 p->usedlen += stringused;
422 p->neededlen += stringneeded;
425 p->neededlen += needed;
426 if (p->buflen >= needed) {
427 p->structbuf += needed;
428 p->buflen -= needed;
429 p->usedlen += needed;
430 } else {
431 if (p->errcode == NERR_Success) {
432 p->errcode = ERRmoredata;
435 return 1;
438 #if CHECK_TYPES
439 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
440 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
441 #else
442 #define PACK(desc,t,v) package(desc,v)
443 #define PACKl(desc,t,v,l) package(desc,v,l)
444 #endif
446 static void PACKI(struct pack_desc* desc, const char *t,int v)
448 PACK(desc,t,v);
451 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
453 PACK(desc,t,v);
456 /****************************************************************************
457 Get a print queue.
458 ****************************************************************************/
460 static void PackDriverData(struct pack_desc* desc)
462 char drivdata[4+4+32];
463 SIVAL(drivdata,0,sizeof drivdata); /* cb */
464 SIVAL(drivdata,4,1000); /* lVersion */
465 memset(drivdata+8,0,32); /* szDeviceName */
466 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
467 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
470 static int check_printq_info(struct pack_desc* desc,
471 unsigned int uLevel, char *id1, char *id2)
473 desc->subformat = NULL;
474 switch( uLevel ) {
475 case 0:
476 desc->format = "B13";
477 break;
478 case 1:
479 desc->format = "B13BWWWzzzzzWW";
480 break;
481 case 2:
482 desc->format = "B13BWWWzzzzzWN";
483 desc->subformat = "WB21BB16B10zWWzDDz";
484 break;
485 case 3:
486 desc->format = "zWWWWzzzzWWzzl";
487 break;
488 case 4:
489 desc->format = "zWWWWzzzzWNzzl";
490 desc->subformat = "WWzWWDDzz";
491 break;
492 case 5:
493 desc->format = "z";
494 break;
495 case 51:
496 desc->format = "K";
497 break;
498 case 52:
499 desc->format = "WzzzzzzzzN";
500 desc->subformat = "z";
501 break;
502 default:
503 DEBUG(0,("check_printq_info: invalid level %d\n",
504 uLevel ));
505 return False;
507 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
508 DEBUG(0,("check_printq_info: invalid format %s\n",
509 id1 ? id1 : "<NULL>" ));
510 return False;
512 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
513 DEBUG(0,("check_printq_info: invalid subformat %s\n",
514 id2 ? id2 : "<NULL>" ));
515 return False;
517 return True;
521 #define RAP_JOB_STATUS_QUEUED 0
522 #define RAP_JOB_STATUS_PAUSED 1
523 #define RAP_JOB_STATUS_SPOOLING 2
524 #define RAP_JOB_STATUS_PRINTING 3
525 #define RAP_JOB_STATUS_PRINTED 4
527 #define RAP_QUEUE_STATUS_PAUSED 1
528 #define RAP_QUEUE_STATUS_ERROR 2
530 /* turn a print job status into a on the wire status
532 static int printj_status(int v)
534 switch (v) {
535 case LPQ_QUEUED:
536 return RAP_JOB_STATUS_QUEUED;
537 case LPQ_PAUSED:
538 return RAP_JOB_STATUS_PAUSED;
539 case LPQ_SPOOLING:
540 return RAP_JOB_STATUS_SPOOLING;
541 case LPQ_PRINTING:
542 return RAP_JOB_STATUS_PRINTING;
544 return 0;
547 /* turn a print queue status into a on the wire status
549 static int printq_status(int v)
551 switch (v) {
552 case LPQ_QUEUED:
553 return 0;
554 case LPQ_PAUSED:
555 return RAP_QUEUE_STATUS_PAUSED;
557 return RAP_QUEUE_STATUS_ERROR;
560 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
561 struct pack_desc *desc,
562 print_queue_struct *queue, int n)
564 time_t t = queue->time;
566 /* the client expects localtime */
567 t -= get_time_zone(t);
569 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
570 if (uLevel == 1) {
571 PACKS(desc,"B21",queue->fs_user); /* szUserName */
572 PACKS(desc,"B",""); /* pad */
573 PACKS(desc,"B16",""); /* szNotifyName */
574 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
575 PACKS(desc,"z",""); /* pszParms */
576 PACKI(desc,"W",n+1); /* uPosition */
577 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
578 PACKS(desc,"z",""); /* pszStatus */
579 PACKI(desc,"D",t); /* ulSubmitted */
580 PACKI(desc,"D",queue->size); /* ulSize */
581 PACKS(desc,"z",queue->fs_file); /* pszComment */
583 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
584 PACKI(desc,"W",queue->priority); /* uPriority */
585 PACKS(desc,"z",queue->fs_user); /* pszUserName */
586 PACKI(desc,"W",n+1); /* uPosition */
587 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
588 PACKI(desc,"D",t); /* ulSubmitted */
589 PACKI(desc,"D",queue->size); /* ulSize */
590 PACKS(desc,"z","Samba"); /* pszComment */
591 PACKS(desc,"z",queue->fs_file); /* pszDocument */
592 if (uLevel == 3) {
593 PACKS(desc,"z",""); /* pszNotifyName */
594 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
595 PACKS(desc,"z",""); /* pszParms */
596 PACKS(desc,"z",""); /* pszStatus */
597 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
598 PACKS(desc,"z","lpd"); /* pszQProcName */
599 PACKS(desc,"z",""); /* pszQProcParms */
600 PACKS(desc,"z","NULL"); /* pszDriverName */
601 PackDriverData(desc); /* pDriverData */
602 PACKS(desc,"z",""); /* pszPrinterName */
603 } else if (uLevel == 4) { /* OS2 */
604 PACKS(desc,"z",""); /* pszSpoolFileName */
605 PACKS(desc,"z",""); /* pszPortName */
606 PACKS(desc,"z",""); /* pszStatus */
607 PACKI(desc,"D",0); /* ulPagesSpooled */
608 PACKI(desc,"D",0); /* ulPagesSent */
609 PACKI(desc,"D",0); /* ulPagesPrinted */
610 PACKI(desc,"D",0); /* ulTimePrinted */
611 PACKI(desc,"D",0); /* ulExtendJobStatus */
612 PACKI(desc,"D",0); /* ulStartPage */
613 PACKI(desc,"D",0); /* ulEndPage */
618 /********************************************************************
619 Return a driver name given an snum.
620 Returns True if from tdb, False otherwise.
621 ********************************************************************/
623 static bool get_driver_name(int snum, char **pp_drivername)
625 NT_PRINTER_INFO_LEVEL *info = NULL;
626 bool in_tdb = false;
628 get_a_printer (NULL, &info, 2, lp_servicename(snum));
629 if (info != NULL) {
630 *pp_drivername = talloc_strdup(talloc_tos(),
631 info->info_2->drivername);
632 in_tdb = true;
633 free_a_printer(&info, 2);
634 if (!*pp_drivername) {
635 return false;
639 return in_tdb;
642 /********************************************************************
643 Respond to the DosPrintQInfo command with a level of 52
644 This is used to get printer driver information for Win9x clients
645 ********************************************************************/
646 static void fill_printq_info_52(connection_struct *conn, int snum,
647 struct pack_desc* desc, int count )
649 int i;
650 fstring location;
651 NT_PRINTER_DRIVER_INFO_LEVEL driver;
652 NT_PRINTER_INFO_LEVEL *printer = NULL;
654 ZERO_STRUCT(driver);
656 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
657 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
658 lp_servicename(snum)));
659 goto err;
662 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
663 "Windows 4.0", 0)) )
665 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
666 printer->info_2->drivername));
667 goto err;
670 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
671 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
672 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
674 PACKI(desc, "W", 0x0400); /* don't know */
675 PACKS(desc, "z", driver.info_3->name); /* long printer name */
676 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
677 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
678 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
680 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
681 standard_sub_basic( "", "", location, sizeof(location)-1 );
682 PACKS(desc,"z", location); /* share to retrieve files */
684 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
685 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
686 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
688 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
689 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
690 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
691 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
692 DEBUG(3,("Driver Location: %s:\n",location));
693 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
694 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
695 PACKI(desc,"N",count); /* number of files to copy */
697 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
699 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
700 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
701 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
704 /* sanity check */
705 if ( i != count )
706 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
707 count, i));
709 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
711 desc->errcode=NERR_Success;
712 goto done;
714 err:
715 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
716 desc->errcode=NERR_notsupported;
718 done:
719 if ( printer )
720 free_a_printer( &printer, 2 );
722 if ( driver.info_3 )
723 free_a_printer_driver( driver, 3 );
727 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
728 struct pack_desc* desc,
729 int count, print_queue_struct* queue,
730 print_status_struct* status)
732 switch (uLevel) {
733 case 1:
734 case 2:
735 PACKS(desc,"B13",SERVICE(snum));
736 break;
737 case 3:
738 case 4:
739 case 5:
740 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
741 break;
742 case 51:
743 PACKI(desc,"K",printq_status(status->status));
744 break;
747 if (uLevel == 1 || uLevel == 2) {
748 PACKS(desc,"B",""); /* alignment */
749 PACKI(desc,"W",5); /* priority */
750 PACKI(desc,"W",0); /* start time */
751 PACKI(desc,"W",0); /* until time */
752 PACKS(desc,"z",""); /* pSepFile */
753 PACKS(desc,"z","lpd"); /* pPrProc */
754 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
755 PACKS(desc,"z",""); /* pParms */
756 if (snum < 0) {
757 PACKS(desc,"z","UNKNOWN PRINTER");
758 PACKI(desc,"W",LPSTAT_ERROR);
760 else if (!status || !status->message[0]) {
761 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
762 PACKI(desc,"W",LPSTAT_OK); /* status */
763 } else {
764 PACKS(desc,"z",status->message);
765 PACKI(desc,"W",printq_status(status->status)); /* status */
767 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
770 if (uLevel == 3 || uLevel == 4) {
771 char *drivername = NULL;
773 PACKI(desc,"W",5); /* uPriority */
774 PACKI(desc,"W",0); /* uStarttime */
775 PACKI(desc,"W",0); /* uUntiltime */
776 PACKI(desc,"W",5); /* pad1 */
777 PACKS(desc,"z",""); /* pszSepFile */
778 PACKS(desc,"z","WinPrint"); /* pszPrProc */
779 PACKS(desc,"z",NULL); /* pszParms */
780 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
781 /* "don't ask" that it's done this way to fix corrupted
782 Win9X/ME printer comments. */
783 if (!status) {
784 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
785 } else {
786 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
788 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
789 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
790 get_driver_name(snum,&drivername);
791 if (!drivername) {
792 return;
794 PACKS(desc,"z",drivername); /* pszDriverName */
795 PackDriverData(desc); /* pDriverData */
798 if (uLevel == 2 || uLevel == 4) {
799 int i;
800 for (i=0;i<count;i++)
801 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
804 if (uLevel==52)
805 fill_printq_info_52( conn, snum, desc, count );
808 /* This function returns the number of files for a given driver */
809 static int get_printerdrivernumber(int snum)
811 int result = 0;
812 NT_PRINTER_DRIVER_INFO_LEVEL driver;
813 NT_PRINTER_INFO_LEVEL *printer = NULL;
815 ZERO_STRUCT(driver);
817 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
818 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
819 lp_servicename(snum)));
820 goto done;
823 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
824 "Windows 4.0", 0)) )
826 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
827 printer->info_2->drivername));
828 goto done;
831 /* count the number of files */
832 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
833 result++;
835 done:
836 if ( printer )
837 free_a_printer( &printer, 2 );
839 if ( driver.info_3 )
840 free_a_printer_driver( driver, 3 );
842 return result;
845 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
846 char *param, int tpscnt,
847 char *data, int tdscnt,
848 int mdrcnt,int mprcnt,
849 char **rdata,char **rparam,
850 int *rdata_len,int *rparam_len)
852 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
853 char *str2 = skip_string(param,tpscnt,str1);
854 char *p = skip_string(param,tpscnt,str2);
855 char *QueueName = p;
856 unsigned int uLevel;
857 int count=0;
858 int snum;
859 char *str3;
860 struct pack_desc desc;
861 print_queue_struct *queue=NULL;
862 print_status_struct status;
863 char* tmpdata=NULL;
865 if (!str1 || !str2 || !p) {
866 return False;
868 memset((char *)&status,'\0',sizeof(status));
869 memset((char *)&desc,'\0',sizeof(desc));
871 p = skip_string(param,tpscnt,p);
872 if (!p) {
873 return False;
875 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
876 str3 = get_safe_str_ptr(param,tpscnt,p,4);
877 /* str3 may be null here and is checked in check_printq_info(). */
879 /* remove any trailing username */
880 if ((p = strchr_m(QueueName,'%')))
881 *p = 0;
883 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
885 /* check it's a supported varient */
886 if (!prefix_ok(str1,"zWrLh"))
887 return False;
888 if (!check_printq_info(&desc,uLevel,str2,str3)) {
890 * Patch from Scott Moomaw <scott@bridgewater.edu>
891 * to return the 'invalid info level' error if an
892 * unknown level was requested.
894 *rdata_len = 0;
895 *rparam_len = 6;
896 *rparam = smb_realloc_limit(*rparam,*rparam_len);
897 if (!*rparam) {
898 return False;
900 SSVALS(*rparam,0,ERRunknownlevel);
901 SSVAL(*rparam,2,0);
902 SSVAL(*rparam,4,0);
903 return(True);
906 snum = find_service(QueueName);
907 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
908 return False;
910 if (uLevel==52) {
911 count = get_printerdrivernumber(snum);
912 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
913 } else {
914 count = print_queue_status(snum, &queue,&status);
917 if (mdrcnt > 0) {
918 *rdata = smb_realloc_limit(*rdata,mdrcnt);
919 if (!*rdata) {
920 SAFE_FREE(queue);
921 return False;
923 desc.base = *rdata;
924 desc.buflen = mdrcnt;
925 } else {
927 * Don't return data but need to get correct length
928 * init_package will return wrong size if buflen=0
930 desc.buflen = getlen(desc.format);
931 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
934 if (init_package(&desc,1,count)) {
935 desc.subcount = count;
936 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
939 *rdata_len = desc.usedlen;
942 * We must set the return code to ERRbuftoosmall
943 * in order to support lanman style printing with Win NT/2k
944 * clients --jerry
946 if (!mdrcnt && lp_disable_spoolss())
947 desc.errcode = ERRbuftoosmall;
949 *rdata_len = desc.usedlen;
950 *rparam_len = 6;
951 *rparam = smb_realloc_limit(*rparam,*rparam_len);
952 if (!*rparam) {
953 SAFE_FREE(queue);
954 SAFE_FREE(tmpdata);
955 return False;
957 SSVALS(*rparam,0,desc.errcode);
958 SSVAL(*rparam,2,0);
959 SSVAL(*rparam,4,desc.neededlen);
961 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
963 SAFE_FREE(queue);
964 SAFE_FREE(tmpdata);
966 return(True);
969 /****************************************************************************
970 View list of all print jobs on all queues.
971 ****************************************************************************/
973 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
974 char *param, int tpscnt,
975 char *data, int tdscnt,
976 int mdrcnt, int mprcnt,
977 char **rdata, char** rparam,
978 int *rdata_len, int *rparam_len)
980 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
981 char *output_format1 = skip_string(param,tpscnt,param_format);
982 char *p = skip_string(param,tpscnt,output_format1);
983 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
984 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
985 int services = lp_numservices();
986 int i, n;
987 struct pack_desc desc;
988 print_queue_struct **queue = NULL;
989 print_status_struct *status = NULL;
990 int *subcntarr = NULL;
991 int queuecnt = 0, subcnt = 0, succnt = 0;
993 if (!param_format || !output_format1 || !p) {
994 return False;
997 memset((char *)&desc,'\0',sizeof(desc));
999 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1001 if (!prefix_ok(param_format,"WrLeh")) {
1002 return False;
1004 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1006 * Patch from Scott Moomaw <scott@bridgewater.edu>
1007 * to return the 'invalid info level' error if an
1008 * unknown level was requested.
1010 *rdata_len = 0;
1011 *rparam_len = 6;
1012 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1013 if (!*rparam) {
1014 return False;
1016 SSVALS(*rparam,0,ERRunknownlevel);
1017 SSVAL(*rparam,2,0);
1018 SSVAL(*rparam,4,0);
1019 return(True);
1022 for (i = 0; i < services; i++) {
1023 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1024 queuecnt++;
1028 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1029 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1030 goto err;
1032 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1033 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1034 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1035 goto err;
1037 memset(status,0,queuecnt*sizeof(print_status_struct));
1038 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1039 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1040 goto err;
1043 subcnt = 0;
1044 n = 0;
1045 for (i = 0; i < services; i++) {
1046 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1047 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1048 subcnt += subcntarr[n];
1049 n++;
1053 if (mdrcnt > 0) {
1054 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1055 if (!*rdata) {
1056 goto err;
1059 desc.base = *rdata;
1060 desc.buflen = mdrcnt;
1062 if (init_package(&desc,queuecnt,subcnt)) {
1063 n = 0;
1064 succnt = 0;
1065 for (i = 0; i < services; i++) {
1066 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1067 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1068 n++;
1069 if (desc.errcode == NERR_Success) {
1070 succnt = n;
1076 SAFE_FREE(subcntarr);
1078 *rdata_len = desc.usedlen;
1079 *rparam_len = 8;
1080 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1081 if (!*rparam) {
1082 goto err;
1084 SSVALS(*rparam,0,desc.errcode);
1085 SSVAL(*rparam,2,0);
1086 SSVAL(*rparam,4,succnt);
1087 SSVAL(*rparam,6,queuecnt);
1089 for (i = 0; i < queuecnt; i++) {
1090 if (queue) {
1091 SAFE_FREE(queue[i]);
1095 SAFE_FREE(queue);
1096 SAFE_FREE(status);
1098 return True;
1100 err:
1102 SAFE_FREE(subcntarr);
1103 for (i = 0; i < queuecnt; i++) {
1104 if (queue) {
1105 SAFE_FREE(queue[i]);
1108 SAFE_FREE(queue);
1109 SAFE_FREE(status);
1111 return False;
1114 /****************************************************************************
1115 Get info level for a server list query.
1116 ****************************************************************************/
1118 static bool check_server_info(int uLevel, char* id)
1120 switch( uLevel ) {
1121 case 0:
1122 if (strcmp(id,"B16") != 0) {
1123 return False;
1125 break;
1126 case 1:
1127 if (strcmp(id,"B16BBDz") != 0) {
1128 return False;
1130 break;
1131 default:
1132 return False;
1134 return True;
1137 struct srv_info_struct {
1138 fstring name;
1139 uint32 type;
1140 fstring comment;
1141 fstring domain;
1142 bool server_added;
1145 /*******************************************************************
1146 Get server info lists from the files saved by nmbd. Return the
1147 number of entries.
1148 ******************************************************************/
1150 static int get_server_info(uint32 servertype,
1151 struct srv_info_struct **servers,
1152 const char *domain)
1154 int count=0;
1155 int alloced=0;
1156 char **lines;
1157 bool local_list_only;
1158 int i;
1160 lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1161 if (!lines) {
1162 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1163 return 0;
1166 /* request for everything is code for request all servers */
1167 if (servertype == SV_TYPE_ALL) {
1168 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1171 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1173 DEBUG(4,("Servertype search: %8x\n",servertype));
1175 for (i=0;lines[i];i++) {
1176 fstring stype;
1177 struct srv_info_struct *s;
1178 const char *ptr = lines[i];
1179 bool ok = True;
1180 TALLOC_CTX *frame = NULL;
1181 char *p;
1183 if (!*ptr) {
1184 continue;
1187 if (count == alloced) {
1188 alloced += 10;
1189 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1190 if (!*servers) {
1191 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1192 file_lines_free(lines);
1193 return 0;
1195 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1197 s = &(*servers)[count];
1199 frame = talloc_stackframe();
1200 s->name[0] = '\0';
1201 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1202 TALLOC_FREE(frame);
1203 continue;
1205 fstrcpy(s->name, p);
1207 stype[0] = '\0';
1208 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1209 TALLOC_FREE(frame);
1210 continue;
1212 fstrcpy(stype, p);
1214 s->comment[0] = '\0';
1215 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1216 TALLOC_FREE(frame);
1217 continue;
1219 fstrcpy(s->comment, p);
1220 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1222 s->domain[0] = '\0';
1223 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1224 /* this allows us to cope with an old nmbd */
1225 fstrcpy(s->domain,lp_workgroup());
1226 } else {
1227 fstrcpy(s->domain, p);
1229 TALLOC_FREE(frame);
1231 if (sscanf(stype,"%X",&s->type) != 1) {
1232 DEBUG(4,("r:host file "));
1233 ok = False;
1236 /* Filter the servers/domains we return based on what was asked for. */
1238 /* Check to see if we are being asked for a local list only. */
1239 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1240 DEBUG(4,("r: local list only"));
1241 ok = False;
1244 /* doesn't match up: don't want it */
1245 if (!(servertype & s->type)) {
1246 DEBUG(4,("r:serv type "));
1247 ok = False;
1250 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1251 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1252 DEBUG(4,("s: dom mismatch "));
1253 ok = False;
1256 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1257 ok = False;
1260 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1261 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1263 if (ok) {
1264 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1265 s->name, s->type, s->comment, s->domain));
1266 s->server_added = True;
1267 count++;
1268 } else {
1269 DEBUG(4,("%20s %8x %25s %15s\n",
1270 s->name, s->type, s->comment, s->domain));
1274 file_lines_free(lines);
1275 return count;
1278 /*******************************************************************
1279 Fill in a server info structure.
1280 ******************************************************************/
1282 static int fill_srv_info(struct srv_info_struct *service,
1283 int uLevel, char **buf, int *buflen,
1284 char **stringbuf, int *stringspace, char *baseaddr)
1286 int struct_len;
1287 char* p;
1288 char* p2;
1289 int l2;
1290 int len;
1292 switch (uLevel) {
1293 case 0:
1294 struct_len = 16;
1295 break;
1296 case 1:
1297 struct_len = 26;
1298 break;
1299 default:
1300 return -1;
1303 if (!buf) {
1304 len = 0;
1305 switch (uLevel) {
1306 case 1:
1307 len = strlen(service->comment)+1;
1308 break;
1311 *buflen = struct_len;
1312 *stringspace = len;
1313 return struct_len + len;
1316 len = struct_len;
1317 p = *buf;
1318 if (*buflen < struct_len) {
1319 return -1;
1321 if (stringbuf) {
1322 p2 = *stringbuf;
1323 l2 = *stringspace;
1324 } else {
1325 p2 = p + struct_len;
1326 l2 = *buflen - struct_len;
1328 if (!baseaddr) {
1329 baseaddr = p;
1332 switch (uLevel) {
1333 case 0:
1334 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1335 break;
1337 case 1:
1338 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1339 SIVAL(p,18,service->type);
1340 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1341 len += CopyAndAdvance(&p2,service->comment,&l2);
1342 break;
1345 if (stringbuf) {
1346 *buf = p + struct_len;
1347 *buflen -= struct_len;
1348 *stringbuf = p2;
1349 *stringspace = l2;
1350 } else {
1351 *buf = p2;
1352 *buflen -= len;
1354 return len;
1358 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1360 return(strcmp(s1->name,s2->name));
1363 /****************************************************************************
1364 View list of servers available (or possibly domains). The info is
1365 extracted from lists saved by nmbd on the local host.
1366 ****************************************************************************/
1368 static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1369 char *param, int tpscnt,
1370 char *data, int tdscnt,
1371 int mdrcnt, int mprcnt, char **rdata,
1372 char **rparam, int *rdata_len, int *rparam_len)
1374 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1375 char *str2 = skip_string(param,tpscnt,str1);
1376 char *p = skip_string(param,tpscnt,str2);
1377 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1378 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1379 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1380 char *p2;
1381 int data_len, fixed_len, string_len;
1382 int f_len = 0, s_len = 0;
1383 struct srv_info_struct *servers=NULL;
1384 int counted=0,total=0;
1385 int i,missed;
1386 fstring domain;
1387 bool domain_request;
1388 bool local_request;
1390 if (!str1 || !str2 || !p) {
1391 return False;
1394 /* If someone sets all the bits they don't really mean to set
1395 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1396 known servers. */
1398 if (servertype == SV_TYPE_ALL) {
1399 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1402 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1403 any other bit (they may just set this bit on its own) they
1404 want all the locally seen servers. However this bit can be
1405 set on its own so set the requested servers to be
1406 ALL - DOMAIN_ENUM. */
1408 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1409 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1412 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1413 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1415 p += 8;
1417 if (!prefix_ok(str1,"WrLehD")) {
1418 return False;
1420 if (!check_server_info(uLevel,str2)) {
1421 return False;
1424 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1425 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1426 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1428 if (strcmp(str1, "WrLehDz") == 0) {
1429 if (skip_string(param,tpscnt,p) == NULL) {
1430 return False;
1432 pull_ascii_fstring(domain, p);
1433 } else {
1434 fstrcpy(domain, lp_workgroup());
1437 if (lp_browse_list()) {
1438 total = get_server_info(servertype,&servers,domain);
1441 data_len = fixed_len = string_len = 0;
1442 missed = 0;
1444 if (total > 0) {
1445 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1449 char *lastname=NULL;
1451 for (i=0;i<total;i++) {
1452 struct srv_info_struct *s = &servers[i];
1454 if (lastname && strequal(lastname,s->name)) {
1455 continue;
1457 lastname = s->name;
1458 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1459 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1460 s->name, s->type, s->comment, s->domain));
1462 if (data_len <= buf_len) {
1463 counted++;
1464 fixed_len += f_len;
1465 string_len += s_len;
1466 } else {
1467 missed++;
1472 *rdata_len = fixed_len + string_len;
1473 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1474 if (!*rdata) {
1475 return False;
1478 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1479 p = *rdata;
1480 f_len = fixed_len;
1481 s_len = string_len;
1484 char *lastname=NULL;
1485 int count2 = counted;
1487 for (i = 0; i < total && count2;i++) {
1488 struct srv_info_struct *s = &servers[i];
1490 if (lastname && strequal(lastname,s->name)) {
1491 continue;
1493 lastname = s->name;
1494 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1495 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1496 s->name, s->type, s->comment, s->domain));
1497 count2--;
1501 *rparam_len = 8;
1502 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1503 if (!*rparam) {
1504 return False;
1506 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1507 SSVAL(*rparam,2,0);
1508 SSVAL(*rparam,4,counted);
1509 SSVAL(*rparam,6,counted+missed);
1511 SAFE_FREE(servers);
1513 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1514 domain,uLevel,counted,counted+missed));
1516 return True;
1519 /****************************************************************************
1520 command 0x34 - suspected of being a "Lookup Names" stub api
1521 ****************************************************************************/
1523 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1524 char *param, int tpscnt,
1525 char *data, int tdscnt,
1526 int mdrcnt, int mprcnt, char **rdata,
1527 char **rparam, int *rdata_len, int *rparam_len)
1529 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1530 char *str2 = skip_string(param,tpscnt,str1);
1531 char *p = skip_string(param,tpscnt,str2);
1532 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1533 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1534 int counted=0;
1535 int missed=0;
1537 if (!str1 || !str2 || !p) {
1538 return False;
1541 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1542 str1, str2, p, uLevel, buf_len));
1544 if (!prefix_ok(str1,"zWrLeh")) {
1545 return False;
1548 *rdata_len = 0;
1550 *rparam_len = 8;
1551 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1552 if (!*rparam) {
1553 return False;
1556 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1557 SSVAL(*rparam,2,0);
1558 SSVAL(*rparam,4,counted);
1559 SSVAL(*rparam,6,counted+missed);
1561 return True;
1564 /****************************************************************************
1565 get info about a share
1566 ****************************************************************************/
1568 static bool check_share_info(int uLevel, char* id)
1570 switch( uLevel ) {
1571 case 0:
1572 if (strcmp(id,"B13") != 0) {
1573 return False;
1575 break;
1576 case 1:
1577 if (strcmp(id,"B13BWz") != 0) {
1578 return False;
1580 break;
1581 case 2:
1582 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1583 return False;
1585 break;
1586 case 91:
1587 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1588 return False;
1590 break;
1591 default:
1592 return False;
1594 return True;
1597 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1598 char** buf, int* buflen,
1599 char** stringbuf, int* stringspace, char* baseaddr)
1601 int struct_len;
1602 char* p;
1603 char* p2;
1604 int l2;
1605 int len;
1607 switch( uLevel ) {
1608 case 0:
1609 struct_len = 13;
1610 break;
1611 case 1:
1612 struct_len = 20;
1613 break;
1614 case 2:
1615 struct_len = 40;
1616 break;
1617 case 91:
1618 struct_len = 68;
1619 break;
1620 default:
1621 return -1;
1625 if (!buf) {
1626 len = 0;
1628 if (uLevel > 0) {
1629 len += StrlenExpanded(conn,snum,lp_comment(snum));
1631 if (uLevel > 1) {
1632 len += strlen(lp_pathname(snum)) + 1;
1634 if (buflen) {
1635 *buflen = struct_len;
1637 if (stringspace) {
1638 *stringspace = len;
1640 return struct_len + len;
1643 len = struct_len;
1644 p = *buf;
1645 if ((*buflen) < struct_len) {
1646 return -1;
1649 if (stringbuf) {
1650 p2 = *stringbuf;
1651 l2 = *stringspace;
1652 } else {
1653 p2 = p + struct_len;
1654 l2 = (*buflen) - struct_len;
1657 if (!baseaddr) {
1658 baseaddr = p;
1661 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1663 if (uLevel > 0) {
1664 int type;
1666 SCVAL(p,13,0);
1667 type = STYPE_DISKTREE;
1668 if (lp_print_ok(snum)) {
1669 type = STYPE_PRINTQ;
1671 if (strequal("IPC",lp_fstype(snum))) {
1672 type = STYPE_IPC;
1674 SSVAL(p,14,type); /* device type */
1675 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1676 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1679 if (uLevel > 1) {
1680 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1681 SSVALS(p,22,-1); /* max uses */
1682 SSVAL(p,24,1); /* current uses */
1683 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1684 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1685 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1688 if (uLevel > 2) {
1689 memset(p+40,0,SHPWLEN+2);
1690 SSVAL(p,50,0);
1691 SIVAL(p,52,0);
1692 SSVAL(p,56,0);
1693 SSVAL(p,58,0);
1694 SIVAL(p,60,0);
1695 SSVAL(p,64,0);
1696 SSVAL(p,66,0);
1699 if (stringbuf) {
1700 (*buf) = p + struct_len;
1701 (*buflen) -= struct_len;
1702 (*stringbuf) = p2;
1703 (*stringspace) = l2;
1704 } else {
1705 (*buf) = p2;
1706 (*buflen) -= len;
1709 return len;
1712 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1713 char *param, int tpscnt,
1714 char *data, int tdscnt,
1715 int mdrcnt,int mprcnt,
1716 char **rdata,char **rparam,
1717 int *rdata_len,int *rparam_len)
1719 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1720 char *str2 = skip_string(param,tpscnt,str1);
1721 char *netname = skip_string(param,tpscnt,str2);
1722 char *p = skip_string(param,tpscnt,netname);
1723 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1724 int snum;
1726 if (!str1 || !str2 || !netname || !p) {
1727 return False;
1730 snum = find_service(netname);
1731 if (snum < 0) {
1732 return False;
1735 /* check it's a supported varient */
1736 if (!prefix_ok(str1,"zWrLh")) {
1737 return False;
1739 if (!check_share_info(uLevel,str2)) {
1740 return False;
1743 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1744 if (!*rdata) {
1745 return False;
1747 p = *rdata;
1748 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1749 if (*rdata_len < 0) {
1750 return False;
1753 *rparam_len = 6;
1754 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1755 if (!*rparam) {
1756 return False;
1758 SSVAL(*rparam,0,NERR_Success);
1759 SSVAL(*rparam,2,0); /* converter word */
1760 SSVAL(*rparam,4,*rdata_len);
1762 return True;
1765 /****************************************************************************
1766 View the list of available shares.
1768 This function is the server side of the NetShareEnum() RAP call.
1769 It fills the return buffer with share names and share comments.
1770 Note that the return buffer normally (in all known cases) allows only
1771 twelve byte strings for share names (plus one for a nul terminator).
1772 Share names longer than 12 bytes must be skipped.
1773 ****************************************************************************/
1775 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1776 char *param, int tpscnt,
1777 char *data, int tdscnt,
1778 int mdrcnt,
1779 int mprcnt,
1780 char **rdata,
1781 char **rparam,
1782 int *rdata_len,
1783 int *rparam_len )
1785 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1786 char *str2 = skip_string(param,tpscnt,str1);
1787 char *p = skip_string(param,tpscnt,str2);
1788 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1789 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1790 char *p2;
1791 int count = 0;
1792 int total=0,counted=0;
1793 bool missed = False;
1794 int i;
1795 int data_len, fixed_len, string_len;
1796 int f_len = 0, s_len = 0;
1798 if (!str1 || !str2 || !p) {
1799 return False;
1802 if (!prefix_ok(str1,"WrLeh")) {
1803 return False;
1805 if (!check_share_info(uLevel,str2)) {
1806 return False;
1809 /* Ensure all the usershares are loaded. */
1810 become_root();
1811 load_registry_shares();
1812 count = load_usershare_shares();
1813 unbecome_root();
1815 data_len = fixed_len = string_len = 0;
1816 for (i=0;i<count;i++) {
1817 fstring servicename_dos;
1818 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1819 continue;
1821 push_ascii_fstring(servicename_dos, lp_servicename(i));
1822 /* Maximum name length = 13. */
1823 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1824 total++;
1825 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1826 if (data_len <= buf_len) {
1827 counted++;
1828 fixed_len += f_len;
1829 string_len += s_len;
1830 } else {
1831 missed = True;
1836 *rdata_len = fixed_len + string_len;
1837 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1838 if (!*rdata) {
1839 return False;
1842 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1843 p = *rdata;
1844 f_len = fixed_len;
1845 s_len = string_len;
1847 for( i = 0; i < count; i++ ) {
1848 fstring servicename_dos;
1849 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1850 continue;
1853 push_ascii_fstring(servicename_dos, lp_servicename(i));
1854 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1855 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1856 break;
1861 *rparam_len = 8;
1862 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1863 if (!*rparam) {
1864 return False;
1866 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1867 SSVAL(*rparam,2,0);
1868 SSVAL(*rparam,4,counted);
1869 SSVAL(*rparam,6,total);
1871 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1872 counted,total,uLevel,
1873 buf_len,*rdata_len,mdrcnt));
1875 return True;
1878 /****************************************************************************
1879 Add a share
1880 ****************************************************************************/
1882 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1883 char *param, int tpscnt,
1884 char *data, int tdscnt,
1885 int mdrcnt,int mprcnt,
1886 char **rdata,char **rparam,
1887 int *rdata_len,int *rparam_len)
1889 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1890 char *str2 = skip_string(param,tpscnt,str1);
1891 char *p = skip_string(param,tpscnt,str2);
1892 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1893 fstring sharename;
1894 fstring comment;
1895 char *pathname = NULL;
1896 char *command, *cmdname;
1897 unsigned int offset;
1898 int snum;
1899 int res = ERRunsup;
1901 if (!str1 || !str2 || !p) {
1902 return False;
1905 /* check it's a supported varient */
1906 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1907 return False;
1909 if (!check_share_info(uLevel,str2)) {
1910 return False;
1912 if (uLevel != 2) {
1913 return False;
1916 /* Do we have a string ? */
1917 if (skip_string(data,mdrcnt,data) == NULL) {
1918 return False;
1920 pull_ascii_fstring(sharename,data);
1921 snum = find_service(sharename);
1922 if (snum >= 0) { /* already exists */
1923 res = ERRfilexists;
1924 goto error_exit;
1927 if (mdrcnt < 28) {
1928 return False;
1931 /* only support disk share adds */
1932 if (SVAL(data,14)!=STYPE_DISKTREE) {
1933 return False;
1936 offset = IVAL(data, 16);
1937 if (offset >= mdrcnt) {
1938 res = ERRinvalidparam;
1939 goto error_exit;
1942 /* Do we have a string ? */
1943 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1944 return False;
1946 pull_ascii_fstring(comment, offset? (data+offset) : "");
1948 offset = IVAL(data, 26);
1950 if (offset >= mdrcnt) {
1951 res = ERRinvalidparam;
1952 goto error_exit;
1955 /* Do we have a string ? */
1956 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1957 return False;
1960 pull_ascii_talloc(talloc_tos(), &pathname, offset? (data+offset) : "");
1961 if (!pathname) {
1962 return false;
1965 string_replace(sharename, '"', ' ');
1966 string_replace(pathname, '"', ' ');
1967 string_replace(comment, '"', ' ');
1969 cmdname = lp_add_share_cmd();
1971 if (!cmdname || *cmdname == '\0') {
1972 return False;
1975 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1976 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
1977 pathname, comment) == -1) {
1978 return false;
1981 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1983 if ((res = smbrun(command, NULL)) != 0) {
1984 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
1985 command, res ));
1986 SAFE_FREE(command);
1987 res = ERRnoaccess;
1988 goto error_exit;
1989 } else {
1990 SAFE_FREE(command);
1991 message_send_all(smbd_messaging_context(),
1992 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1995 *rparam_len = 6;
1996 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1997 if (!*rparam) {
1998 return False;
2000 SSVAL(*rparam,0,NERR_Success);
2001 SSVAL(*rparam,2,0); /* converter word */
2002 SSVAL(*rparam,4,*rdata_len);
2003 *rdata_len = 0;
2005 return True;
2007 error_exit:
2009 *rparam_len = 4;
2010 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2011 if (!*rparam) {
2012 return False;
2014 *rdata_len = 0;
2015 SSVAL(*rparam,0,res);
2016 SSVAL(*rparam,2,0);
2017 return True;
2020 /****************************************************************************
2021 view list of groups available
2022 ****************************************************************************/
2024 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2025 char *param, int tpscnt,
2026 char *data, int tdscnt,
2027 int mdrcnt,int mprcnt,
2028 char **rdata,char **rparam,
2029 int *rdata_len,int *rparam_len)
2031 int i;
2032 int errflags=0;
2033 int resume_context, cli_buf_size;
2034 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2035 char *str2 = skip_string(param,tpscnt,str1);
2036 char *p = skip_string(param,tpscnt,str2);
2038 struct pdb_search *search;
2039 struct samr_displayentry *entries;
2041 int num_entries;
2043 if (!str1 || !str2 || !p) {
2044 return False;
2047 if (strcmp(str1,"WrLeh") != 0) {
2048 return False;
2051 /* parameters
2052 * W-> resume context (number of users to skip)
2053 * r -> return parameter pointer to receive buffer
2054 * L -> length of receive buffer
2055 * e -> return parameter number of entries
2056 * h -> return parameter total number of users
2059 if (strcmp("B21",str2) != 0) {
2060 return False;
2063 /* get list of domain groups SID_DOMAIN_GRP=2 */
2064 become_root();
2065 search = pdb_search_groups();
2066 unbecome_root();
2068 if (search == NULL) {
2069 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
2070 return False;
2073 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2074 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2075 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2076 "%d\n", resume_context, cli_buf_size));
2078 become_root();
2079 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
2080 &entries);
2081 unbecome_root();
2083 *rdata_len = cli_buf_size;
2084 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2085 if (!*rdata) {
2086 return False;
2089 p = *rdata;
2091 for(i=0; i<num_entries; i++) {
2092 fstring name;
2093 fstrcpy(name, entries[i].account_name);
2094 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
2095 /* truncate the name at 21 chars. */
2096 memcpy(p, name, 21);
2097 DEBUG(10,("adding entry %d group %s\n", i, p));
2098 p += 21;
2099 p += 5; /* Both NT4 and W2k3SP1 do padding here.
2100 No idea why... */
2101 } else {
2102 /* set overflow error */
2103 DEBUG(3,("overflow on entry %d group %s\n", i, name));
2104 errflags=234;
2105 break;
2109 pdb_search_destroy(search);
2111 *rdata_len = PTR_DIFF(p,*rdata);
2113 *rparam_len = 8;
2114 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2115 if (!*rparam) {
2116 return False;
2118 SSVAL(*rparam, 0, errflags);
2119 SSVAL(*rparam, 2, 0); /* converter word */
2120 SSVAL(*rparam, 4, i); /* is this right?? */
2121 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
2123 return(True);
2126 /*******************************************************************
2127 Get groups that a user is a member of.
2128 ******************************************************************/
2130 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2131 char *param, int tpscnt,
2132 char *data, int tdscnt,
2133 int mdrcnt,int mprcnt,
2134 char **rdata,char **rparam,
2135 int *rdata_len,int *rparam_len)
2137 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2138 char *str2 = skip_string(param,tpscnt,str1);
2139 char *UserName = skip_string(param,tpscnt,str2);
2140 char *p = skip_string(param,tpscnt,UserName);
2141 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2142 const char *level_string;
2143 int count=0;
2144 struct samu *sampw = NULL;
2145 bool ret = False;
2146 DOM_SID *sids;
2147 gid_t *gids;
2148 size_t num_groups;
2149 size_t i;
2150 NTSTATUS result;
2151 DOM_SID user_sid;
2152 enum lsa_SidType type;
2153 char *endp = NULL;
2154 TALLOC_CTX *mem_ctx;
2156 if (!str1 || !str2 || !UserName || !p) {
2157 return False;
2160 *rparam_len = 8;
2161 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2162 if (!*rparam) {
2163 return False;
2166 /* check it's a supported varient */
2168 if ( strcmp(str1,"zWrLeh") != 0 )
2169 return False;
2171 switch( uLevel ) {
2172 case 0:
2173 level_string = "B21";
2174 break;
2175 default:
2176 return False;
2179 if (strcmp(level_string,str2) != 0)
2180 return False;
2182 *rdata_len = mdrcnt + 1024;
2183 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2184 if (!*rdata) {
2185 return False;
2188 SSVAL(*rparam,0,NERR_Success);
2189 SSVAL(*rparam,2,0); /* converter word */
2191 p = *rdata;
2192 endp = *rdata + *rdata_len;
2194 mem_ctx = talloc_new(NULL);
2195 if (mem_ctx == NULL) {
2196 DEBUG(0, ("talloc_new failed\n"));
2197 return False;
2200 if ( !(sampw = samu_new(mem_ctx)) ) {
2201 DEBUG(0, ("samu_new() failed!\n"));
2202 TALLOC_FREE(mem_ctx);
2203 return False;
2206 /* Lookup the user information; This should only be one of
2207 our accounts (not remote domains) */
2209 become_root(); /* ROOT BLOCK */
2211 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2212 NULL, NULL, &user_sid, &type)) {
2213 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2214 goto done;
2217 if (type != SID_NAME_USER) {
2218 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2219 sid_type_lookup(type)));
2220 goto done;
2223 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2224 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2225 sid_string_dbg(&user_sid), UserName));
2226 goto done;
2229 gids = NULL;
2230 sids = NULL;
2231 num_groups = 0;
2233 result = pdb_enum_group_memberships(mem_ctx, sampw,
2234 &sids, &gids, &num_groups);
2236 if (!NT_STATUS_IS_OK(result)) {
2237 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2238 UserName));
2239 goto done;
2242 for (i=0; i<num_groups; i++) {
2243 const char *grp_name;
2245 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2246 strlcpy(p, grp_name, PTR_DIFF(endp,p));
2247 p += 21;
2248 count++;
2252 *rdata_len = PTR_DIFF(p,*rdata);
2254 SSVAL(*rparam,4,count); /* is this right?? */
2255 SSVAL(*rparam,6,count); /* is this right?? */
2257 ret = True;
2259 done:
2260 unbecome_root(); /* END ROOT BLOCK */
2262 TALLOC_FREE(mem_ctx);
2264 return ret;
2267 /*******************************************************************
2268 Get all users.
2269 ******************************************************************/
2271 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2272 char *param, int tpscnt,
2273 char *data, int tdscnt,
2274 int mdrcnt,int mprcnt,
2275 char **rdata,char **rparam,
2276 int *rdata_len,int *rparam_len)
2278 int count_sent=0;
2279 int num_users=0;
2280 int errflags=0;
2281 int i, resume_context, cli_buf_size;
2282 struct pdb_search *search;
2283 struct samr_displayentry *users;
2285 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2286 char *str2 = skip_string(param,tpscnt,str1);
2287 char *p = skip_string(param,tpscnt,str2);
2288 char *endp = NULL;
2290 if (!str1 || !str2 || !p) {
2291 return False;
2294 if (strcmp(str1,"WrLeh") != 0)
2295 return False;
2296 /* parameters
2297 * W-> resume context (number of users to skip)
2298 * r -> return parameter pointer to receive buffer
2299 * L -> length of receive buffer
2300 * e -> return parameter number of entries
2301 * h -> return parameter total number of users
2304 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2305 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2306 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2307 resume_context, cli_buf_size));
2309 *rparam_len = 8;
2310 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2311 if (!*rparam) {
2312 return False;
2315 /* check it's a supported varient */
2316 if (strcmp("B21",str2) != 0)
2317 return False;
2319 *rdata_len = cli_buf_size;
2320 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2321 if (!*rdata) {
2322 return False;
2325 p = *rdata;
2326 endp = *rdata + *rdata_len;
2328 become_root();
2329 search = pdb_search_users(ACB_NORMAL);
2330 unbecome_root();
2331 if (search == NULL) {
2332 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2333 return False;
2336 become_root();
2337 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2338 &users);
2339 unbecome_root();
2341 errflags=NERR_Success;
2343 for (i=0; i<num_users; i++) {
2344 const char *name = users[i].account_name;
2346 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2347 strlcpy(p,name,PTR_DIFF(endp,p));
2348 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2349 "%s\n",count_sent,p));
2350 p += 21;
2351 count_sent++;
2352 } else {
2353 /* set overflow error */
2354 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2355 "username %s\n",count_sent,name));
2356 errflags=234;
2357 break;
2361 pdb_search_destroy(search);
2363 *rdata_len = PTR_DIFF(p,*rdata);
2365 SSVAL(*rparam,0,errflags);
2366 SSVAL(*rparam,2,0); /* converter word */
2367 SSVAL(*rparam,4,count_sent); /* is this right?? */
2368 SSVAL(*rparam,6,num_users); /* is this right?? */
2370 return True;
2373 /****************************************************************************
2374 Get the time of day info.
2375 ****************************************************************************/
2377 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2378 char *param, int tpscnt,
2379 char *data, int tdscnt,
2380 int mdrcnt,int mprcnt,
2381 char **rdata,char **rparam,
2382 int *rdata_len,int *rparam_len)
2384 struct tm *t;
2385 time_t unixdate = time(NULL);
2386 char *p;
2388 *rparam_len = 4;
2389 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2390 if (!*rparam) {
2391 return False;
2394 *rdata_len = 21;
2395 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2396 if (!*rdata) {
2397 return False;
2400 SSVAL(*rparam,0,NERR_Success);
2401 SSVAL(*rparam,2,0); /* converter word */
2403 p = *rdata;
2405 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2406 by NT in a "net time" operation,
2407 it seems to ignore the one below */
2409 /* the client expects to get localtime, not GMT, in this bit
2410 (I think, this needs testing) */
2411 t = localtime(&unixdate);
2412 if (!t) {
2413 return False;
2416 SIVAL(p,4,0); /* msecs ? */
2417 SCVAL(p,8,t->tm_hour);
2418 SCVAL(p,9,t->tm_min);
2419 SCVAL(p,10,t->tm_sec);
2420 SCVAL(p,11,0); /* hundredths of seconds */
2421 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2422 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2423 SCVAL(p,16,t->tm_mday);
2424 SCVAL(p,17,t->tm_mon + 1);
2425 SSVAL(p,18,1900+t->tm_year);
2426 SCVAL(p,20,t->tm_wday);
2428 return True;
2431 /****************************************************************************
2432 Set the user password.
2433 *****************************************************************************/
2435 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2436 char *param, int tpscnt,
2437 char *data, int tdscnt,
2438 int mdrcnt,int mprcnt,
2439 char **rdata,char **rparam,
2440 int *rdata_len,int *rparam_len)
2442 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2443 char *p = NULL;
2444 fstring user;
2445 fstring pass1,pass2;
2447 /* Skip 2 strings. */
2448 p = skip_string(param,tpscnt,np);
2449 p = skip_string(param,tpscnt,p);
2451 if (!np || !p) {
2452 return False;
2455 /* Do we have a string ? */
2456 if (skip_string(param,tpscnt,p) == NULL) {
2457 return False;
2459 pull_ascii_fstring(user,p);
2461 p = skip_string(param,tpscnt,p);
2462 if (!p) {
2463 return False;
2466 memset(pass1,'\0',sizeof(pass1));
2467 memset(pass2,'\0',sizeof(pass2));
2469 * We use 31 here not 32 as we're checking
2470 * the last byte we want to access is safe.
2472 if (!is_offset_safe(param,tpscnt,p,31)) {
2473 return False;
2475 memcpy(pass1,p,16);
2476 memcpy(pass2,p+16,16);
2478 *rparam_len = 4;
2479 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2480 if (!*rparam) {
2481 return False;
2484 *rdata_len = 0;
2486 SSVAL(*rparam,0,NERR_badpass);
2487 SSVAL(*rparam,2,0); /* converter word */
2489 DEBUG(3,("Set password for <%s>\n",user));
2492 * Attempt to verify the old password against smbpasswd entries
2493 * Win98 clients send old and new password in plaintext for this call.
2497 auth_serversupplied_info *server_info = NULL;
2498 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2500 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2502 become_root();
2503 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2504 SSVAL(*rparam,0,NERR_Success);
2506 unbecome_root();
2508 TALLOC_FREE(server_info);
2510 data_blob_clear_free(&password);
2514 * If the plaintext change failed, attempt
2515 * the old encrypted method. NT will generate this
2516 * after trying the samr method. Note that this
2517 * method is done as a last resort as this
2518 * password change method loses the NT password hash
2519 * and cannot change the UNIX password as no plaintext
2520 * is received.
2523 if(SVAL(*rparam,0) != NERR_Success) {
2524 struct samu *hnd = NULL;
2526 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2527 become_root();
2528 if (change_lanman_password(hnd,(uchar *)pass2)) {
2529 SSVAL(*rparam,0,NERR_Success);
2531 unbecome_root();
2532 TALLOC_FREE(hnd);
2536 memset((char *)pass1,'\0',sizeof(fstring));
2537 memset((char *)pass2,'\0',sizeof(fstring));
2539 return(True);
2542 /****************************************************************************
2543 Set the user password (SamOEM version - gets plaintext).
2544 ****************************************************************************/
2546 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2547 char *param, int tpscnt,
2548 char *data, int tdscnt,
2549 int mdrcnt,int mprcnt,
2550 char **rdata,char **rparam,
2551 int *rdata_len,int *rparam_len)
2553 fstring user;
2554 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2555 *rparam_len = 2;
2556 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2557 if (!*rparam) {
2558 return False;
2561 if (!p) {
2562 return False;
2564 *rdata_len = 0;
2566 SSVAL(*rparam,0,NERR_badpass);
2569 * Check the parameter definition is correct.
2572 /* Do we have a string ? */
2573 if (skip_string(param,tpscnt,p) == 0) {
2574 return False;
2576 if(!strequal(p, "zsT")) {
2577 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2578 return False;
2580 p = skip_string(param, tpscnt, p);
2581 if (!p) {
2582 return False;
2585 /* Do we have a string ? */
2586 if (skip_string(param,tpscnt,p) == 0) {
2587 return False;
2589 if(!strequal(p, "B516B16")) {
2590 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2591 return False;
2593 p = skip_string(param,tpscnt,p);
2594 if (!p) {
2595 return False;
2597 /* Do we have a string ? */
2598 if (skip_string(param,tpscnt,p) == 0) {
2599 return False;
2601 p += pull_ascii_fstring(user,p);
2603 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2606 * Pass the user through the NT -> unix user mapping
2607 * function.
2610 (void)map_username(user);
2612 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2613 SSVAL(*rparam,0,NERR_Success);
2616 return(True);
2619 /****************************************************************************
2620 delete a print job
2621 Form: <W> <>
2622 ****************************************************************************/
2624 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2625 char *param, int tpscnt,
2626 char *data, int tdscnt,
2627 int mdrcnt,int mprcnt,
2628 char **rdata,char **rparam,
2629 int *rdata_len,int *rparam_len)
2631 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2632 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2633 char *str2 = skip_string(param,tpscnt,str1);
2634 char *p = skip_string(param,tpscnt,str2);
2635 uint32 jobid;
2636 int snum;
2637 fstring sharename;
2638 int errcode;
2639 WERROR werr = WERR_OK;
2641 if (!str1 || !str2 || !p) {
2642 return False;
2645 * We use 1 here not 2 as we're checking
2646 * the last byte we want to access is safe.
2648 if (!is_offset_safe(param,tpscnt,p,1)) {
2649 return False;
2651 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2652 return False;
2654 /* check it's a supported varient */
2655 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2656 return(False);
2658 *rparam_len = 4;
2659 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2660 if (!*rparam) {
2661 return False;
2663 *rdata_len = 0;
2665 if (!print_job_exists(sharename, jobid)) {
2666 errcode = NERR_JobNotFound;
2667 goto out;
2670 snum = lp_servicenumber( sharename);
2671 if (snum == -1) {
2672 errcode = NERR_DestNotFound;
2673 goto out;
2676 errcode = NERR_notsupported;
2678 switch (function) {
2679 case 81: /* delete */
2680 if (print_job_delete(&current_user, snum, jobid, &werr))
2681 errcode = NERR_Success;
2682 break;
2683 case 82: /* pause */
2684 if (print_job_pause(&current_user, snum, jobid, &werr))
2685 errcode = NERR_Success;
2686 break;
2687 case 83: /* resume */
2688 if (print_job_resume(&current_user, snum, jobid, &werr))
2689 errcode = NERR_Success;
2690 break;
2693 if (!W_ERROR_IS_OK(werr))
2694 errcode = W_ERROR_V(werr);
2696 out:
2697 SSVAL(*rparam,0,errcode);
2698 SSVAL(*rparam,2,0); /* converter word */
2700 return(True);
2703 /****************************************************************************
2704 Purge a print queue - or pause or resume it.
2705 ****************************************************************************/
2707 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2708 char *param, int tpscnt,
2709 char *data, int tdscnt,
2710 int mdrcnt,int mprcnt,
2711 char **rdata,char **rparam,
2712 int *rdata_len,int *rparam_len)
2714 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2715 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2716 char *str2 = skip_string(param,tpscnt,str1);
2717 char *QueueName = skip_string(param,tpscnt,str2);
2718 int errcode = NERR_notsupported;
2719 int snum;
2720 WERROR werr = WERR_OK;
2722 if (!str1 || !str2 || !QueueName) {
2723 return False;
2726 /* check it's a supported varient */
2727 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2728 return(False);
2730 *rparam_len = 4;
2731 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2732 if (!*rparam) {
2733 return False;
2735 *rdata_len = 0;
2737 if (skip_string(param,tpscnt,QueueName) == NULL) {
2738 return False;
2740 snum = print_queue_snum(QueueName);
2742 if (snum == -1) {
2743 errcode = NERR_JobNotFound;
2744 goto out;
2747 switch (function) {
2748 case 74: /* Pause queue */
2749 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2750 break;
2751 case 75: /* Resume queue */
2752 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2753 break;
2754 case 103: /* Purge */
2755 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2756 break;
2759 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2761 out:
2762 SSVAL(*rparam,0,errcode);
2763 SSVAL(*rparam,2,0); /* converter word */
2765 return(True);
2768 /****************************************************************************
2769 set the property of a print job (undocumented?)
2770 ? function = 0xb -> set name of print job
2771 ? function = 0x6 -> move print job up/down
2772 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2773 or <WWsTP> <WB21BB16B10zWWzDDz>
2774 ****************************************************************************/
2776 static int check_printjob_info(struct pack_desc* desc,
2777 int uLevel, char* id)
2779 desc->subformat = NULL;
2780 switch( uLevel ) {
2781 case 0: desc->format = "W"; break;
2782 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2783 case 2: desc->format = "WWzWWDDzz"; break;
2784 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2785 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2786 default:
2787 DEBUG(0,("check_printjob_info: invalid level %d\n",
2788 uLevel ));
2789 return False;
2791 if (id == NULL || strcmp(desc->format,id) != 0) {
2792 DEBUG(0,("check_printjob_info: invalid format %s\n",
2793 id ? id : "<NULL>" ));
2794 return False;
2796 return True;
2799 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2800 char *param, int tpscnt,
2801 char *data, int tdscnt,
2802 int mdrcnt,int mprcnt,
2803 char **rdata,char **rparam,
2804 int *rdata_len,int *rparam_len)
2806 struct pack_desc desc;
2807 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2808 char *str2 = skip_string(param,tpscnt,str1);
2809 char *p = skip_string(param,tpscnt,str2);
2810 uint32 jobid;
2811 fstring sharename;
2812 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2813 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2814 int place, errcode;
2816 if (!str1 || !str2 || !p) {
2817 return False;
2820 * We use 1 here not 2 as we're checking
2821 * the last byte we want to access is safe.
2823 if (!is_offset_safe(param,tpscnt,p,1)) {
2824 return False;
2826 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2827 return False;
2828 *rparam_len = 4;
2829 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2830 if (!*rparam) {
2831 return False;
2834 if (!share_defined(sharename)) {
2835 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2836 sharename));
2837 return False;
2840 *rdata_len = 0;
2842 /* check it's a supported varient */
2843 if ((strcmp(str1,"WWsTP")) ||
2844 (!check_printjob_info(&desc,uLevel,str2)))
2845 return(False);
2847 if (!print_job_exists(sharename, jobid)) {
2848 errcode=NERR_JobNotFound;
2849 goto out;
2852 errcode = NERR_notsupported;
2854 switch (function) {
2855 case 0x6:
2856 /* change job place in the queue,
2857 data gives the new place */
2858 place = SVAL(data,0);
2859 if (print_job_set_place(sharename, jobid, place)) {
2860 errcode=NERR_Success;
2862 break;
2864 case 0xb:
2865 /* change print job name, data gives the name */
2866 if (print_job_set_name(sharename, jobid, data)) {
2867 errcode=NERR_Success;
2869 break;
2871 default:
2872 return False;
2875 out:
2876 SSVALS(*rparam,0,errcode);
2877 SSVAL(*rparam,2,0); /* converter word */
2879 return(True);
2883 /****************************************************************************
2884 Get info about the server.
2885 ****************************************************************************/
2887 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
2888 char *param, int tpscnt,
2889 char *data, int tdscnt,
2890 int mdrcnt,int mprcnt,
2891 char **rdata,char **rparam,
2892 int *rdata_len,int *rparam_len)
2894 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2895 char *str2 = skip_string(param,tpscnt,str1);
2896 char *p = skip_string(param,tpscnt,str2);
2897 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2898 char *p2;
2899 int struct_len;
2901 if (!str1 || !str2 || !p) {
2902 return False;
2905 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2907 /* check it's a supported varient */
2908 if (!prefix_ok(str1,"WrLh")) {
2909 return False;
2912 switch( uLevel ) {
2913 case 0:
2914 if (strcmp(str2,"B16") != 0) {
2915 return False;
2917 struct_len = 16;
2918 break;
2919 case 1:
2920 if (strcmp(str2,"B16BBDz") != 0) {
2921 return False;
2923 struct_len = 26;
2924 break;
2925 case 2:
2926 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2927 return False;
2929 struct_len = 134;
2930 break;
2931 case 3:
2932 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2933 return False;
2935 struct_len = 144;
2936 break;
2937 case 20:
2938 if (strcmp(str2,"DN") != 0) {
2939 return False;
2941 struct_len = 6;
2942 break;
2943 case 50:
2944 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2945 return False;
2947 struct_len = 42;
2948 break;
2949 default:
2950 return False;
2953 *rdata_len = mdrcnt;
2954 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2955 if (!*rdata) {
2956 return False;
2959 p = *rdata;
2960 p2 = p + struct_len;
2961 if (uLevel != 20) {
2962 srvstr_push(NULL, 0, p,global_myname(),16,
2963 STR_ASCII|STR_UPPER|STR_TERMINATE);
2965 p += 16;
2966 if (uLevel > 0) {
2967 struct srv_info_struct *servers=NULL;
2968 int i,count;
2969 char *comment = NULL;
2970 TALLOC_CTX *ctx = talloc_tos();
2971 uint32 servertype= lp_default_server_announce();
2973 comment = talloc_strdup(ctx,lp_serverstring());
2974 if (!comment) {
2975 return false;
2978 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2979 for (i=0;i<count;i++) {
2980 if (strequal(servers[i].name,global_myname())) {
2981 servertype = servers[i].type;
2982 TALLOC_FREE(comment);
2983 comment = talloc_strdup(ctx,
2984 servers[i].comment);
2985 if (comment) {
2986 return false;
2992 SAFE_FREE(servers);
2994 SCVAL(p,0,lp_major_announce_version());
2995 SCVAL(p,1,lp_minor_announce_version());
2996 SIVAL(p,2,servertype);
2998 if (mdrcnt == struct_len) {
2999 SIVAL(p,6,0);
3000 } else {
3001 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3002 comment = talloc_sub_advanced(ctx,
3003 lp_servicename(SNUM(conn)),
3004 conn->user,
3005 conn->connectpath,
3006 conn->gid,
3007 get_current_username(),
3008 current_user_info.domain,
3009 comment);
3010 if (comment) {
3011 return false;
3013 if (mdrcnt - struct_len <= 0) {
3014 return false;
3016 push_ascii(p2,
3017 comment,
3018 MIN(mdrcnt - struct_len,
3019 MAX_SERVER_STRING_LENGTH),
3020 STR_TERMINATE);
3021 p2 = skip_string(*rdata,*rdata_len,p2);
3022 if (!p2) {
3023 return False;
3028 if (uLevel > 1) {
3029 return False; /* not yet implemented */
3032 *rdata_len = PTR_DIFF(p2,*rdata);
3034 *rparam_len = 6;
3035 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3036 if (!*rparam) {
3037 return False;
3039 SSVAL(*rparam,0,NERR_Success);
3040 SSVAL(*rparam,2,0); /* converter word */
3041 SSVAL(*rparam,4,*rdata_len);
3043 return True;
3046 /****************************************************************************
3047 Get info about the server.
3048 ****************************************************************************/
3050 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3051 char *param, int tpscnt,
3052 char *data, int tdscnt,
3053 int mdrcnt,int mprcnt,
3054 char **rdata,char **rparam,
3055 int *rdata_len,int *rparam_len)
3057 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3058 char *str2 = skip_string(param,tpscnt,str1);
3059 char *p = skip_string(param,tpscnt,str2);
3060 char *p2;
3061 char *endp;
3062 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3064 if (!str1 || !str2 || !p) {
3065 return False;
3068 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3070 *rparam_len = 6;
3071 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3072 if (!*rparam) {
3073 return False;
3076 /* check it's a supported varient */
3077 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3078 return False;
3081 *rdata_len = mdrcnt + 1024;
3082 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3083 if (!*rdata) {
3084 return False;
3087 SSVAL(*rparam,0,NERR_Success);
3088 SSVAL(*rparam,2,0); /* converter word */
3090 p = *rdata;
3091 endp = *rdata + *rdata_len;
3093 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3094 if (!p2) {
3095 return False;
3098 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3099 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3100 strupper_m(p2);
3101 p2 = skip_string(*rdata,*rdata_len,p2);
3102 if (!p2) {
3103 return False;
3105 p += 4;
3107 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3108 strlcpy(p2,current_user_info.smb_name,PTR_DIFF(endp,p2));
3109 p2 = skip_string(*rdata,*rdata_len,p2);
3110 if (!p2) {
3111 return False;
3113 p += 4;
3115 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3116 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3117 strupper_m(p2);
3118 p2 = skip_string(*rdata,*rdata_len,p2);
3119 if (!p2) {
3120 return False;
3122 p += 4;
3124 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3125 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3126 p += 2;
3128 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3129 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3130 p2 = skip_string(*rdata,*rdata_len,p2);
3131 if (!p2) {
3132 return False;
3134 p += 4;
3136 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3137 strlcpy(p2,"",PTR_DIFF(endp,p2));
3138 p2 = skip_string(*rdata,*rdata_len,p2);
3139 if (!p2) {
3140 return False;
3142 p += 4;
3144 *rdata_len = PTR_DIFF(p2,*rdata);
3146 SSVAL(*rparam,4,*rdata_len);
3148 return True;
3151 /****************************************************************************
3152 get info about a user
3154 struct user_info_11 {
3155 char usri11_name[21]; 0-20
3156 char usri11_pad; 21
3157 char *usri11_comment; 22-25
3158 char *usri11_usr_comment; 26-29
3159 unsigned short usri11_priv; 30-31
3160 unsigned long usri11_auth_flags; 32-35
3161 long usri11_password_age; 36-39
3162 char *usri11_homedir; 40-43
3163 char *usri11_parms; 44-47
3164 long usri11_last_logon; 48-51
3165 long usri11_last_logoff; 52-55
3166 unsigned short usri11_bad_pw_count; 56-57
3167 unsigned short usri11_num_logons; 58-59
3168 char *usri11_logon_server; 60-63
3169 unsigned short usri11_country_code; 64-65
3170 char *usri11_workstations; 66-69
3171 unsigned long usri11_max_storage; 70-73
3172 unsigned short usri11_units_per_week; 74-75
3173 unsigned char *usri11_logon_hours; 76-79
3174 unsigned short usri11_code_page; 80-81
3177 where:
3179 usri11_name specifies the user name for which information is retrieved
3181 usri11_pad aligns the next data structure element to a word boundary
3183 usri11_comment is a null terminated ASCII comment
3185 usri11_user_comment is a null terminated ASCII comment about the user
3187 usri11_priv specifies the level of the privilege assigned to the user.
3188 The possible values are:
3190 Name Value Description
3191 USER_PRIV_GUEST 0 Guest privilege
3192 USER_PRIV_USER 1 User privilege
3193 USER_PRV_ADMIN 2 Administrator privilege
3195 usri11_auth_flags specifies the account operator privileges. The
3196 possible values are:
3198 Name Value Description
3199 AF_OP_PRINT 0 Print operator
3202 Leach, Naik [Page 28]
3206 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3209 AF_OP_COMM 1 Communications operator
3210 AF_OP_SERVER 2 Server operator
3211 AF_OP_ACCOUNTS 3 Accounts operator
3214 usri11_password_age specifies how many seconds have elapsed since the
3215 password was last changed.
3217 usri11_home_dir points to a null terminated ASCII string that contains
3218 the path name of the user's home directory.
3220 usri11_parms points to a null terminated ASCII string that is set
3221 aside for use by applications.
3223 usri11_last_logon specifies the time when the user last logged on.
3224 This value is stored as the number of seconds elapsed since
3225 00:00:00, January 1, 1970.
3227 usri11_last_logoff specifies the time when the user last logged off.
3228 This value is stored as the number of seconds elapsed since
3229 00:00:00, January 1, 1970. A value of 0 means the last logoff
3230 time is unknown.
3232 usri11_bad_pw_count specifies the number of incorrect passwords
3233 entered since the last successful logon.
3235 usri11_log1_num_logons specifies the number of times this user has
3236 logged on. A value of -1 means the number of logons is unknown.
3238 usri11_logon_server points to a null terminated ASCII string that
3239 contains the name of the server to which logon requests are sent.
3240 A null string indicates logon requests should be sent to the
3241 domain controller.
3243 usri11_country_code specifies the country code for the user's language
3244 of choice.
3246 usri11_workstations points to a null terminated ASCII string that
3247 contains the names of workstations the user may log on from.
3248 There may be up to 8 workstations, with the names separated by
3249 commas. A null strings indicates there are no restrictions.
3251 usri11_max_storage specifies the maximum amount of disk space the user
3252 can occupy. A value of 0xffffffff indicates there are no
3253 restrictions.
3255 usri11_units_per_week specifies the equal number of time units into
3256 which a week is divided. This value must be equal to 168.
3258 usri11_logon_hours points to a 21 byte (168 bits) string that
3259 specifies the time during which the user can log on. Each bit
3260 represents one unique hour in a week. The first bit (bit 0, word
3261 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3265 Leach, Naik [Page 29]
3269 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3272 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3273 are no restrictions.
3275 usri11_code_page specifies the code page for the user's language of
3276 choice
3278 All of the pointers in this data structure need to be treated
3279 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3280 to be ignored. The converter word returned in the parameters section
3281 needs to be subtracted from the lower 16 bits to calculate an offset
3282 into the return buffer where this ASCII string resides.
3284 There is no auxiliary data in the response.
3286 ****************************************************************************/
3288 #define usri11_name 0
3289 #define usri11_pad 21
3290 #define usri11_comment 22
3291 #define usri11_usr_comment 26
3292 #define usri11_full_name 30
3293 #define usri11_priv 34
3294 #define usri11_auth_flags 36
3295 #define usri11_password_age 40
3296 #define usri11_homedir 44
3297 #define usri11_parms 48
3298 #define usri11_last_logon 52
3299 #define usri11_last_logoff 56
3300 #define usri11_bad_pw_count 60
3301 #define usri11_num_logons 62
3302 #define usri11_logon_server 64
3303 #define usri11_country_code 68
3304 #define usri11_workstations 70
3305 #define usri11_max_storage 74
3306 #define usri11_units_per_week 78
3307 #define usri11_logon_hours 80
3308 #define usri11_code_page 84
3309 #define usri11_end 86
3311 #define USER_PRIV_GUEST 0
3312 #define USER_PRIV_USER 1
3313 #define USER_PRIV_ADMIN 2
3315 #define AF_OP_PRINT 0
3316 #define AF_OP_COMM 1
3317 #define AF_OP_SERVER 2
3318 #define AF_OP_ACCOUNTS 3
3321 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3322 char *param, int tpscnt,
3323 char *data, int tdscnt,
3324 int mdrcnt,int mprcnt,
3325 char **rdata,char **rparam,
3326 int *rdata_len,int *rparam_len)
3328 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3329 char *str2 = skip_string(param,tpscnt,str1);
3330 char *UserName = skip_string(param,tpscnt,str2);
3331 char *p = skip_string(param,tpscnt,UserName);
3332 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3333 char *p2;
3334 char *endp;
3335 const char *level_string;
3337 /* get NIS home of a previously validated user - simeon */
3338 /* With share level security vuid will always be zero.
3339 Don't depend on vuser being non-null !!. JRA */
3340 user_struct *vuser = get_valid_user_struct(vuid);
3341 if(vuser != NULL) {
3342 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3343 vuser->user.unix_name));
3346 if (!str1 || !str2 || !UserName || !p) {
3347 return False;
3350 *rparam_len = 6;
3351 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3352 if (!*rparam) {
3353 return False;
3356 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3358 /* check it's a supported variant */
3359 if (strcmp(str1,"zWrLh") != 0) {
3360 return False;
3362 switch( uLevel ) {
3363 case 0: level_string = "B21"; break;
3364 case 1: level_string = "B21BB16DWzzWz"; break;
3365 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3366 case 10: level_string = "B21Bzzz"; break;
3367 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3368 default: return False;
3371 if (strcmp(level_string,str2) != 0) {
3372 return False;
3375 *rdata_len = mdrcnt + 1024;
3376 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3377 if (!*rdata) {
3378 return False;
3381 SSVAL(*rparam,0,NERR_Success);
3382 SSVAL(*rparam,2,0); /* converter word */
3384 p = *rdata;
3385 endp = *rdata + *rdata_len;
3386 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3387 if (!p2) {
3388 return False;
3391 memset(p,0,21);
3392 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3394 if (uLevel > 0) {
3395 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3396 *p2 = 0;
3399 if (uLevel >= 10) {
3400 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3401 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3402 p2 = skip_string(*rdata,*rdata_len,p2);
3403 if (!p2) {
3404 return False;
3407 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3408 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3409 p2 = skip_string(*rdata,*rdata_len,p2);
3410 if (!p2) {
3411 return False;
3414 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3415 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3416 strlcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName),PTR_DIFF(endp,p2));
3417 p2 = skip_string(*rdata,*rdata_len,p2);
3418 if (!p2) {
3419 return False;
3423 if (uLevel == 11) {
3424 /* modelled after NTAS 3.51 reply */
3425 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3426 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3427 SIVALS(p,usri11_password_age,-1); /* password age */
3428 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3429 strlcpy(p2, vuser && vuser->homedir ? vuser->homedir : "",PTR_DIFF(endp,p2));
3430 p2 = skip_string(*rdata,*rdata_len,p2);
3431 if (!p2) {
3432 return False;
3434 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3435 strlcpy(p2,"",PTR_DIFF(endp,p2));
3436 p2 = skip_string(*rdata,*rdata_len,p2);
3437 if (!p2) {
3438 return False;
3440 SIVAL(p,usri11_last_logon,0); /* last logon */
3441 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3442 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3443 SSVALS(p,usri11_num_logons,-1); /* num logons */
3444 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3445 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3446 p2 = skip_string(*rdata,*rdata_len,p2);
3447 if (!p2) {
3448 return False;
3450 SSVAL(p,usri11_country_code,0); /* country code */
3452 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3453 strlcpy(p2,"",PTR_DIFF(endp,p2));
3454 p2 = skip_string(*rdata,*rdata_len,p2);
3455 if (!p2) {
3456 return False;
3459 SIVALS(p,usri11_max_storage,-1); /* max storage */
3460 SSVAL(p,usri11_units_per_week,168); /* units per week */
3461 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3463 /* a simple way to get logon hours at all times. */
3464 memset(p2,0xff,21);
3465 SCVAL(p2,21,0); /* fix zero termination */
3466 p2 = skip_string(*rdata,*rdata_len,p2);
3467 if (!p2) {
3468 return False;
3471 SSVAL(p,usri11_code_page,0); /* code page */
3474 if (uLevel == 1 || uLevel == 2) {
3475 memset(p+22,' ',16); /* password */
3476 SIVALS(p,38,-1); /* password age */
3477 SSVAL(p,42,
3478 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3479 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3480 strlcpy(p2, vuser && vuser->homedir ? vuser->homedir : "",PTR_DIFF(endp,p2));
3481 p2 = skip_string(*rdata,*rdata_len,p2);
3482 if (!p2) {
3483 return False;
3485 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3486 *p2++ = 0;
3487 SSVAL(p,52,0); /* flags */
3488 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3489 strlcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "",PTR_DIFF(endp,p2));
3490 p2 = skip_string(*rdata,*rdata_len,p2);
3491 if (!p2) {
3492 return False;
3494 if (uLevel == 2) {
3495 SIVAL(p,60,0); /* auth_flags */
3496 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3497 strlcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName),PTR_DIFF(endp,p2));
3498 p2 = skip_string(*rdata,*rdata_len,p2);
3499 if (!p2) {
3500 return False;
3502 SIVAL(p,68,0); /* urs_comment */
3503 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3504 strlcpy(p2,"",PTR_DIFF(endp,p2));
3505 p2 = skip_string(*rdata,*rdata_len,p2);
3506 if (!p2) {
3507 return False;
3509 SIVAL(p,76,0); /* workstations */
3510 SIVAL(p,80,0); /* last_logon */
3511 SIVAL(p,84,0); /* last_logoff */
3512 SIVALS(p,88,-1); /* acct_expires */
3513 SIVALS(p,92,-1); /* max_storage */
3514 SSVAL(p,96,168); /* units_per_week */
3515 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3516 memset(p2,-1,21);
3517 p2 += 21;
3518 SSVALS(p,102,-1); /* bad_pw_count */
3519 SSVALS(p,104,-1); /* num_logons */
3520 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3522 TALLOC_CTX *ctx = talloc_tos();
3523 int space_rem = *rdata_len - (p2 - *rdata);
3524 char *tmp;
3526 if (space_rem <= 0) {
3527 return false;
3529 tmp = talloc_strdup(ctx, "\\\\%L");
3530 if (!tmp) {
3531 return false;
3533 tmp = talloc_sub_basic(ctx,
3536 tmp);
3537 if (!tmp) {
3538 return false;
3541 push_ascii(p2,
3542 tmp,
3543 space_rem,
3544 STR_TERMINATE);
3546 p2 = skip_string(*rdata,*rdata_len,p2);
3547 if (!p2) {
3548 return False;
3550 SSVAL(p,110,49); /* country_code */
3551 SSVAL(p,112,860); /* code page */
3555 *rdata_len = PTR_DIFF(p2,*rdata);
3557 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3559 return(True);
3562 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3563 char *param, int tpscnt,
3564 char *data, int tdscnt,
3565 int mdrcnt,int mprcnt,
3566 char **rdata,char **rparam,
3567 int *rdata_len,int *rparam_len)
3569 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3570 char *str2 = skip_string(param,tpscnt,str1);
3571 char *p = skip_string(param,tpscnt,str2);
3572 int uLevel;
3573 struct pack_desc desc;
3574 char* name;
3575 /* With share level security vuid will always be zero.
3576 Don't depend on vuser being non-null !!. JRA */
3577 user_struct *vuser = get_valid_user_struct(vuid);
3579 if (!str1 || !str2 || !p) {
3580 return False;
3583 if(vuser != NULL) {
3584 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3585 vuser->user.unix_name));
3588 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3589 name = get_safe_str_ptr(param,tpscnt,p,2);
3590 if (!name) {
3591 return False;
3594 memset((char *)&desc,'\0',sizeof(desc));
3596 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3598 /* check it's a supported varient */
3599 if (strcmp(str1,"OOWb54WrLh") != 0) {
3600 return False;
3602 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3603 return False;
3605 if (mdrcnt > 0) {
3606 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3607 if (!*rdata) {
3608 return False;
3612 desc.base = *rdata;
3613 desc.buflen = mdrcnt;
3614 desc.subformat = NULL;
3615 desc.format = str2;
3617 if (init_package(&desc,1,0)) {
3618 PACKI(&desc,"W",0); /* code */
3619 PACKS(&desc,"B21",name); /* eff. name */
3620 PACKS(&desc,"B",""); /* pad */
3621 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3622 PACKI(&desc,"D",0); /* auth flags XXX */
3623 PACKI(&desc,"W",0); /* num logons */
3624 PACKI(&desc,"W",0); /* bad pw count */
3625 PACKI(&desc,"D",0); /* last logon */
3626 PACKI(&desc,"D",-1); /* last logoff */
3627 PACKI(&desc,"D",-1); /* logoff time */
3628 PACKI(&desc,"D",-1); /* kickoff time */
3629 PACKI(&desc,"D",0); /* password age */
3630 PACKI(&desc,"D",0); /* password can change */
3631 PACKI(&desc,"D",-1); /* password must change */
3634 fstring mypath;
3635 fstrcpy(mypath,"\\\\");
3636 fstrcat(mypath,get_local_machine_name());
3637 strupper_m(mypath);
3638 PACKS(&desc,"z",mypath); /* computer */
3641 PACKS(&desc,"z",lp_workgroup());/* domain */
3642 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3643 PACKI(&desc,"D",0x00000000); /* reserved */
3646 *rdata_len = desc.usedlen;
3647 *rparam_len = 6;
3648 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3649 if (!*rparam) {
3650 return False;
3652 SSVALS(*rparam,0,desc.errcode);
3653 SSVAL(*rparam,2,0);
3654 SSVAL(*rparam,4,desc.neededlen);
3656 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3658 return True;
3661 /****************************************************************************
3662 api_WAccessGetUserPerms
3663 ****************************************************************************/
3665 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3666 char *param, int tpscnt,
3667 char *data, int tdscnt,
3668 int mdrcnt,int mprcnt,
3669 char **rdata,char **rparam,
3670 int *rdata_len,int *rparam_len)
3672 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3673 char *str2 = skip_string(param,tpscnt,str1);
3674 char *user = skip_string(param,tpscnt,str2);
3675 char *resource = skip_string(param,tpscnt,user);
3677 if (!str1 || !str2 || !user || !resource) {
3678 return False;
3681 if (skip_string(param,tpscnt,resource) == NULL) {
3682 return False;
3684 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3686 /* check it's a supported varient */
3687 if (strcmp(str1,"zzh") != 0) {
3688 return False;
3690 if (strcmp(str2,"") != 0) {
3691 return False;
3694 *rparam_len = 6;
3695 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3696 if (!*rparam) {
3697 return False;
3699 SSVALS(*rparam,0,0); /* errorcode */
3700 SSVAL(*rparam,2,0); /* converter word */
3701 SSVAL(*rparam,4,0x7f); /* permission flags */
3703 return True;
3706 /****************************************************************************
3707 api_WPrintJobEnumerate
3708 ****************************************************************************/
3710 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3711 char *param, int tpscnt,
3712 char *data, int tdscnt,
3713 int mdrcnt,int mprcnt,
3714 char **rdata,char **rparam,
3715 int *rdata_len,int *rparam_len)
3717 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3718 char *str2 = skip_string(param,tpscnt,str1);
3719 char *p = skip_string(param,tpscnt,str2);
3720 int uLevel;
3721 int count;
3722 int i;
3723 int snum;
3724 fstring sharename;
3725 uint32 jobid;
3726 struct pack_desc desc;
3727 print_queue_struct *queue=NULL;
3728 print_status_struct status;
3729 char *tmpdata=NULL;
3731 if (!str1 || !str2 || !p) {
3732 return False;
3735 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3737 memset((char *)&desc,'\0',sizeof(desc));
3738 memset((char *)&status,'\0',sizeof(status));
3740 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3742 /* check it's a supported varient */
3743 if (strcmp(str1,"WWrLh") != 0) {
3744 return False;
3746 if (!check_printjob_info(&desc,uLevel,str2)) {
3747 return False;
3750 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3751 return False;
3754 snum = lp_servicenumber( sharename);
3755 if (snum < 0 || !VALID_SNUM(snum)) {
3756 return(False);
3759 count = print_queue_status(snum,&queue,&status);
3760 for (i = 0; i < count; i++) {
3761 if (queue[i].job == jobid) {
3762 break;
3766 if (mdrcnt > 0) {
3767 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3768 if (!*rdata) {
3769 return False;
3771 desc.base = *rdata;
3772 desc.buflen = mdrcnt;
3773 } else {
3775 * Don't return data but need to get correct length
3776 * init_package will return wrong size if buflen=0
3778 desc.buflen = getlen(desc.format);
3779 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3782 if (init_package(&desc,1,0)) {
3783 if (i < count) {
3784 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3785 *rdata_len = desc.usedlen;
3786 } else {
3787 desc.errcode = NERR_JobNotFound;
3788 *rdata_len = 0;
3792 *rparam_len = 6;
3793 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3794 if (!*rparam) {
3795 return False;
3797 SSVALS(*rparam,0,desc.errcode);
3798 SSVAL(*rparam,2,0);
3799 SSVAL(*rparam,4,desc.neededlen);
3801 SAFE_FREE(queue);
3802 SAFE_FREE(tmpdata);
3804 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3806 return True;
3809 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3810 char *param, int tpscnt,
3811 char *data, int tdscnt,
3812 int mdrcnt,int mprcnt,
3813 char **rdata,char **rparam,
3814 int *rdata_len,int *rparam_len)
3816 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3817 char *str2 = skip_string(param,tpscnt,str1);
3818 char *p = skip_string(param,tpscnt,str2);
3819 char *name = p;
3820 int uLevel;
3821 int count;
3822 int i, succnt=0;
3823 int snum;
3824 struct pack_desc desc;
3825 print_queue_struct *queue=NULL;
3826 print_status_struct status;
3828 if (!str1 || !str2 || !p) {
3829 return False;
3832 memset((char *)&desc,'\0',sizeof(desc));
3833 memset((char *)&status,'\0',sizeof(status));
3835 p = skip_string(param,tpscnt,p);
3836 if (!p) {
3837 return False;
3839 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3841 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3843 /* check it's a supported variant */
3844 if (strcmp(str1,"zWrLeh") != 0) {
3845 return False;
3848 if (uLevel > 2) {
3849 return False; /* defined only for uLevel 0,1,2 */
3852 if (!check_printjob_info(&desc,uLevel,str2)) {
3853 return False;
3856 snum = find_service(name);
3857 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3858 return False;
3861 count = print_queue_status(snum,&queue,&status);
3862 if (mdrcnt > 0) {
3863 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3864 if (!*rdata) {
3865 return False;
3868 desc.base = *rdata;
3869 desc.buflen = mdrcnt;
3871 if (init_package(&desc,count,0)) {
3872 succnt = 0;
3873 for (i = 0; i < count; i++) {
3874 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3875 if (desc.errcode == NERR_Success) {
3876 succnt = i+1;
3881 *rdata_len = desc.usedlen;
3883 *rparam_len = 8;
3884 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3885 if (!*rparam) {
3886 return False;
3888 SSVALS(*rparam,0,desc.errcode);
3889 SSVAL(*rparam,2,0);
3890 SSVAL(*rparam,4,succnt);
3891 SSVAL(*rparam,6,count);
3893 SAFE_FREE(queue);
3895 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3897 return True;
3900 static int check_printdest_info(struct pack_desc* desc,
3901 int uLevel, char* id)
3903 desc->subformat = NULL;
3904 switch( uLevel ) {
3905 case 0:
3906 desc->format = "B9";
3907 break;
3908 case 1:
3909 desc->format = "B9B21WWzW";
3910 break;
3911 case 2:
3912 desc->format = "z";
3913 break;
3914 case 3:
3915 desc->format = "zzzWWzzzWW";
3916 break;
3917 default:
3918 DEBUG(0,("check_printdest_info: invalid level %d\n",
3919 uLevel));
3920 return False;
3922 if (id == NULL || strcmp(desc->format,id) != 0) {
3923 DEBUG(0,("check_printdest_info: invalid string %s\n",
3924 id ? id : "<NULL>" ));
3925 return False;
3927 return True;
3930 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3931 struct pack_desc* desc)
3933 char buf[100];
3935 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3936 buf[sizeof(buf)-1] = 0;
3937 strupper_m(buf);
3939 if (uLevel <= 1) {
3940 PACKS(desc,"B9",buf); /* szName */
3941 if (uLevel == 1) {
3942 PACKS(desc,"B21",""); /* szUserName */
3943 PACKI(desc,"W",0); /* uJobId */
3944 PACKI(desc,"W",0); /* fsStatus */
3945 PACKS(desc,"z",""); /* pszStatus */
3946 PACKI(desc,"W",0); /* time */
3950 if (uLevel == 2 || uLevel == 3) {
3951 PACKS(desc,"z",buf); /* pszPrinterName */
3952 if (uLevel == 3) {
3953 PACKS(desc,"z",""); /* pszUserName */
3954 PACKS(desc,"z",""); /* pszLogAddr */
3955 PACKI(desc,"W",0); /* uJobId */
3956 PACKI(desc,"W",0); /* fsStatus */
3957 PACKS(desc,"z",""); /* pszStatus */
3958 PACKS(desc,"z",""); /* pszComment */
3959 PACKS(desc,"z","NULL"); /* pszDrivers */
3960 PACKI(desc,"W",0); /* time */
3961 PACKI(desc,"W",0); /* pad1 */
3966 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
3967 char *param, int tpscnt,
3968 char *data, int tdscnt,
3969 int mdrcnt,int mprcnt,
3970 char **rdata,char **rparam,
3971 int *rdata_len,int *rparam_len)
3973 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3974 char *str2 = skip_string(param,tpscnt,str1);
3975 char *p = skip_string(param,tpscnt,str2);
3976 char* PrinterName = p;
3977 int uLevel;
3978 struct pack_desc desc;
3979 int snum;
3980 char *tmpdata=NULL;
3982 if (!str1 || !str2 || !p) {
3983 return False;
3986 memset((char *)&desc,'\0',sizeof(desc));
3988 p = skip_string(param,tpscnt,p);
3989 if (!p) {
3990 return False;
3992 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3994 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3996 /* check it's a supported varient */
3997 if (strcmp(str1,"zWrLh") != 0) {
3998 return False;
4000 if (!check_printdest_info(&desc,uLevel,str2)) {
4001 return False;
4004 snum = find_service(PrinterName);
4005 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4006 *rdata_len = 0;
4007 desc.errcode = NERR_DestNotFound;
4008 desc.neededlen = 0;
4009 } else {
4010 if (mdrcnt > 0) {
4011 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4012 if (!*rdata) {
4013 return False;
4015 desc.base = *rdata;
4016 desc.buflen = mdrcnt;
4017 } else {
4019 * Don't return data but need to get correct length
4020 * init_package will return wrong size if buflen=0
4022 desc.buflen = getlen(desc.format);
4023 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4025 if (init_package(&desc,1,0)) {
4026 fill_printdest_info(conn,snum,uLevel,&desc);
4028 *rdata_len = desc.usedlen;
4031 *rparam_len = 6;
4032 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4033 if (!*rparam) {
4034 return False;
4036 SSVALS(*rparam,0,desc.errcode);
4037 SSVAL(*rparam,2,0);
4038 SSVAL(*rparam,4,desc.neededlen);
4040 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4041 SAFE_FREE(tmpdata);
4043 return True;
4046 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4047 char *param, int tpscnt,
4048 char *data, int tdscnt,
4049 int mdrcnt,int mprcnt,
4050 char **rdata,char **rparam,
4051 int *rdata_len,int *rparam_len)
4053 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4054 char *str2 = skip_string(param,tpscnt,str1);
4055 char *p = skip_string(param,tpscnt,str2);
4056 int uLevel;
4057 int queuecnt;
4058 int i, n, succnt=0;
4059 struct pack_desc desc;
4060 int services = lp_numservices();
4062 if (!str1 || !str2 || !p) {
4063 return False;
4066 memset((char *)&desc,'\0',sizeof(desc));
4068 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4070 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4072 /* check it's a supported varient */
4073 if (strcmp(str1,"WrLeh") != 0) {
4074 return False;
4076 if (!check_printdest_info(&desc,uLevel,str2)) {
4077 return False;
4080 queuecnt = 0;
4081 for (i = 0; i < services; i++) {
4082 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4083 queuecnt++;
4087 if (mdrcnt > 0) {
4088 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4089 if (!*rdata) {
4090 return False;
4094 desc.base = *rdata;
4095 desc.buflen = mdrcnt;
4096 if (init_package(&desc,queuecnt,0)) {
4097 succnt = 0;
4098 n = 0;
4099 for (i = 0; i < services; i++) {
4100 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4101 fill_printdest_info(conn,i,uLevel,&desc);
4102 n++;
4103 if (desc.errcode == NERR_Success) {
4104 succnt = n;
4110 *rdata_len = desc.usedlen;
4112 *rparam_len = 8;
4113 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4114 if (!*rparam) {
4115 return False;
4117 SSVALS(*rparam,0,desc.errcode);
4118 SSVAL(*rparam,2,0);
4119 SSVAL(*rparam,4,succnt);
4120 SSVAL(*rparam,6,queuecnt);
4122 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4124 return True;
4127 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4128 char *param, int tpscnt,
4129 char *data, int tdscnt,
4130 int mdrcnt,int mprcnt,
4131 char **rdata,char **rparam,
4132 int *rdata_len,int *rparam_len)
4134 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4135 char *str2 = skip_string(param,tpscnt,str1);
4136 char *p = skip_string(param,tpscnt,str2);
4137 int uLevel;
4138 int succnt;
4139 struct pack_desc desc;
4141 if (!str1 || !str2 || !p) {
4142 return False;
4145 memset((char *)&desc,'\0',sizeof(desc));
4147 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4149 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4151 /* check it's a supported varient */
4152 if (strcmp(str1,"WrLeh") != 0) {
4153 return False;
4155 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4156 return False;
4159 if (mdrcnt > 0) {
4160 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4161 if (!*rdata) {
4162 return False;
4165 desc.base = *rdata;
4166 desc.buflen = mdrcnt;
4167 if (init_package(&desc,1,0)) {
4168 PACKS(&desc,"B41","NULL");
4171 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4173 *rdata_len = desc.usedlen;
4175 *rparam_len = 8;
4176 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4177 if (!*rparam) {
4178 return False;
4180 SSVALS(*rparam,0,desc.errcode);
4181 SSVAL(*rparam,2,0);
4182 SSVAL(*rparam,4,succnt);
4183 SSVAL(*rparam,6,1);
4185 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4187 return True;
4190 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4191 char *param, int tpscnt,
4192 char *data, int tdscnt,
4193 int mdrcnt,int mprcnt,
4194 char **rdata,char **rparam,
4195 int *rdata_len,int *rparam_len)
4197 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4198 char *str2 = skip_string(param,tpscnt,str1);
4199 char *p = skip_string(param,tpscnt,str2);
4200 int uLevel;
4201 int succnt;
4202 struct pack_desc desc;
4204 if (!str1 || !str2 || !p) {
4205 return False;
4207 memset((char *)&desc,'\0',sizeof(desc));
4209 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4211 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4213 /* check it's a supported varient */
4214 if (strcmp(str1,"WrLeh") != 0) {
4215 return False;
4217 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4218 return False;
4221 if (mdrcnt > 0) {
4222 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4223 if (!*rdata) {
4224 return False;
4227 desc.base = *rdata;
4228 desc.buflen = mdrcnt;
4229 desc.format = str2;
4230 if (init_package(&desc,1,0)) {
4231 PACKS(&desc,"B13","lpd");
4234 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4236 *rdata_len = desc.usedlen;
4238 *rparam_len = 8;
4239 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4240 if (!*rparam) {
4241 return False;
4243 SSVALS(*rparam,0,desc.errcode);
4244 SSVAL(*rparam,2,0);
4245 SSVAL(*rparam,4,succnt);
4246 SSVAL(*rparam,6,1);
4248 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4250 return True;
4253 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4254 char *param, int tpscnt,
4255 char *data, int tdscnt,
4256 int mdrcnt,int mprcnt,
4257 char **rdata,char **rparam,
4258 int *rdata_len,int *rparam_len)
4260 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4261 char *str2 = skip_string(param,tpscnt,str1);
4262 char *p = skip_string(param,tpscnt,str2);
4263 int uLevel;
4264 int succnt;
4265 struct pack_desc desc;
4267 if (!str1 || !str2 || !p) {
4268 return False;
4271 memset((char *)&desc,'\0',sizeof(desc));
4273 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4275 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4277 /* check it's a supported varient */
4278 if (strcmp(str1,"WrLeh") != 0) {
4279 return False;
4281 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4282 return False;
4285 if (mdrcnt > 0) {
4286 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4287 if (!*rdata) {
4288 return False;
4291 memset((char *)&desc,'\0',sizeof(desc));
4292 desc.base = *rdata;
4293 desc.buflen = mdrcnt;
4294 desc.format = str2;
4295 if (init_package(&desc,1,0)) {
4296 PACKS(&desc,"B13","lp0");
4299 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4301 *rdata_len = desc.usedlen;
4303 *rparam_len = 8;
4304 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4305 if (!*rparam) {
4306 return False;
4308 SSVALS(*rparam,0,desc.errcode);
4309 SSVAL(*rparam,2,0);
4310 SSVAL(*rparam,4,succnt);
4311 SSVAL(*rparam,6,1);
4313 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4315 return True;
4318 /****************************************************************************
4319 List open sessions
4320 ****************************************************************************/
4322 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4323 char *param, int tpscnt,
4324 char *data, int tdscnt,
4325 int mdrcnt,int mprcnt,
4326 char **rdata,char **rparam,
4327 int *rdata_len,int *rparam_len)
4330 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4331 char *str2 = skip_string(param,tpscnt,str1);
4332 char *p = skip_string(param,tpscnt,str2);
4333 int uLevel;
4334 struct pack_desc desc;
4335 struct sessionid *session_list;
4336 int i, num_sessions;
4338 if (!str1 || !str2 || !p) {
4339 return False;
4342 memset((char *)&desc,'\0',sizeof(desc));
4344 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4346 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4347 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4348 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4350 /* check it's a supported varient */
4351 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4352 return False;
4354 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4355 return False;
4358 num_sessions = list_sessions(talloc_tos(), &session_list);
4360 if (mdrcnt > 0) {
4361 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4362 if (!*rdata) {
4363 return False;
4366 memset((char *)&desc,'\0',sizeof(desc));
4367 desc.base = *rdata;
4368 desc.buflen = mdrcnt;
4369 desc.format = str2;
4370 if (!init_package(&desc,num_sessions,0)) {
4371 return False;
4374 for(i=0; i<num_sessions; i++) {
4375 PACKS(&desc, "z", session_list[i].remote_machine);
4376 PACKS(&desc, "z", session_list[i].username);
4377 PACKI(&desc, "W", 1); /* num conns */
4378 PACKI(&desc, "W", 0); /* num opens */
4379 PACKI(&desc, "W", 1); /* num users */
4380 PACKI(&desc, "D", 0); /* session time */
4381 PACKI(&desc, "D", 0); /* idle time */
4382 PACKI(&desc, "D", 0); /* flags */
4383 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4386 *rdata_len = desc.usedlen;
4388 *rparam_len = 8;
4389 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4390 if (!*rparam) {
4391 return False;
4393 SSVALS(*rparam,0,desc.errcode);
4394 SSVAL(*rparam,2,0); /* converter */
4395 SSVAL(*rparam,4,num_sessions); /* count */
4397 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4399 return True;
4403 /****************************************************************************
4404 The buffer was too small.
4405 ****************************************************************************/
4407 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4408 int mdrcnt, int mprcnt,
4409 char **rdata, char **rparam,
4410 int *rdata_len, int *rparam_len)
4412 *rparam_len = MIN(*rparam_len,mprcnt);
4413 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4414 if (!*rparam) {
4415 return False;
4418 *rdata_len = 0;
4420 SSVAL(*rparam,0,NERR_BufTooSmall);
4422 DEBUG(3,("Supplied buffer too small in API command\n"));
4424 return True;
4427 /****************************************************************************
4428 The request is not supported.
4429 ****************************************************************************/
4431 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4432 char *param, int tpscnt,
4433 char *data, int tdscnt,
4434 int mdrcnt, int mprcnt,
4435 char **rdata, char **rparam,
4436 int *rdata_len, int *rparam_len)
4438 *rparam_len = 4;
4439 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4440 if (!*rparam) {
4441 return False;
4444 *rdata_len = 0;
4446 SSVAL(*rparam,0,NERR_notsupported);
4447 SSVAL(*rparam,2,0); /* converter word */
4449 DEBUG(3,("Unsupported API command\n"));
4451 return True;
4454 static const struct {
4455 const char *name;
4456 int id;
4457 bool (*fn)(connection_struct *, uint16,
4458 char *, int,
4459 char *, int,
4460 int,int,char **,char **,int *,int *);
4461 bool auth_user; /* Deny anonymous access? */
4462 } api_commands[] = {
4463 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4464 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4465 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4466 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4467 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4468 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4469 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4470 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4471 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4472 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4473 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4474 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4475 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4476 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4477 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4478 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4479 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4480 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4481 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4482 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4483 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4484 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4485 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4486 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4487 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4488 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4489 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4490 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4491 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4492 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4493 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4494 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4495 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4496 {NULL, -1, api_Unsupported}
4497 /* The following RAP calls are not implemented by Samba:
4499 RAP_WFileEnum2 - anon not OK
4504 /****************************************************************************
4505 Handle remote api calls.
4506 ****************************************************************************/
4508 void api_reply(connection_struct *conn, uint16 vuid,
4509 struct smb_request *req,
4510 char *data, char *params,
4511 int tdscnt, int tpscnt,
4512 int mdrcnt, int mprcnt)
4514 int api_command;
4515 char *rdata = NULL;
4516 char *rparam = NULL;
4517 const char *name1 = NULL;
4518 const char *name2 = NULL;
4519 int rdata_len = 0;
4520 int rparam_len = 0;
4521 bool reply=False;
4522 int i;
4524 if (!params) {
4525 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4526 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4527 return;
4530 if (tpscnt < 2) {
4531 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4532 return;
4534 api_command = SVAL(params,0);
4535 /* Is there a string at position params+2 ? */
4536 if (skip_string(params,tpscnt,params+2)) {
4537 name1 = params + 2;
4538 } else {
4539 name1 = "";
4541 name2 = skip_string(params,tpscnt,params+2);
4542 if (!name2) {
4543 name2 = "";
4546 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4547 api_command,
4548 name1,
4549 name2,
4550 tdscnt,tpscnt,mdrcnt,mprcnt));
4552 for (i=0;api_commands[i].name;i++) {
4553 if (api_commands[i].id == api_command && api_commands[i].fn) {
4554 DEBUG(3,("Doing %s\n",api_commands[i].name));
4555 break;
4559 /* Check whether this api call can be done anonymously */
4561 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4562 user_struct *user = get_valid_user_struct(vuid);
4564 if (!user || user->guest) {
4565 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4566 return;
4570 rdata = (char *)SMB_MALLOC(1024);
4571 if (rdata) {
4572 memset(rdata,'\0',1024);
4575 rparam = (char *)SMB_MALLOC(1024);
4576 if (rparam) {
4577 memset(rparam,'\0',1024);
4580 if(!rdata || !rparam) {
4581 DEBUG(0,("api_reply: malloc fail !\n"));
4582 SAFE_FREE(rdata);
4583 SAFE_FREE(rparam);
4584 reply_nterror(req, NT_STATUS_NO_MEMORY);
4585 return;
4588 reply = api_commands[i].fn(conn,
4589 vuid,
4590 params,tpscnt, /* params + length */
4591 data,tdscnt, /* data + length */
4592 mdrcnt,mprcnt,
4593 &rdata,&rparam,&rdata_len,&rparam_len);
4596 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4597 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4598 &rdata,&rparam,&rdata_len,&rparam_len);
4601 /* if we get False back then it's actually unsupported */
4602 if (!reply) {
4603 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4604 &rdata,&rparam,&rdata_len,&rparam_len);
4607 /* If api_Unsupported returns false we can't return anything. */
4608 if (reply) {
4609 send_trans_reply(conn, req, rparam, rparam_len,
4610 rdata, rdata_len, False);
4613 SAFE_FREE(rdata);
4614 SAFE_FREE(rparam);
4615 return;