s3:smbd: implement api_RNetServerEnum3
[Samba/gbeck.git] / source3 / smbd / lanman.c
blob98c9d75420370b38779c5acb7a3b919990abcf13
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"
29 #include "../lib/util/binsearch.h"
31 #ifdef CHECK_TYPES
32 #undef CHECK_TYPES
33 #endif
34 #define CHECK_TYPES 0
36 #define NERR_Success 0
37 #define NERR_badpass 86
38 #define NERR_notsupported 50
40 #define NERR_BASE (2100)
41 #define NERR_BufTooSmall (NERR_BASE+23)
42 #define NERR_JobNotFound (NERR_BASE+51)
43 #define NERR_DestNotFound (NERR_BASE+52)
45 #define ACCESS_READ 0x01
46 #define ACCESS_WRITE 0x02
47 #define ACCESS_CREATE 0x04
49 #define SHPWLEN 8 /* share password length */
51 /* Limit size of ipc replies */
53 static char *smb_realloc_limit(void *ptr, size_t size)
55 char *val;
57 size = MAX((size),4*1024);
58 val = (char *)SMB_REALLOC(ptr,size);
59 if (val) {
60 memset(val,'\0',size);
62 return val;
65 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
66 char *param, int tpscnt,
67 char *data, int tdscnt,
68 int mdrcnt, int mprcnt,
69 char **rdata, char **rparam,
70 int *rdata_len, int *rparam_len);
72 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
73 int mdrcnt, int mprcnt,
74 char **rdata, char **rparam,
75 int *rdata_len, int *rparam_len);
78 static int CopyExpanded(connection_struct *conn,
79 int snum, char **dst, char *src, int *p_space_remaining)
81 TALLOC_CTX *ctx = talloc_tos();
82 char *buf = NULL;
83 int l;
85 if (!src || !dst || !p_space_remaining || !(*dst) ||
86 *p_space_remaining <= 0) {
87 return 0;
90 buf = talloc_strdup(ctx, src);
91 if (!buf) {
92 *p_space_remaining = 0;
93 return 0;
95 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
96 if (!buf) {
97 *p_space_remaining = 0;
98 return 0;
100 buf = talloc_sub_advanced(ctx,
101 lp_servicename(SNUM(conn)),
102 conn->server_info->unix_name,
103 conn->connectpath,
104 conn->server_info->utok.gid,
105 conn->server_info->sanitized_username,
106 pdb_get_domain(conn->server_info->sam_account),
107 buf);
108 if (!buf) {
109 *p_space_remaining = 0;
110 return 0;
112 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
113 if (l == -1) {
114 return 0;
116 (*dst) += l;
117 (*p_space_remaining) -= l;
118 return l;
121 static int CopyAndAdvance(char **dst, char *src, int *n)
123 int l;
124 if (!src || !dst || !n || !(*dst)) {
125 return 0;
127 l = push_ascii(*dst,src,*n, STR_TERMINATE);
128 if (l == -1) {
129 return 0;
131 (*dst) += l;
132 (*n) -= l;
133 return l;
136 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
138 TALLOC_CTX *ctx = talloc_tos();
139 char *buf = NULL;
140 if (!s) {
141 return 0;
143 buf = talloc_strdup(ctx,s);
144 if (!buf) {
145 return 0;
147 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
148 if (!buf) {
149 return 0;
151 buf = talloc_sub_advanced(ctx,
152 lp_servicename(SNUM(conn)),
153 conn->server_info->unix_name,
154 conn->connectpath,
155 conn->server_info->utok.gid,
156 conn->server_info->sanitized_username,
157 pdb_get_domain(conn->server_info->sam_account),
158 buf);
159 if (!buf) {
160 return 0;
162 return strlen(buf) + 1;
165 static char *Expand(connection_struct *conn, int snum, char *s)
167 TALLOC_CTX *ctx = talloc_tos();
168 char *buf = NULL;
170 if (!s) {
171 return NULL;
173 buf = talloc_strdup(ctx,s);
174 if (!buf) {
175 return 0;
177 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
178 if (!buf) {
179 return 0;
181 return talloc_sub_advanced(ctx,
182 lp_servicename(SNUM(conn)),
183 conn->server_info->unix_name,
184 conn->connectpath,
185 conn->server_info->utok.gid,
186 conn->server_info->sanitized_username,
187 pdb_get_domain(conn->server_info->sam_account),
188 buf);
191 /*******************************************************************
192 Check a API string for validity when we only need to check the prefix.
193 ******************************************************************/
195 static bool prefix_ok(const char *str, const char *prefix)
197 return(strncmp(str,prefix,strlen(prefix)) == 0);
200 struct pack_desc {
201 const char *format; /* formatstring for structure */
202 const char *subformat; /* subformat for structure */
203 char *base; /* baseaddress of buffer */
204 int buflen; /* remaining size for fixed part; on init: length of base */
205 int subcount; /* count of substructures */
206 char *structbuf; /* pointer into buffer for remaining fixed part */
207 int stringlen; /* remaining size for variable part */
208 char *stringbuf; /* pointer into buffer for remaining variable part */
209 int neededlen; /* total needed size */
210 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
211 const char *curpos; /* current position; pointer into format or subformat */
212 int errcode;
215 static int get_counter(const char **p)
217 int i, n;
218 if (!p || !(*p)) {
219 return 1;
221 if (!isdigit((int)**p)) {
222 return 1;
224 for (n = 0;;) {
225 i = **p;
226 if (isdigit(i)) {
227 n = 10 * n + (i - '0');
228 } else {
229 return n;
231 (*p)++;
235 static int getlen(const char *p)
237 int n = 0;
238 if (!p) {
239 return 0;
242 while (*p) {
243 switch( *p++ ) {
244 case 'W': /* word (2 byte) */
245 n += 2;
246 break;
247 case 'K': /* status word? (2 byte) */
248 n += 2;
249 break;
250 case 'N': /* count of substructures (word) at end */
251 n += 2;
252 break;
253 case 'D': /* double word (4 byte) */
254 case 'z': /* offset to zero terminated string (4 byte) */
255 case 'l': /* offset to user data (4 byte) */
256 n += 4;
257 break;
258 case 'b': /* offset to data (with counter) (4 byte) */
259 n += 4;
260 get_counter(&p);
261 break;
262 case 'B': /* byte (with optional counter) */
263 n += get_counter(&p);
264 break;
267 return n;
270 static bool init_package(struct pack_desc *p, int count, int subcount)
272 int n = p->buflen;
273 int i;
275 if (!p->format || !p->base) {
276 return False;
279 i = count * getlen(p->format);
280 if (p->subformat) {
281 i += subcount * getlen(p->subformat);
283 p->structbuf = p->base;
284 p->neededlen = 0;
285 p->usedlen = 0;
286 p->subcount = 0;
287 p->curpos = p->format;
288 if (i > n) {
289 p->neededlen = i;
290 i = n = 0;
291 #if 0
293 * This is the old error code we used. Aparently
294 * WinNT/2k systems return ERRbuftoosmall (2123) and
295 * OS/2 needs this. I'm leaving this here so we can revert
296 * if needed. JRA.
298 p->errcode = ERRmoredata;
299 #else
300 p->errcode = ERRbuftoosmall;
301 #endif
302 } else {
303 p->errcode = NERR_Success;
305 p->buflen = i;
306 n -= i;
307 p->stringbuf = p->base + i;
308 p->stringlen = n;
309 return (p->errcode == NERR_Success);
312 static int package(struct pack_desc *p, ...)
314 va_list args;
315 int needed=0, stringneeded;
316 const char *str=NULL;
317 int is_string=0, stringused;
318 int32 temp;
320 va_start(args,p);
322 if (!*p->curpos) {
323 if (!p->subcount) {
324 p->curpos = p->format;
325 } else {
326 p->curpos = p->subformat;
327 p->subcount--;
330 #if CHECK_TYPES
331 str = va_arg(args,char*);
332 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
333 #endif
334 stringneeded = -1;
336 if (!p->curpos) {
337 va_end(args);
338 return 0;
341 switch( *p->curpos++ ) {
342 case 'W': /* word (2 byte) */
343 needed = 2;
344 temp = va_arg(args,int);
345 if (p->buflen >= needed) {
346 SSVAL(p->structbuf,0,temp);
348 break;
349 case 'K': /* status word? (2 byte) */
350 needed = 2;
351 temp = va_arg(args,int);
352 if (p->buflen >= needed) {
353 SSVAL(p->structbuf,0,temp);
355 break;
356 case 'N': /* count of substructures (word) at end */
357 needed = 2;
358 p->subcount = va_arg(args,int);
359 if (p->buflen >= needed) {
360 SSVAL(p->structbuf,0,p->subcount);
362 break;
363 case 'D': /* double word (4 byte) */
364 needed = 4;
365 temp = va_arg(args,int);
366 if (p->buflen >= needed) {
367 SIVAL(p->structbuf,0,temp);
369 break;
370 case 'B': /* byte (with optional counter) */
371 needed = get_counter(&p->curpos);
373 char *s = va_arg(args,char*);
374 if (p->buflen >= needed) {
375 StrnCpy(p->structbuf,s?s:"",needed-1);
378 break;
379 case 'z': /* offset to zero terminated string (4 byte) */
380 str = va_arg(args,char*);
381 stringneeded = (str ? strlen(str)+1 : 0);
382 is_string = 1;
383 break;
384 case 'l': /* offset to user data (4 byte) */
385 str = va_arg(args,char*);
386 stringneeded = va_arg(args,int);
387 is_string = 0;
388 break;
389 case 'b': /* offset to data (with counter) (4 byte) */
390 str = va_arg(args,char*);
391 stringneeded = get_counter(&p->curpos);
392 is_string = 0;
393 break;
396 va_end(args);
397 if (stringneeded >= 0) {
398 needed = 4;
399 if (p->buflen >= needed) {
400 stringused = stringneeded;
401 if (stringused > p->stringlen) {
402 stringused = (is_string ? p->stringlen : 0);
403 if (p->errcode == NERR_Success) {
404 p->errcode = ERRmoredata;
407 if (!stringused) {
408 SIVAL(p->structbuf,0,0);
409 } else {
410 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
411 memcpy(p->stringbuf,str?str:"",stringused);
412 if (is_string) {
413 p->stringbuf[stringused-1] = '\0';
415 p->stringbuf += stringused;
416 p->stringlen -= stringused;
417 p->usedlen += stringused;
420 p->neededlen += stringneeded;
423 p->neededlen += needed;
424 if (p->buflen >= needed) {
425 p->structbuf += needed;
426 p->buflen -= needed;
427 p->usedlen += needed;
428 } else {
429 if (p->errcode == NERR_Success) {
430 p->errcode = ERRmoredata;
433 return 1;
436 #if CHECK_TYPES
437 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
438 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
439 #else
440 #define PACK(desc,t,v) package(desc,v)
441 #define PACKl(desc,t,v,l) package(desc,v,l)
442 #endif
444 static void PACKI(struct pack_desc* desc, const char *t,int v)
446 PACK(desc,t,v);
449 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
451 PACK(desc,t,v);
454 /****************************************************************************
455 Get a print queue.
456 ****************************************************************************/
458 static void PackDriverData(struct pack_desc* desc)
460 char drivdata[4+4+32];
461 SIVAL(drivdata,0,sizeof drivdata); /* cb */
462 SIVAL(drivdata,4,1000); /* lVersion */
463 memset(drivdata+8,0,32); /* szDeviceName */
464 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
465 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
468 static int check_printq_info(struct pack_desc* desc,
469 unsigned int uLevel, char *id1, char *id2)
471 desc->subformat = NULL;
472 switch( uLevel ) {
473 case 0:
474 desc->format = "B13";
475 break;
476 case 1:
477 desc->format = "B13BWWWzzzzzWW";
478 break;
479 case 2:
480 desc->format = "B13BWWWzzzzzWN";
481 desc->subformat = "WB21BB16B10zWWzDDz";
482 break;
483 case 3:
484 desc->format = "zWWWWzzzzWWzzl";
485 break;
486 case 4:
487 desc->format = "zWWWWzzzzWNzzl";
488 desc->subformat = "WWzWWDDzz";
489 break;
490 case 5:
491 desc->format = "z";
492 break;
493 case 51:
494 desc->format = "K";
495 break;
496 case 52:
497 desc->format = "WzzzzzzzzN";
498 desc->subformat = "z";
499 break;
500 default:
501 DEBUG(0,("check_printq_info: invalid level %d\n",
502 uLevel ));
503 return False;
505 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
506 DEBUG(0,("check_printq_info: invalid format %s\n",
507 id1 ? id1 : "<NULL>" ));
508 return False;
510 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
511 DEBUG(0,("check_printq_info: invalid subformat %s\n",
512 id2 ? id2 : "<NULL>" ));
513 return False;
515 return True;
519 #define RAP_JOB_STATUS_QUEUED 0
520 #define RAP_JOB_STATUS_PAUSED 1
521 #define RAP_JOB_STATUS_SPOOLING 2
522 #define RAP_JOB_STATUS_PRINTING 3
523 #define RAP_JOB_STATUS_PRINTED 4
525 #define RAP_QUEUE_STATUS_PAUSED 1
526 #define RAP_QUEUE_STATUS_ERROR 2
528 /* turn a print job status into a on the wire status
530 static int printj_status(int v)
532 switch (v) {
533 case LPQ_QUEUED:
534 return RAP_JOB_STATUS_QUEUED;
535 case LPQ_PAUSED:
536 return RAP_JOB_STATUS_PAUSED;
537 case LPQ_SPOOLING:
538 return RAP_JOB_STATUS_SPOOLING;
539 case LPQ_PRINTING:
540 return RAP_JOB_STATUS_PRINTING;
542 return 0;
545 /* turn a print queue status into a on the wire status
547 static int printq_status(int v)
549 switch (v) {
550 case LPQ_QUEUED:
551 return 0;
552 case LPQ_PAUSED:
553 return RAP_QUEUE_STATUS_PAUSED;
555 return RAP_QUEUE_STATUS_ERROR;
558 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
559 struct pack_desc *desc,
560 print_queue_struct *queue, int n)
562 time_t t = queue->time;
564 /* the client expects localtime */
565 t -= get_time_zone(t);
567 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
568 if (uLevel == 1) {
569 PACKS(desc,"B21",queue->fs_user); /* szUserName */
570 PACKS(desc,"B",""); /* pad */
571 PACKS(desc,"B16",""); /* szNotifyName */
572 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
573 PACKS(desc,"z",""); /* pszParms */
574 PACKI(desc,"W",n+1); /* uPosition */
575 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
576 PACKS(desc,"z",""); /* pszStatus */
577 PACKI(desc,"D",t); /* ulSubmitted */
578 PACKI(desc,"D",queue->size); /* ulSize */
579 PACKS(desc,"z",queue->fs_file); /* pszComment */
581 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
582 PACKI(desc,"W",queue->priority); /* uPriority */
583 PACKS(desc,"z",queue->fs_user); /* pszUserName */
584 PACKI(desc,"W",n+1); /* uPosition */
585 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
586 PACKI(desc,"D",t); /* ulSubmitted */
587 PACKI(desc,"D",queue->size); /* ulSize */
588 PACKS(desc,"z","Samba"); /* pszComment */
589 PACKS(desc,"z",queue->fs_file); /* pszDocument */
590 if (uLevel == 3) {
591 PACKS(desc,"z",""); /* pszNotifyName */
592 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
593 PACKS(desc,"z",""); /* pszParms */
594 PACKS(desc,"z",""); /* pszStatus */
595 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
596 PACKS(desc,"z","lpd"); /* pszQProcName */
597 PACKS(desc,"z",""); /* pszQProcParms */
598 PACKS(desc,"z","NULL"); /* pszDriverName */
599 PackDriverData(desc); /* pDriverData */
600 PACKS(desc,"z",""); /* pszPrinterName */
601 } else if (uLevel == 4) { /* OS2 */
602 PACKS(desc,"z",""); /* pszSpoolFileName */
603 PACKS(desc,"z",""); /* pszPortName */
604 PACKS(desc,"z",""); /* pszStatus */
605 PACKI(desc,"D",0); /* ulPagesSpooled */
606 PACKI(desc,"D",0); /* ulPagesSent */
607 PACKI(desc,"D",0); /* ulPagesPrinted */
608 PACKI(desc,"D",0); /* ulTimePrinted */
609 PACKI(desc,"D",0); /* ulExtendJobStatus */
610 PACKI(desc,"D",0); /* ulStartPage */
611 PACKI(desc,"D",0); /* ulEndPage */
616 /********************************************************************
617 Return a driver name given an snum.
618 Returns True if from tdb, False otherwise.
619 ********************************************************************/
621 static bool get_driver_name(int snum, char **pp_drivername)
623 NT_PRINTER_INFO_LEVEL *info = NULL;
624 bool in_tdb = false;
626 get_a_printer (NULL, &info, 2, lp_servicename(snum));
627 if (info != NULL) {
628 *pp_drivername = talloc_strdup(talloc_tos(),
629 info->info_2->drivername);
630 in_tdb = true;
631 free_a_printer(&info, 2);
632 if (!*pp_drivername) {
633 return false;
637 return in_tdb;
640 /********************************************************************
641 Respond to the DosPrintQInfo command with a level of 52
642 This is used to get printer driver information for Win9x clients
643 ********************************************************************/
644 static void fill_printq_info_52(connection_struct *conn, int snum,
645 struct pack_desc* desc, int count )
647 int i;
648 fstring location;
649 NT_PRINTER_DRIVER_INFO_LEVEL driver;
650 NT_PRINTER_INFO_LEVEL *printer = NULL;
652 ZERO_STRUCT(driver);
654 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
655 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
656 lp_servicename(snum)));
657 goto err;
660 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
661 "Windows 4.0", 0)) )
663 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
664 printer->info_2->drivername));
665 goto err;
668 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
669 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
670 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
672 PACKI(desc, "W", 0x0400); /* don't know */
673 PACKS(desc, "z", driver.info_3->name); /* long printer name */
674 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
675 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
676 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
678 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
679 standard_sub_basic( "", "", location, sizeof(location)-1 );
680 PACKS(desc,"z", location); /* share to retrieve files */
682 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
683 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
684 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
686 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
687 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
688 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
689 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
690 DEBUG(3,("Driver Location: %s:\n",location));
691 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
692 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
693 PACKI(desc,"N",count); /* number of files to copy */
695 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
697 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
698 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
699 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
702 /* sanity check */
703 if ( i != count )
704 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
705 count, i));
707 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
709 desc->errcode=NERR_Success;
710 goto done;
712 err:
713 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
714 desc->errcode=NERR_notsupported;
716 done:
717 if ( printer )
718 free_a_printer( &printer, 2 );
720 if ( driver.info_3 )
721 free_a_printer_driver( driver, 3 );
725 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
726 struct pack_desc* desc,
727 int count, print_queue_struct* queue,
728 print_status_struct* status)
730 switch (uLevel) {
731 case 1:
732 case 2:
733 PACKS(desc,"B13",SERVICE(snum));
734 break;
735 case 3:
736 case 4:
737 case 5:
738 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
739 break;
740 case 51:
741 PACKI(desc,"K",printq_status(status->status));
742 break;
745 if (uLevel == 1 || uLevel == 2) {
746 PACKS(desc,"B",""); /* alignment */
747 PACKI(desc,"W",5); /* priority */
748 PACKI(desc,"W",0); /* start time */
749 PACKI(desc,"W",0); /* until time */
750 PACKS(desc,"z",""); /* pSepFile */
751 PACKS(desc,"z","lpd"); /* pPrProc */
752 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
753 PACKS(desc,"z",""); /* pParms */
754 if (snum < 0) {
755 PACKS(desc,"z","UNKNOWN PRINTER");
756 PACKI(desc,"W",LPSTAT_ERROR);
758 else if (!status || !status->message[0]) {
759 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
760 PACKI(desc,"W",LPSTAT_OK); /* status */
761 } else {
762 PACKS(desc,"z",status->message);
763 PACKI(desc,"W",printq_status(status->status)); /* status */
765 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
768 if (uLevel == 3 || uLevel == 4) {
769 char *drivername = NULL;
771 PACKI(desc,"W",5); /* uPriority */
772 PACKI(desc,"W",0); /* uStarttime */
773 PACKI(desc,"W",0); /* uUntiltime */
774 PACKI(desc,"W",5); /* pad1 */
775 PACKS(desc,"z",""); /* pszSepFile */
776 PACKS(desc,"z","WinPrint"); /* pszPrProc */
777 PACKS(desc,"z",NULL); /* pszParms */
778 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
779 /* "don't ask" that it's done this way to fix corrupted
780 Win9X/ME printer comments. */
781 if (!status) {
782 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
783 } else {
784 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
786 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
787 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
788 get_driver_name(snum,&drivername);
789 if (!drivername) {
790 return;
792 PACKS(desc,"z",drivername); /* pszDriverName */
793 PackDriverData(desc); /* pDriverData */
796 if (uLevel == 2 || uLevel == 4) {
797 int i;
798 for (i=0;i<count;i++)
799 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
802 if (uLevel==52)
803 fill_printq_info_52( conn, snum, desc, count );
806 /* This function returns the number of files for a given driver */
807 static int get_printerdrivernumber(int snum)
809 int result = 0;
810 NT_PRINTER_DRIVER_INFO_LEVEL driver;
811 NT_PRINTER_INFO_LEVEL *printer = NULL;
813 ZERO_STRUCT(driver);
815 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
816 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
817 lp_servicename(snum)));
818 goto done;
821 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
822 "Windows 4.0", 0)) )
824 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
825 printer->info_2->drivername));
826 goto done;
829 /* count the number of files */
830 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
831 result++;
833 done:
834 if ( printer )
835 free_a_printer( &printer, 2 );
837 if ( driver.info_3 )
838 free_a_printer_driver( driver, 3 );
840 return result;
843 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
844 char *param, int tpscnt,
845 char *data, int tdscnt,
846 int mdrcnt,int mprcnt,
847 char **rdata,char **rparam,
848 int *rdata_len,int *rparam_len)
850 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
851 char *str2 = skip_string(param,tpscnt,str1);
852 char *p = skip_string(param,tpscnt,str2);
853 char *QueueName = p;
854 unsigned int uLevel;
855 int count=0;
856 int snum;
857 char *str3;
858 struct pack_desc desc;
859 print_queue_struct *queue=NULL;
860 print_status_struct status;
861 char* tmpdata=NULL;
863 if (!str1 || !str2 || !p) {
864 return False;
866 memset((char *)&status,'\0',sizeof(status));
867 memset((char *)&desc,'\0',sizeof(desc));
869 p = skip_string(param,tpscnt,p);
870 if (!p) {
871 return False;
873 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
874 str3 = get_safe_str_ptr(param,tpscnt,p,4);
875 /* str3 may be null here and is checked in check_printq_info(). */
877 /* remove any trailing username */
878 if ((p = strchr_m(QueueName,'%')))
879 *p = 0;
881 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
883 /* check it's a supported varient */
884 if (!prefix_ok(str1,"zWrLh"))
885 return False;
886 if (!check_printq_info(&desc,uLevel,str2,str3)) {
888 * Patch from Scott Moomaw <scott@bridgewater.edu>
889 * to return the 'invalid info level' error if an
890 * unknown level was requested.
892 *rdata_len = 0;
893 *rparam_len = 6;
894 *rparam = smb_realloc_limit(*rparam,*rparam_len);
895 if (!*rparam) {
896 return False;
898 SSVALS(*rparam,0,ERRunknownlevel);
899 SSVAL(*rparam,2,0);
900 SSVAL(*rparam,4,0);
901 return(True);
904 snum = find_service(QueueName);
905 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
906 return False;
908 if (uLevel==52) {
909 count = get_printerdrivernumber(snum);
910 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
911 } else {
912 count = print_queue_status(snum, &queue,&status);
915 if (mdrcnt > 0) {
916 *rdata = smb_realloc_limit(*rdata,mdrcnt);
917 if (!*rdata) {
918 SAFE_FREE(queue);
919 return False;
921 desc.base = *rdata;
922 desc.buflen = mdrcnt;
923 } else {
925 * Don't return data but need to get correct length
926 * init_package will return wrong size if buflen=0
928 desc.buflen = getlen(desc.format);
929 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
932 if (init_package(&desc,1,count)) {
933 desc.subcount = count;
934 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
937 *rdata_len = desc.usedlen;
940 * We must set the return code to ERRbuftoosmall
941 * in order to support lanman style printing with Win NT/2k
942 * clients --jerry
944 if (!mdrcnt && lp_disable_spoolss())
945 desc.errcode = ERRbuftoosmall;
947 *rdata_len = desc.usedlen;
948 *rparam_len = 6;
949 *rparam = smb_realloc_limit(*rparam,*rparam_len);
950 if (!*rparam) {
951 SAFE_FREE(queue);
952 SAFE_FREE(tmpdata);
953 return False;
955 SSVALS(*rparam,0,desc.errcode);
956 SSVAL(*rparam,2,0);
957 SSVAL(*rparam,4,desc.neededlen);
959 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
961 SAFE_FREE(queue);
962 SAFE_FREE(tmpdata);
964 return(True);
967 /****************************************************************************
968 View list of all print jobs on all queues.
969 ****************************************************************************/
971 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
972 char *param, int tpscnt,
973 char *data, int tdscnt,
974 int mdrcnt, int mprcnt,
975 char **rdata, char** rparam,
976 int *rdata_len, int *rparam_len)
978 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
979 char *output_format1 = skip_string(param,tpscnt,param_format);
980 char *p = skip_string(param,tpscnt,output_format1);
981 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
982 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
983 int services = lp_numservices();
984 int i, n;
985 struct pack_desc desc;
986 print_queue_struct **queue = NULL;
987 print_status_struct *status = NULL;
988 int *subcntarr = NULL;
989 int queuecnt = 0, subcnt = 0, succnt = 0;
991 if (!param_format || !output_format1 || !p) {
992 return False;
995 memset((char *)&desc,'\0',sizeof(desc));
997 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
999 if (!prefix_ok(param_format,"WrLeh")) {
1000 return False;
1002 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1004 * Patch from Scott Moomaw <scott@bridgewater.edu>
1005 * to return the 'invalid info level' error if an
1006 * unknown level was requested.
1008 *rdata_len = 0;
1009 *rparam_len = 6;
1010 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1011 if (!*rparam) {
1012 return False;
1014 SSVALS(*rparam,0,ERRunknownlevel);
1015 SSVAL(*rparam,2,0);
1016 SSVAL(*rparam,4,0);
1017 return(True);
1020 for (i = 0; i < services; i++) {
1021 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1022 queuecnt++;
1026 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1027 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1028 goto err;
1030 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1031 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1032 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1033 goto err;
1035 memset(status,0,queuecnt*sizeof(print_status_struct));
1036 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1037 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1038 goto err;
1041 subcnt = 0;
1042 n = 0;
1043 for (i = 0; i < services; i++) {
1044 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1045 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1046 subcnt += subcntarr[n];
1047 n++;
1051 if (mdrcnt > 0) {
1052 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1053 if (!*rdata) {
1054 goto err;
1057 desc.base = *rdata;
1058 desc.buflen = mdrcnt;
1060 if (init_package(&desc,queuecnt,subcnt)) {
1061 n = 0;
1062 succnt = 0;
1063 for (i = 0; i < services; i++) {
1064 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1065 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1066 n++;
1067 if (desc.errcode == NERR_Success) {
1068 succnt = n;
1074 SAFE_FREE(subcntarr);
1076 *rdata_len = desc.usedlen;
1077 *rparam_len = 8;
1078 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1079 if (!*rparam) {
1080 goto err;
1082 SSVALS(*rparam,0,desc.errcode);
1083 SSVAL(*rparam,2,0);
1084 SSVAL(*rparam,4,succnt);
1085 SSVAL(*rparam,6,queuecnt);
1087 for (i = 0; i < queuecnt; i++) {
1088 if (queue) {
1089 SAFE_FREE(queue[i]);
1093 SAFE_FREE(queue);
1094 SAFE_FREE(status);
1096 return True;
1098 err:
1100 SAFE_FREE(subcntarr);
1101 for (i = 0; i < queuecnt; i++) {
1102 if (queue) {
1103 SAFE_FREE(queue[i]);
1106 SAFE_FREE(queue);
1107 SAFE_FREE(status);
1109 return False;
1112 /****************************************************************************
1113 Get info level for a server list query.
1114 ****************************************************************************/
1116 static bool check_server_info(int uLevel, char* id)
1118 switch( uLevel ) {
1119 case 0:
1120 if (strcmp(id,"B16") != 0) {
1121 return False;
1123 break;
1124 case 1:
1125 if (strcmp(id,"B16BBDz") != 0) {
1126 return False;
1128 break;
1129 default:
1130 return False;
1132 return True;
1135 struct srv_info_struct {
1136 fstring name;
1137 uint32 type;
1138 fstring comment;
1139 fstring domain;
1140 bool server_added;
1143 /*******************************************************************
1144 Get server info lists from the files saved by nmbd. Return the
1145 number of entries.
1146 ******************************************************************/
1148 static int get_server_info(uint32 servertype,
1149 struct srv_info_struct **servers,
1150 const char *domain)
1152 int count=0;
1153 int alloced=0;
1154 char **lines;
1155 bool local_list_only;
1156 int i;
1158 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1159 if (!lines) {
1160 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1161 return 0;
1164 /* request for everything is code for request all servers */
1165 if (servertype == SV_TYPE_ALL) {
1166 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1169 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1171 DEBUG(4,("Servertype search: %8x\n",servertype));
1173 for (i=0;lines[i];i++) {
1174 fstring stype;
1175 struct srv_info_struct *s;
1176 const char *ptr = lines[i];
1177 bool ok = True;
1178 TALLOC_CTX *frame = NULL;
1179 char *p;
1181 if (!*ptr) {
1182 continue;
1185 if (count == alloced) {
1186 alloced += 10;
1187 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1188 if (!*servers) {
1189 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1190 TALLOC_FREE(lines);
1191 return 0;
1193 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1195 s = &(*servers)[count];
1197 frame = talloc_stackframe();
1198 s->name[0] = '\0';
1199 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1200 TALLOC_FREE(frame);
1201 continue;
1203 fstrcpy(s->name, p);
1205 stype[0] = '\0';
1206 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1207 TALLOC_FREE(frame);
1208 continue;
1210 fstrcpy(stype, p);
1212 s->comment[0] = '\0';
1213 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1214 TALLOC_FREE(frame);
1215 continue;
1217 fstrcpy(s->comment, p);
1218 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1220 s->domain[0] = '\0';
1221 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1222 /* this allows us to cope with an old nmbd */
1223 fstrcpy(s->domain,lp_workgroup());
1224 } else {
1225 fstrcpy(s->domain, p);
1227 TALLOC_FREE(frame);
1229 if (sscanf(stype,"%X",&s->type) != 1) {
1230 DEBUG(4,("r:host file "));
1231 ok = False;
1234 /* Filter the servers/domains we return based on what was asked for. */
1236 /* Check to see if we are being asked for a local list only. */
1237 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1238 DEBUG(4,("r: local list only"));
1239 ok = False;
1242 /* doesn't match up: don't want it */
1243 if (!(servertype & s->type)) {
1244 DEBUG(4,("r:serv type "));
1245 ok = False;
1248 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1249 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1250 DEBUG(4,("s: dom mismatch "));
1251 ok = False;
1254 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1255 ok = False;
1258 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1259 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1261 if (ok) {
1262 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1263 s->name, s->type, s->comment, s->domain));
1264 s->server_added = True;
1265 count++;
1266 } else {
1267 DEBUG(4,("%20s %8x %25s %15s\n",
1268 s->name, s->type, s->comment, s->domain));
1272 TALLOC_FREE(lines);
1273 return count;
1276 /*******************************************************************
1277 Fill in a server info structure.
1278 ******************************************************************/
1280 static int fill_srv_info(struct srv_info_struct *service,
1281 int uLevel, char **buf, int *buflen,
1282 char **stringbuf, int *stringspace, char *baseaddr)
1284 int struct_len;
1285 char* p;
1286 char* p2;
1287 int l2;
1288 int len;
1290 switch (uLevel) {
1291 case 0:
1292 struct_len = 16;
1293 break;
1294 case 1:
1295 struct_len = 26;
1296 break;
1297 default:
1298 return -1;
1301 if (!buf) {
1302 len = 0;
1303 switch (uLevel) {
1304 case 1:
1305 len = strlen(service->comment)+1;
1306 break;
1309 *buflen = struct_len;
1310 *stringspace = len;
1311 return struct_len + len;
1314 len = struct_len;
1315 p = *buf;
1316 if (*buflen < struct_len) {
1317 return -1;
1319 if (stringbuf) {
1320 p2 = *stringbuf;
1321 l2 = *stringspace;
1322 } else {
1323 p2 = p + struct_len;
1324 l2 = *buflen - struct_len;
1326 if (!baseaddr) {
1327 baseaddr = p;
1330 switch (uLevel) {
1331 case 0:
1332 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1333 break;
1335 case 1:
1336 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1337 SIVAL(p,18,service->type);
1338 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1339 len += CopyAndAdvance(&p2,service->comment,&l2);
1340 break;
1343 if (stringbuf) {
1344 *buf = p + struct_len;
1345 *buflen -= struct_len;
1346 *stringbuf = p2;
1347 *stringspace = l2;
1348 } else {
1349 *buf = p2;
1350 *buflen -= len;
1352 return len;
1356 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1358 #undef strcasecmp
1359 return strcasecmp(s1->name,s2->name);
1362 /****************************************************************************
1363 View list of servers available (or possibly domains). The info is
1364 extracted from lists saved by nmbd on the local host.
1365 ****************************************************************************/
1367 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1368 char *param, int tpscnt,
1369 char *data, int tdscnt,
1370 int mdrcnt, int mprcnt, char **rdata,
1371 char **rparam, int *rdata_len, int *rparam_len)
1373 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1374 char *str2 = skip_string(param,tpscnt,str1);
1375 char *p = skip_string(param,tpscnt,str2);
1376 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1377 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1378 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1379 char *p2;
1380 int data_len, fixed_len, string_len;
1381 int f_len = 0, s_len = 0;
1382 struct srv_info_struct *servers=NULL;
1383 int counted=0,total=0;
1384 int i,missed;
1385 fstring domain;
1386 bool domain_request;
1387 bool local_request;
1389 if (!str1 || !str2 || !p) {
1390 return False;
1393 /* If someone sets all the bits they don't really mean to set
1394 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1395 known servers. */
1397 if (servertype == SV_TYPE_ALL) {
1398 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1401 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1402 any other bit (they may just set this bit on its own) they
1403 want all the locally seen servers. However this bit can be
1404 set on its own so set the requested servers to be
1405 ALL - DOMAIN_ENUM. */
1407 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1408 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1411 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1412 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1414 p += 8;
1416 if (!prefix_ok(str1,"WrLehD")) {
1417 return False;
1419 if (!check_server_info(uLevel,str2)) {
1420 return False;
1423 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1424 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1425 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1427 if (strcmp(str1, "WrLehDz") == 0) {
1428 if (skip_string(param,tpscnt,p) == NULL) {
1429 return False;
1431 pull_ascii_fstring(domain, p);
1432 } else {
1433 fstrcpy(domain, lp_workgroup());
1436 DEBUG(4, ("domain [%s]\n", domain));
1438 if (lp_browse_list()) {
1439 total = get_server_info(servertype,&servers,domain);
1442 data_len = fixed_len = string_len = 0;
1443 missed = 0;
1445 if (total > 0) {
1446 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1450 char *lastname=NULL;
1452 for (i=0;i<total;i++) {
1453 struct srv_info_struct *s = &servers[i];
1455 if (lastname && strequal(lastname,s->name)) {
1456 continue;
1458 lastname = s->name;
1459 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1460 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1461 i, s->name, s->type, s->comment, s->domain));
1463 if (data_len <= buf_len) {
1464 counted++;
1465 fixed_len += f_len;
1466 string_len += s_len;
1467 } else {
1468 missed++;
1473 *rdata_len = fixed_len + string_len;
1474 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1475 if (!*rdata) {
1476 return False;
1479 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1480 p = *rdata;
1481 f_len = fixed_len;
1482 s_len = string_len;
1485 char *lastname=NULL;
1486 int count2 = counted;
1488 for (i = 0; i < total && count2;i++) {
1489 struct srv_info_struct *s = &servers[i];
1491 if (lastname && strequal(lastname,s->name)) {
1492 continue;
1494 lastname = s->name;
1495 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1496 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1497 i, s->name, s->type, s->comment, s->domain));
1498 count2--;
1502 *rparam_len = 8;
1503 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1504 if (!*rparam) {
1505 return False;
1507 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1508 SSVAL(*rparam,2,0);
1509 SSVAL(*rparam,4,counted);
1510 SSVAL(*rparam,6,counted+missed);
1512 SAFE_FREE(servers);
1514 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1515 domain,uLevel,counted,counted+missed));
1517 return True;
1520 static bool srv_name_match(const char *n1, const char *n2)
1523 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1525 * In Windows, FirstNameToReturn need not be an exact match:
1526 * the server will return a list of servers that exist on
1527 * the network greater than or equal to the FirstNameToReturn.
1529 int ret = strcasecmp(n1, n2);
1531 if (ret <= 0) {
1532 return 0;
1535 return ret;
1538 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1539 char *param, int tpscnt,
1540 char *data, int tdscnt,
1541 int mdrcnt, int mprcnt, char **rdata,
1542 char **rparam, int *rdata_len, int *rparam_len)
1544 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1545 char *str2 = skip_string(param,tpscnt,str1);
1546 char *p = skip_string(param,tpscnt,str2);
1547 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1548 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1549 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1550 char *p2;
1551 int data_len, fixed_len, string_len;
1552 int f_len = 0, s_len = 0;
1553 struct srv_info_struct *servers=NULL;
1554 int counted=0,first=0,total=0;
1555 int i,missed;
1556 fstring domain;
1557 fstring first_name;
1558 bool domain_request;
1559 bool local_request;
1561 if (!str1 || !str2 || !p) {
1562 return False;
1565 /* If someone sets all the bits they don't really mean to set
1566 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1567 known servers. */
1569 if (servertype == SV_TYPE_ALL) {
1570 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1573 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1574 any other bit (they may just set this bit on its own) they
1575 want all the locally seen servers. However this bit can be
1576 set on its own so set the requested servers to be
1577 ALL - DOMAIN_ENUM. */
1579 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1580 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1583 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1584 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1586 p += 8;
1588 if (strcmp(str1, "WrLehDzz") != 0) {
1589 return false;
1591 if (!check_server_info(uLevel,str2)) {
1592 return False;
1595 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1596 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1597 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1599 if (skip_string(param,tpscnt,p) == NULL) {
1600 return False;
1602 pull_ascii_fstring(domain, p);
1603 if (domain[0] == '\0') {
1604 fstrcpy(domain, lp_workgroup());
1606 p = skip_string(param,tpscnt,p);
1607 if (skip_string(param,tpscnt,p) == NULL) {
1608 return False;
1610 pull_ascii_fstring(first_name, p);
1612 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1613 domain, first_name));
1615 if (lp_browse_list()) {
1616 total = get_server_info(servertype,&servers,domain);
1619 data_len = fixed_len = string_len = 0;
1620 missed = 0;
1622 if (total > 0) {
1623 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1626 if (first_name[0] != '\0') {
1627 struct srv_info_struct *first_server = NULL;
1629 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1630 srv_name_match, first_server);
1631 if (first_server) {
1632 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1634 * The binary search may not find the exact match
1635 * so we need to search backward to find the first match
1637 * This implements the strange matching windows
1638 * implements. (see the comment in srv_name_match().
1640 for (;first > 0;) {
1641 int ret;
1642 ret = strcasecmp(first_name,
1643 servers[first-1].name);
1644 if (ret > 0) {
1645 break;
1647 first--;
1649 } else {
1650 /* we should return no entries */
1651 first = total;
1656 char *lastname=NULL;
1658 for (i=first;i<total;i++) {
1659 struct srv_info_struct *s = &servers[i];
1661 if (lastname && strequal(lastname,s->name)) {
1662 continue;
1664 lastname = s->name;
1665 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1666 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1667 i, s->name, s->type, s->comment, s->domain));
1669 if (data_len <= buf_len) {
1670 counted++;
1671 fixed_len += f_len;
1672 string_len += s_len;
1673 } else {
1674 missed++;
1679 *rdata_len = fixed_len + string_len;
1680 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1681 if (!*rdata) {
1682 return False;
1685 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1686 p = *rdata;
1687 f_len = fixed_len;
1688 s_len = string_len;
1691 char *lastname=NULL;
1692 int count2 = counted;
1694 for (i = first; i < total && count2;i++) {
1695 struct srv_info_struct *s = &servers[i];
1697 if (lastname && strequal(lastname,s->name)) {
1698 continue;
1700 lastname = s->name;
1701 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1702 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1703 i, s->name, s->type, s->comment, s->domain));
1704 count2--;
1708 *rparam_len = 8;
1709 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1710 if (!*rparam) {
1711 return False;
1713 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1714 SSVAL(*rparam,2,0);
1715 SSVAL(*rparam,4,counted);
1716 SSVAL(*rparam,6,counted+missed);
1718 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1719 domain,uLevel,first,first_name,
1720 first < total ? servers[first].name : "",
1721 counted,counted+missed));
1723 SAFE_FREE(servers);
1725 return True;
1728 /****************************************************************************
1729 command 0x34 - suspected of being a "Lookup Names" stub api
1730 ****************************************************************************/
1732 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1733 char *param, int tpscnt,
1734 char *data, int tdscnt,
1735 int mdrcnt, int mprcnt, char **rdata,
1736 char **rparam, int *rdata_len, int *rparam_len)
1738 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1739 char *str2 = skip_string(param,tpscnt,str1);
1740 char *p = skip_string(param,tpscnt,str2);
1741 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1742 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1743 int counted=0;
1744 int missed=0;
1746 if (!str1 || !str2 || !p) {
1747 return False;
1750 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1751 str1, str2, p, uLevel, buf_len));
1753 if (!prefix_ok(str1,"zWrLeh")) {
1754 return False;
1757 *rdata_len = 0;
1759 *rparam_len = 8;
1760 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1761 if (!*rparam) {
1762 return False;
1765 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1766 SSVAL(*rparam,2,0);
1767 SSVAL(*rparam,4,counted);
1768 SSVAL(*rparam,6,counted+missed);
1770 return True;
1773 /****************************************************************************
1774 get info about a share
1775 ****************************************************************************/
1777 static bool check_share_info(int uLevel, char* id)
1779 switch( uLevel ) {
1780 case 0:
1781 if (strcmp(id,"B13") != 0) {
1782 return False;
1784 break;
1785 case 1:
1786 if (strcmp(id,"B13BWz") != 0) {
1787 return False;
1789 break;
1790 case 2:
1791 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1792 return False;
1794 break;
1795 case 91:
1796 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1797 return False;
1799 break;
1800 default:
1801 return False;
1803 return True;
1806 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1807 char** buf, int* buflen,
1808 char** stringbuf, int* stringspace, char* baseaddr)
1810 int struct_len;
1811 char* p;
1812 char* p2;
1813 int l2;
1814 int len;
1816 switch( uLevel ) {
1817 case 0:
1818 struct_len = 13;
1819 break;
1820 case 1:
1821 struct_len = 20;
1822 break;
1823 case 2:
1824 struct_len = 40;
1825 break;
1826 case 91:
1827 struct_len = 68;
1828 break;
1829 default:
1830 return -1;
1833 if (!buf) {
1834 len = 0;
1836 if (uLevel > 0) {
1837 len += StrlenExpanded(conn,snum,lp_comment(snum));
1839 if (uLevel > 1) {
1840 len += strlen(lp_pathname(snum)) + 1;
1842 if (buflen) {
1843 *buflen = struct_len;
1845 if (stringspace) {
1846 *stringspace = len;
1848 return struct_len + len;
1851 len = struct_len;
1852 p = *buf;
1853 if ((*buflen) < struct_len) {
1854 return -1;
1857 if (stringbuf) {
1858 p2 = *stringbuf;
1859 l2 = *stringspace;
1860 } else {
1861 p2 = p + struct_len;
1862 l2 = (*buflen) - struct_len;
1865 if (!baseaddr) {
1866 baseaddr = p;
1869 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1871 if (uLevel > 0) {
1872 int type;
1874 SCVAL(p,13,0);
1875 type = STYPE_DISKTREE;
1876 if (lp_print_ok(snum)) {
1877 type = STYPE_PRINTQ;
1879 if (strequal("IPC",lp_fstype(snum))) {
1880 type = STYPE_IPC;
1882 SSVAL(p,14,type); /* device type */
1883 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1884 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1887 if (uLevel > 1) {
1888 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1889 SSVALS(p,22,-1); /* max uses */
1890 SSVAL(p,24,1); /* current uses */
1891 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1892 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1893 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1896 if (uLevel > 2) {
1897 memset(p+40,0,SHPWLEN+2);
1898 SSVAL(p,50,0);
1899 SIVAL(p,52,0);
1900 SSVAL(p,56,0);
1901 SSVAL(p,58,0);
1902 SIVAL(p,60,0);
1903 SSVAL(p,64,0);
1904 SSVAL(p,66,0);
1907 if (stringbuf) {
1908 (*buf) = p + struct_len;
1909 (*buflen) -= struct_len;
1910 (*stringbuf) = p2;
1911 (*stringspace) = l2;
1912 } else {
1913 (*buf) = p2;
1914 (*buflen) -= len;
1917 return len;
1920 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1921 char *param, int tpscnt,
1922 char *data, int tdscnt,
1923 int mdrcnt,int mprcnt,
1924 char **rdata,char **rparam,
1925 int *rdata_len,int *rparam_len)
1927 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1928 char *str2 = skip_string(param,tpscnt,str1);
1929 char *netname = skip_string(param,tpscnt,str2);
1930 char *p = skip_string(param,tpscnt,netname);
1931 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1932 int snum;
1934 if (!str1 || !str2 || !netname || !p) {
1935 return False;
1938 snum = find_service(netname);
1939 if (snum < 0) {
1940 return False;
1943 /* check it's a supported varient */
1944 if (!prefix_ok(str1,"zWrLh")) {
1945 return False;
1947 if (!check_share_info(uLevel,str2)) {
1948 return False;
1951 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1952 if (!*rdata) {
1953 return False;
1955 p = *rdata;
1956 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1957 if (*rdata_len < 0) {
1958 return False;
1961 *rparam_len = 6;
1962 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1963 if (!*rparam) {
1964 return False;
1966 SSVAL(*rparam,0,NERR_Success);
1967 SSVAL(*rparam,2,0); /* converter word */
1968 SSVAL(*rparam,4,*rdata_len);
1970 return True;
1973 /****************************************************************************
1974 View the list of available shares.
1976 This function is the server side of the NetShareEnum() RAP call.
1977 It fills the return buffer with share names and share comments.
1978 Note that the return buffer normally (in all known cases) allows only
1979 twelve byte strings for share names (plus one for a nul terminator).
1980 Share names longer than 12 bytes must be skipped.
1981 ****************************************************************************/
1983 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1984 char *param, int tpscnt,
1985 char *data, int tdscnt,
1986 int mdrcnt,
1987 int mprcnt,
1988 char **rdata,
1989 char **rparam,
1990 int *rdata_len,
1991 int *rparam_len )
1993 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1994 char *str2 = skip_string(param,tpscnt,str1);
1995 char *p = skip_string(param,tpscnt,str2);
1996 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1997 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1998 char *p2;
1999 int count = 0;
2000 int total=0,counted=0;
2001 bool missed = False;
2002 int i;
2003 int data_len, fixed_len, string_len;
2004 int f_len = 0, s_len = 0;
2006 if (!str1 || !str2 || !p) {
2007 return False;
2010 if (!prefix_ok(str1,"WrLeh")) {
2011 return False;
2013 if (!check_share_info(uLevel,str2)) {
2014 return False;
2017 /* Ensure all the usershares are loaded. */
2018 become_root();
2019 load_registry_shares();
2020 count = load_usershare_shares();
2021 unbecome_root();
2023 data_len = fixed_len = string_len = 0;
2024 for (i=0;i<count;i++) {
2025 fstring servicename_dos;
2026 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2027 continue;
2029 push_ascii_fstring(servicename_dos, lp_servicename(i));
2030 /* Maximum name length = 13. */
2031 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2032 total++;
2033 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2034 if (data_len <= buf_len) {
2035 counted++;
2036 fixed_len += f_len;
2037 string_len += s_len;
2038 } else {
2039 missed = True;
2044 *rdata_len = fixed_len + string_len;
2045 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2046 if (!*rdata) {
2047 return False;
2050 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2051 p = *rdata;
2052 f_len = fixed_len;
2053 s_len = string_len;
2055 for( i = 0; i < count; i++ ) {
2056 fstring servicename_dos;
2057 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2058 continue;
2061 push_ascii_fstring(servicename_dos, lp_servicename(i));
2062 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2063 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2064 break;
2069 *rparam_len = 8;
2070 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2071 if (!*rparam) {
2072 return False;
2074 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2075 SSVAL(*rparam,2,0);
2076 SSVAL(*rparam,4,counted);
2077 SSVAL(*rparam,6,total);
2079 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2080 counted,total,uLevel,
2081 buf_len,*rdata_len,mdrcnt));
2083 return True;
2086 /****************************************************************************
2087 Add a share
2088 ****************************************************************************/
2090 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2091 char *param, int tpscnt,
2092 char *data, int tdscnt,
2093 int mdrcnt,int mprcnt,
2094 char **rdata,char **rparam,
2095 int *rdata_len,int *rparam_len)
2097 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2098 char *str2 = skip_string(param,tpscnt,str1);
2099 char *p = skip_string(param,tpscnt,str2);
2100 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2101 fstring sharename;
2102 fstring comment;
2103 char *pathname = NULL;
2104 char *command, *cmdname;
2105 unsigned int offset;
2106 int snum;
2107 int res = ERRunsup;
2108 size_t converted_size;
2110 if (!str1 || !str2 || !p) {
2111 return False;
2114 /* check it's a supported varient */
2115 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2116 return False;
2118 if (!check_share_info(uLevel,str2)) {
2119 return False;
2121 if (uLevel != 2) {
2122 return False;
2125 /* Do we have a string ? */
2126 if (skip_string(data,mdrcnt,data) == NULL) {
2127 return False;
2129 pull_ascii_fstring(sharename,data);
2130 snum = find_service(sharename);
2131 if (snum >= 0) { /* already exists */
2132 res = ERRfilexists;
2133 goto error_exit;
2136 if (mdrcnt < 28) {
2137 return False;
2140 /* only support disk share adds */
2141 if (SVAL(data,14)!=STYPE_DISKTREE) {
2142 return False;
2145 offset = IVAL(data, 16);
2146 if (offset >= mdrcnt) {
2147 res = ERRinvalidparam;
2148 goto error_exit;
2151 /* Do we have a string ? */
2152 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2153 return False;
2155 pull_ascii_fstring(comment, offset? (data+offset) : "");
2157 offset = IVAL(data, 26);
2159 if (offset >= mdrcnt) {
2160 res = ERRinvalidparam;
2161 goto error_exit;
2164 /* Do we have a string ? */
2165 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2166 return False;
2169 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2170 offset ? (data+offset) : "", &converted_size))
2172 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2173 strerror(errno)));
2176 if (!pathname) {
2177 return false;
2180 string_replace(sharename, '"', ' ');
2181 string_replace(pathname, '"', ' ');
2182 string_replace(comment, '"', ' ');
2184 cmdname = lp_add_share_cmd();
2186 if (!cmdname || *cmdname == '\0') {
2187 return False;
2190 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
2191 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
2192 pathname, comment) == -1) {
2193 return false;
2196 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
2198 if ((res = smbrun(command, NULL)) != 0) {
2199 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
2200 command, res ));
2201 SAFE_FREE(command);
2202 res = ERRnoaccess;
2203 goto error_exit;
2204 } else {
2205 SAFE_FREE(command);
2206 message_send_all(smbd_messaging_context(),
2207 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2210 *rparam_len = 6;
2211 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2212 if (!*rparam) {
2213 return False;
2215 SSVAL(*rparam,0,NERR_Success);
2216 SSVAL(*rparam,2,0); /* converter word */
2217 SSVAL(*rparam,4,*rdata_len);
2218 *rdata_len = 0;
2220 return True;
2222 error_exit:
2224 *rparam_len = 4;
2225 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2226 if (!*rparam) {
2227 return False;
2229 *rdata_len = 0;
2230 SSVAL(*rparam,0,res);
2231 SSVAL(*rparam,2,0);
2232 return True;
2235 /****************************************************************************
2236 view list of groups available
2237 ****************************************************************************/
2239 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2240 char *param, int tpscnt,
2241 char *data, int tdscnt,
2242 int mdrcnt,int mprcnt,
2243 char **rdata,char **rparam,
2244 int *rdata_len,int *rparam_len)
2246 int i;
2247 int errflags=0;
2248 int resume_context, cli_buf_size;
2249 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2250 char *str2 = skip_string(param,tpscnt,str1);
2251 char *p = skip_string(param,tpscnt,str2);
2253 uint32_t num_groups;
2254 uint32_t resume_handle;
2255 struct rpc_pipe_client *samr_pipe;
2256 struct policy_handle samr_handle, domain_handle;
2257 NTSTATUS status;
2259 if (!str1 || !str2 || !p) {
2260 return False;
2263 if (strcmp(str1,"WrLeh") != 0) {
2264 return False;
2267 /* parameters
2268 * W-> resume context (number of users to skip)
2269 * r -> return parameter pointer to receive buffer
2270 * L -> length of receive buffer
2271 * e -> return parameter number of entries
2272 * h -> return parameter total number of users
2275 if (strcmp("B21",str2) != 0) {
2276 return False;
2279 status = rpc_pipe_open_internal(
2280 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2281 conn->server_info, &samr_pipe);
2282 if (!NT_STATUS_IS_OK(status)) {
2283 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2284 nt_errstr(status)));
2285 return false;
2288 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2289 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2290 if (!NT_STATUS_IS_OK(status)) {
2291 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2292 nt_errstr(status)));
2293 return false;
2296 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2297 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2298 get_global_sam_sid(), &domain_handle);
2299 if (!NT_STATUS_IS_OK(status)) {
2300 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2301 nt_errstr(status)));
2302 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2303 return false;
2306 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2307 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2308 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2309 "%d\n", resume_context, cli_buf_size));
2311 *rdata_len = cli_buf_size;
2312 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2313 if (!*rdata) {
2314 return False;
2317 p = *rdata;
2319 errflags = NERR_Success;
2320 num_groups = 0;
2321 resume_handle = 0;
2323 while (true) {
2324 struct samr_SamArray *sam_entries;
2325 uint32_t num_entries;
2327 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2328 &domain_handle,
2329 &resume_handle,
2330 &sam_entries, 1,
2331 &num_entries);
2332 if (!NT_STATUS_IS_OK(status)) {
2333 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2334 "%s\n", nt_errstr(status)));
2335 break;
2338 if (num_entries == 0) {
2339 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2340 "no entries -- done\n"));
2341 break;
2344 for(i=0; i<num_entries; i++) {
2345 const char *name;
2347 name = sam_entries->entries[i].name.string;
2349 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2350 /* set overflow error */
2351 DEBUG(3,("overflow on entry %d group %s\n", i,
2352 name));
2353 errflags=234;
2354 break;
2357 /* truncate the name at 21 chars. */
2358 memset(p, 0, 21);
2359 strlcpy(p, name, 21);
2360 DEBUG(10,("adding entry %d group %s\n", i, p));
2361 p += 21;
2362 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2363 * idea why... */
2364 num_groups += 1;
2367 if (errflags != NERR_Success) {
2368 break;
2371 TALLOC_FREE(sam_entries);
2374 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2375 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2377 *rdata_len = PTR_DIFF(p,*rdata);
2379 *rparam_len = 8;
2380 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2381 if (!*rparam) {
2382 return False;
2384 SSVAL(*rparam, 0, errflags);
2385 SSVAL(*rparam, 2, 0); /* converter word */
2386 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2387 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2389 return(True);
2392 /*******************************************************************
2393 Get groups that a user is a member of.
2394 ******************************************************************/
2396 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2397 char *param, int tpscnt,
2398 char *data, int tdscnt,
2399 int mdrcnt,int mprcnt,
2400 char **rdata,char **rparam,
2401 int *rdata_len,int *rparam_len)
2403 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2404 char *str2 = skip_string(param,tpscnt,str1);
2405 char *UserName = skip_string(param,tpscnt,str2);
2406 char *p = skip_string(param,tpscnt,UserName);
2407 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2408 const char *level_string;
2409 int count=0;
2410 bool ret = False;
2411 uint32_t i;
2412 char *endp = NULL;
2414 struct rpc_pipe_client *samr_pipe;
2415 struct policy_handle samr_handle, domain_handle, user_handle;
2416 struct lsa_String name;
2417 struct lsa_Strings names;
2418 struct samr_Ids type, rid;
2419 struct samr_RidWithAttributeArray *rids;
2420 NTSTATUS status;
2422 if (!str1 || !str2 || !UserName || !p) {
2423 return False;
2426 *rparam_len = 8;
2427 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2428 if (!*rparam) {
2429 return False;
2432 /* check it's a supported varient */
2434 if ( strcmp(str1,"zWrLeh") != 0 )
2435 return False;
2437 switch( uLevel ) {
2438 case 0:
2439 level_string = "B21";
2440 break;
2441 default:
2442 return False;
2445 if (strcmp(level_string,str2) != 0)
2446 return False;
2448 *rdata_len = mdrcnt + 1024;
2449 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2450 if (!*rdata) {
2451 return False;
2454 SSVAL(*rparam,0,NERR_Success);
2455 SSVAL(*rparam,2,0); /* converter word */
2457 p = *rdata;
2458 endp = *rdata + *rdata_len;
2460 status = rpc_pipe_open_internal(
2461 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2462 conn->server_info, &samr_pipe);
2463 if (!NT_STATUS_IS_OK(status)) {
2464 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2465 nt_errstr(status)));
2466 return false;
2469 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2470 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2471 if (!NT_STATUS_IS_OK(status)) {
2472 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2473 nt_errstr(status)));
2474 return false;
2477 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2478 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2479 get_global_sam_sid(), &domain_handle);
2480 if (!NT_STATUS_IS_OK(status)) {
2481 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2482 nt_errstr(status)));
2483 goto close_sam;
2486 name.string = UserName;
2488 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2489 &domain_handle, 1, &name,
2490 &rid, &type);
2491 if (!NT_STATUS_IS_OK(status)) {
2492 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2493 nt_errstr(status)));
2494 goto close_domain;
2497 if (type.ids[0] != SID_NAME_USER) {
2498 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2499 sid_type_lookup(type.ids[0])));
2500 goto close_domain;
2503 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2504 &domain_handle,
2505 SAMR_USER_ACCESS_GET_GROUPS,
2506 rid.ids[0], &user_handle);
2507 if (!NT_STATUS_IS_OK(status)) {
2508 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2509 nt_errstr(status)));
2510 goto close_domain;
2513 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2514 &user_handle, &rids);
2515 if (!NT_STATUS_IS_OK(status)) {
2516 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2517 nt_errstr(status)));
2518 goto close_user;
2521 for (i=0; i<rids->count; i++) {
2523 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2524 &domain_handle,
2525 1, &rids->rids[i].rid,
2526 &names, &type);
2527 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2528 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2529 p += 21;
2530 count++;
2534 *rdata_len = PTR_DIFF(p,*rdata);
2536 SSVAL(*rparam,4,count); /* is this right?? */
2537 SSVAL(*rparam,6,count); /* is this right?? */
2539 ret = True;
2541 close_user:
2542 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2543 close_domain:
2544 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2545 close_sam:
2546 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2548 return ret;
2551 /*******************************************************************
2552 Get all users.
2553 ******************************************************************/
2555 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2556 char *param, int tpscnt,
2557 char *data, int tdscnt,
2558 int mdrcnt,int mprcnt,
2559 char **rdata,char **rparam,
2560 int *rdata_len,int *rparam_len)
2562 int count_sent=0;
2563 int num_users=0;
2564 int errflags=0;
2565 int i, resume_context, cli_buf_size;
2566 uint32_t resume_handle;
2568 struct rpc_pipe_client *samr_pipe;
2569 struct policy_handle samr_handle, domain_handle;
2570 NTSTATUS status;
2572 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2573 char *str2 = skip_string(param,tpscnt,str1);
2574 char *p = skip_string(param,tpscnt,str2);
2575 char *endp = NULL;
2577 if (!str1 || !str2 || !p) {
2578 return False;
2581 if (strcmp(str1,"WrLeh") != 0)
2582 return False;
2583 /* parameters
2584 * W-> resume context (number of users to skip)
2585 * r -> return parameter pointer to receive buffer
2586 * L -> length of receive buffer
2587 * e -> return parameter number of entries
2588 * h -> return parameter total number of users
2591 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2592 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2593 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2594 resume_context, cli_buf_size));
2596 *rparam_len = 8;
2597 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2598 if (!*rparam) {
2599 return False;
2602 /* check it's a supported varient */
2603 if (strcmp("B21",str2) != 0)
2604 return False;
2606 *rdata_len = cli_buf_size;
2607 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2608 if (!*rdata) {
2609 return False;
2612 p = *rdata;
2613 endp = *rdata + *rdata_len;
2615 status = rpc_pipe_open_internal(
2616 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2617 conn->server_info, &samr_pipe);
2618 if (!NT_STATUS_IS_OK(status)) {
2619 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2620 nt_errstr(status)));
2621 return false;
2624 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2625 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2626 if (!NT_STATUS_IS_OK(status)) {
2627 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2628 nt_errstr(status)));
2629 return false;
2632 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2633 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2634 get_global_sam_sid(), &domain_handle);
2635 if (!NT_STATUS_IS_OK(status)) {
2636 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2637 nt_errstr(status)));
2638 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2639 return false;
2642 errflags=NERR_Success;
2644 resume_handle = 0;
2646 while (true) {
2647 struct samr_SamArray *sam_entries;
2648 uint32_t num_entries;
2650 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2651 &domain_handle,
2652 &resume_handle,
2653 0, &sam_entries, 1,
2654 &num_entries);
2656 if (!NT_STATUS_IS_OK(status)) {
2657 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2658 "%s\n", nt_errstr(status)));
2659 break;
2662 if (num_entries == 0) {
2663 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2664 "no entries -- done\n"));
2665 break;
2668 for (i=0; i<num_entries; i++) {
2669 const char *name;
2671 name = sam_entries->entries[i].name.string;
2673 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2674 &&(strlen(name)<=21)) {
2675 strlcpy(p,name,PTR_DIFF(endp,p));
2676 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2677 "username %s\n",count_sent,p));
2678 p += 21;
2679 count_sent++;
2680 } else {
2681 /* set overflow error */
2682 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2683 "username %s\n",count_sent,name));
2684 errflags=234;
2685 break;
2689 if (errflags != NERR_Success) {
2690 break;
2693 TALLOC_FREE(sam_entries);
2696 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2697 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2699 *rdata_len = PTR_DIFF(p,*rdata);
2701 SSVAL(*rparam,0,errflags);
2702 SSVAL(*rparam,2,0); /* converter word */
2703 SSVAL(*rparam,4,count_sent); /* is this right?? */
2704 SSVAL(*rparam,6,num_users); /* is this right?? */
2706 return True;
2709 /****************************************************************************
2710 Get the time of day info.
2711 ****************************************************************************/
2713 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2714 char *param, int tpscnt,
2715 char *data, int tdscnt,
2716 int mdrcnt,int mprcnt,
2717 char **rdata,char **rparam,
2718 int *rdata_len,int *rparam_len)
2720 struct tm *t;
2721 time_t unixdate = time(NULL);
2722 char *p;
2724 *rparam_len = 4;
2725 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2726 if (!*rparam) {
2727 return False;
2730 *rdata_len = 21;
2731 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2732 if (!*rdata) {
2733 return False;
2736 SSVAL(*rparam,0,NERR_Success);
2737 SSVAL(*rparam,2,0); /* converter word */
2739 p = *rdata;
2741 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2742 by NT in a "net time" operation,
2743 it seems to ignore the one below */
2745 /* the client expects to get localtime, not GMT, in this bit
2746 (I think, this needs testing) */
2747 t = localtime(&unixdate);
2748 if (!t) {
2749 return False;
2752 SIVAL(p,4,0); /* msecs ? */
2753 SCVAL(p,8,t->tm_hour);
2754 SCVAL(p,9,t->tm_min);
2755 SCVAL(p,10,t->tm_sec);
2756 SCVAL(p,11,0); /* hundredths of seconds */
2757 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2758 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2759 SCVAL(p,16,t->tm_mday);
2760 SCVAL(p,17,t->tm_mon + 1);
2761 SSVAL(p,18,1900+t->tm_year);
2762 SCVAL(p,20,t->tm_wday);
2764 return True;
2767 /****************************************************************************
2768 Set the user password.
2769 *****************************************************************************/
2771 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2772 char *param, int tpscnt,
2773 char *data, int tdscnt,
2774 int mdrcnt,int mprcnt,
2775 char **rdata,char **rparam,
2776 int *rdata_len,int *rparam_len)
2778 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2779 char *p = NULL;
2780 fstring user;
2781 fstring pass1,pass2;
2783 /* Skip 2 strings. */
2784 p = skip_string(param,tpscnt,np);
2785 p = skip_string(param,tpscnt,p);
2787 if (!np || !p) {
2788 return False;
2791 /* Do we have a string ? */
2792 if (skip_string(param,tpscnt,p) == NULL) {
2793 return False;
2795 pull_ascii_fstring(user,p);
2797 p = skip_string(param,tpscnt,p);
2798 if (!p) {
2799 return False;
2802 memset(pass1,'\0',sizeof(pass1));
2803 memset(pass2,'\0',sizeof(pass2));
2805 * We use 31 here not 32 as we're checking
2806 * the last byte we want to access is safe.
2808 if (!is_offset_safe(param,tpscnt,p,31)) {
2809 return False;
2811 memcpy(pass1,p,16);
2812 memcpy(pass2,p+16,16);
2814 *rparam_len = 4;
2815 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2816 if (!*rparam) {
2817 return False;
2820 *rdata_len = 0;
2822 SSVAL(*rparam,0,NERR_badpass);
2823 SSVAL(*rparam,2,0); /* converter word */
2825 DEBUG(3,("Set password for <%s>\n",user));
2828 * Attempt to verify the old password against smbpasswd entries
2829 * Win98 clients send old and new password in plaintext for this call.
2833 auth_serversupplied_info *server_info = NULL;
2834 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2836 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2838 become_root();
2839 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2840 SSVAL(*rparam,0,NERR_Success);
2842 unbecome_root();
2844 TALLOC_FREE(server_info);
2846 data_blob_clear_free(&password);
2850 * If the plaintext change failed, attempt
2851 * the old encrypted method. NT will generate this
2852 * after trying the samr method. Note that this
2853 * method is done as a last resort as this
2854 * password change method loses the NT password hash
2855 * and cannot change the UNIX password as no plaintext
2856 * is received.
2859 if(SVAL(*rparam,0) != NERR_Success) {
2860 struct samu *hnd = NULL;
2862 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2863 become_root();
2864 if (change_lanman_password(hnd,(uchar *)pass2)) {
2865 SSVAL(*rparam,0,NERR_Success);
2867 unbecome_root();
2868 TALLOC_FREE(hnd);
2872 memset((char *)pass1,'\0',sizeof(fstring));
2873 memset((char *)pass2,'\0',sizeof(fstring));
2875 return(True);
2878 /****************************************************************************
2879 Set the user password (SamOEM version - gets plaintext).
2880 ****************************************************************************/
2882 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2883 char *param, int tpscnt,
2884 char *data, int tdscnt,
2885 int mdrcnt,int mprcnt,
2886 char **rdata,char **rparam,
2887 int *rdata_len,int *rparam_len)
2889 fstring user;
2890 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2891 *rparam_len = 2;
2892 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2893 if (!*rparam) {
2894 return False;
2897 if (!p) {
2898 return False;
2900 *rdata_len = 0;
2902 SSVAL(*rparam,0,NERR_badpass);
2905 * Check the parameter definition is correct.
2908 /* Do we have a string ? */
2909 if (skip_string(param,tpscnt,p) == 0) {
2910 return False;
2912 if(!strequal(p, "zsT")) {
2913 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2914 return False;
2916 p = skip_string(param, tpscnt, p);
2917 if (!p) {
2918 return False;
2921 /* Do we have a string ? */
2922 if (skip_string(param,tpscnt,p) == 0) {
2923 return False;
2925 if(!strequal(p, "B516B16")) {
2926 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2927 return False;
2929 p = skip_string(param,tpscnt,p);
2930 if (!p) {
2931 return False;
2933 /* Do we have a string ? */
2934 if (skip_string(param,tpscnt,p) == 0) {
2935 return False;
2937 p += pull_ascii_fstring(user,p);
2939 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2942 * Pass the user through the NT -> unix user mapping
2943 * function.
2946 (void)map_username(user);
2948 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2949 SSVAL(*rparam,0,NERR_Success);
2952 return(True);
2955 /****************************************************************************
2956 delete a print job
2957 Form: <W> <>
2958 ****************************************************************************/
2960 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2961 char *param, int tpscnt,
2962 char *data, int tdscnt,
2963 int mdrcnt,int mprcnt,
2964 char **rdata,char **rparam,
2965 int *rdata_len,int *rparam_len)
2967 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2968 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2969 char *str2 = skip_string(param,tpscnt,str1);
2970 char *p = skip_string(param,tpscnt,str2);
2971 uint32 jobid;
2972 int snum;
2973 fstring sharename;
2974 int errcode;
2975 WERROR werr = WERR_OK;
2977 if (!str1 || !str2 || !p) {
2978 return False;
2981 * We use 1 here not 2 as we're checking
2982 * the last byte we want to access is safe.
2984 if (!is_offset_safe(param,tpscnt,p,1)) {
2985 return False;
2987 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2988 return False;
2990 /* check it's a supported varient */
2991 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2992 return(False);
2994 *rparam_len = 4;
2995 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2996 if (!*rparam) {
2997 return False;
2999 *rdata_len = 0;
3001 if (!print_job_exists(sharename, jobid)) {
3002 errcode = NERR_JobNotFound;
3003 goto out;
3006 snum = lp_servicenumber( sharename);
3007 if (snum == -1) {
3008 errcode = NERR_DestNotFound;
3009 goto out;
3012 errcode = NERR_notsupported;
3014 switch (function) {
3015 case 81: /* delete */
3016 if (print_job_delete(conn->server_info, snum, jobid, &werr))
3017 errcode = NERR_Success;
3018 break;
3019 case 82: /* pause */
3020 if (print_job_pause(conn->server_info, snum, jobid, &werr))
3021 errcode = NERR_Success;
3022 break;
3023 case 83: /* resume */
3024 if (print_job_resume(conn->server_info, snum, jobid, &werr))
3025 errcode = NERR_Success;
3026 break;
3029 if (!W_ERROR_IS_OK(werr))
3030 errcode = W_ERROR_V(werr);
3032 out:
3033 SSVAL(*rparam,0,errcode);
3034 SSVAL(*rparam,2,0); /* converter word */
3036 return(True);
3039 /****************************************************************************
3040 Purge a print queue - or pause or resume it.
3041 ****************************************************************************/
3043 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3044 char *param, int tpscnt,
3045 char *data, int tdscnt,
3046 int mdrcnt,int mprcnt,
3047 char **rdata,char **rparam,
3048 int *rdata_len,int *rparam_len)
3050 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3051 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3052 char *str2 = skip_string(param,tpscnt,str1);
3053 char *QueueName = skip_string(param,tpscnt,str2);
3054 int errcode = NERR_notsupported;
3055 int snum;
3056 WERROR werr = WERR_OK;
3058 if (!str1 || !str2 || !QueueName) {
3059 return False;
3062 /* check it's a supported varient */
3063 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3064 return(False);
3066 *rparam_len = 4;
3067 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3068 if (!*rparam) {
3069 return False;
3071 *rdata_len = 0;
3073 if (skip_string(param,tpscnt,QueueName) == NULL) {
3074 return False;
3076 snum = print_queue_snum(QueueName);
3078 if (snum == -1) {
3079 errcode = NERR_JobNotFound;
3080 goto out;
3083 switch (function) {
3084 case 74: /* Pause queue */
3085 werr = print_queue_pause(conn->server_info, snum);
3086 break;
3087 case 75: /* Resume queue */
3088 werr = print_queue_resume(conn->server_info, snum);
3089 break;
3090 case 103: /* Purge */
3091 werr = print_queue_purge(conn->server_info, snum);
3092 break;
3093 default:
3094 werr = WERR_NOT_SUPPORTED;
3095 break;
3098 errcode = W_ERROR_V(werr);
3100 out:
3101 SSVAL(*rparam,0,errcode);
3102 SSVAL(*rparam,2,0); /* converter word */
3104 return(True);
3107 /****************************************************************************
3108 set the property of a print job (undocumented?)
3109 ? function = 0xb -> set name of print job
3110 ? function = 0x6 -> move print job up/down
3111 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3112 or <WWsTP> <WB21BB16B10zWWzDDz>
3113 ****************************************************************************/
3115 static int check_printjob_info(struct pack_desc* desc,
3116 int uLevel, char* id)
3118 desc->subformat = NULL;
3119 switch( uLevel ) {
3120 case 0: desc->format = "W"; break;
3121 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3122 case 2: desc->format = "WWzWWDDzz"; break;
3123 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3124 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3125 default:
3126 DEBUG(0,("check_printjob_info: invalid level %d\n",
3127 uLevel ));
3128 return False;
3130 if (id == NULL || strcmp(desc->format,id) != 0) {
3131 DEBUG(0,("check_printjob_info: invalid format %s\n",
3132 id ? id : "<NULL>" ));
3133 return False;
3135 return True;
3138 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3139 char *param, int tpscnt,
3140 char *data, int tdscnt,
3141 int mdrcnt,int mprcnt,
3142 char **rdata,char **rparam,
3143 int *rdata_len,int *rparam_len)
3145 struct pack_desc desc;
3146 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3147 char *str2 = skip_string(param,tpscnt,str1);
3148 char *p = skip_string(param,tpscnt,str2);
3149 uint32 jobid;
3150 fstring sharename;
3151 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3152 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3153 int place, errcode;
3155 if (!str1 || !str2 || !p) {
3156 return False;
3159 * We use 1 here not 2 as we're checking
3160 * the last byte we want to access is safe.
3162 if (!is_offset_safe(param,tpscnt,p,1)) {
3163 return False;
3165 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3166 return False;
3167 *rparam_len = 4;
3168 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3169 if (!*rparam) {
3170 return False;
3173 if (!share_defined(sharename)) {
3174 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
3175 sharename));
3176 return False;
3179 *rdata_len = 0;
3181 /* check it's a supported varient */
3182 if ((strcmp(str1,"WWsTP")) ||
3183 (!check_printjob_info(&desc,uLevel,str2)))
3184 return(False);
3186 if (!print_job_exists(sharename, jobid)) {
3187 errcode=NERR_JobNotFound;
3188 goto out;
3191 errcode = NERR_notsupported;
3193 switch (function) {
3194 case 0x6:
3195 /* change job place in the queue,
3196 data gives the new place */
3197 place = SVAL(data,0);
3198 if (print_job_set_place(sharename, jobid, place)) {
3199 errcode=NERR_Success;
3201 break;
3203 case 0xb:
3204 /* change print job name, data gives the name */
3205 if (print_job_set_name(sharename, jobid, data)) {
3206 errcode=NERR_Success;
3208 break;
3210 default:
3211 return False;
3214 out:
3215 SSVALS(*rparam,0,errcode);
3216 SSVAL(*rparam,2,0); /* converter word */
3218 return(True);
3222 /****************************************************************************
3223 Get info about the server.
3224 ****************************************************************************/
3226 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3227 char *param, int tpscnt,
3228 char *data, int tdscnt,
3229 int mdrcnt,int mprcnt,
3230 char **rdata,char **rparam,
3231 int *rdata_len,int *rparam_len)
3233 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3234 char *str2 = skip_string(param,tpscnt,str1);
3235 char *p = skip_string(param,tpscnt,str2);
3236 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3237 char *p2;
3238 int struct_len;
3240 if (!str1 || !str2 || !p) {
3241 return False;
3244 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3246 /* check it's a supported varient */
3247 if (!prefix_ok(str1,"WrLh")) {
3248 return False;
3251 switch( uLevel ) {
3252 case 0:
3253 if (strcmp(str2,"B16") != 0) {
3254 return False;
3256 struct_len = 16;
3257 break;
3258 case 1:
3259 if (strcmp(str2,"B16BBDz") != 0) {
3260 return False;
3262 struct_len = 26;
3263 break;
3264 case 2:
3265 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3266 return False;
3268 struct_len = 134;
3269 break;
3270 case 3:
3271 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3272 return False;
3274 struct_len = 144;
3275 break;
3276 case 20:
3277 if (strcmp(str2,"DN") != 0) {
3278 return False;
3280 struct_len = 6;
3281 break;
3282 case 50:
3283 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3284 return False;
3286 struct_len = 42;
3287 break;
3288 default:
3289 return False;
3292 *rdata_len = mdrcnt;
3293 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3294 if (!*rdata) {
3295 return False;
3298 p = *rdata;
3299 p2 = p + struct_len;
3300 if (uLevel != 20) {
3301 srvstr_push(NULL, 0, p,global_myname(),16,
3302 STR_ASCII|STR_UPPER|STR_TERMINATE);
3304 p += 16;
3305 if (uLevel > 0) {
3306 struct srv_info_struct *servers=NULL;
3307 int i,count;
3308 char *comment = NULL;
3309 TALLOC_CTX *ctx = talloc_tos();
3310 uint32 servertype= lp_default_server_announce();
3312 comment = talloc_strdup(ctx,lp_serverstring());
3313 if (!comment) {
3314 return false;
3317 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3318 for (i=0;i<count;i++) {
3319 if (strequal(servers[i].name,global_myname())) {
3320 servertype = servers[i].type;
3321 TALLOC_FREE(comment);
3322 comment = talloc_strdup(ctx,
3323 servers[i].comment);
3324 if (comment) {
3325 return false;
3331 SAFE_FREE(servers);
3333 SCVAL(p,0,lp_major_announce_version());
3334 SCVAL(p,1,lp_minor_announce_version());
3335 SIVAL(p,2,servertype);
3337 if (mdrcnt == struct_len) {
3338 SIVAL(p,6,0);
3339 } else {
3340 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3341 comment = talloc_sub_advanced(
3342 ctx,
3343 lp_servicename(SNUM(conn)),
3344 conn->server_info->unix_name,
3345 conn->connectpath,
3346 conn->server_info->utok.gid,
3347 conn->server_info->sanitized_username,
3348 pdb_get_domain(conn->server_info->sam_account),
3349 comment);
3350 if (comment) {
3351 return false;
3353 if (mdrcnt - struct_len <= 0) {
3354 return false;
3356 push_ascii(p2,
3357 comment,
3358 MIN(mdrcnt - struct_len,
3359 MAX_SERVER_STRING_LENGTH),
3360 STR_TERMINATE);
3361 p2 = skip_string(*rdata,*rdata_len,p2);
3362 if (!p2) {
3363 return False;
3368 if (uLevel > 1) {
3369 return False; /* not yet implemented */
3372 *rdata_len = PTR_DIFF(p2,*rdata);
3374 *rparam_len = 6;
3375 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3376 if (!*rparam) {
3377 return False;
3379 SSVAL(*rparam,0,NERR_Success);
3380 SSVAL(*rparam,2,0); /* converter word */
3381 SSVAL(*rparam,4,*rdata_len);
3383 return True;
3386 /****************************************************************************
3387 Get info about the server.
3388 ****************************************************************************/
3390 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3391 char *param, int tpscnt,
3392 char *data, int tdscnt,
3393 int mdrcnt,int mprcnt,
3394 char **rdata,char **rparam,
3395 int *rdata_len,int *rparam_len)
3397 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3398 char *str2 = skip_string(param,tpscnt,str1);
3399 char *p = skip_string(param,tpscnt,str2);
3400 char *p2;
3401 char *endp;
3402 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3404 if (!str1 || !str2 || !p) {
3405 return False;
3408 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3410 *rparam_len = 6;
3411 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3412 if (!*rparam) {
3413 return False;
3416 /* check it's a supported varient */
3417 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3418 return False;
3421 *rdata_len = mdrcnt + 1024;
3422 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3423 if (!*rdata) {
3424 return False;
3427 SSVAL(*rparam,0,NERR_Success);
3428 SSVAL(*rparam,2,0); /* converter word */
3430 p = *rdata;
3431 endp = *rdata + *rdata_len;
3433 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3434 if (!p2) {
3435 return False;
3438 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3439 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3440 strupper_m(p2);
3441 p2 = skip_string(*rdata,*rdata_len,p2);
3442 if (!p2) {
3443 return False;
3445 p += 4;
3447 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3448 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3449 p2 = skip_string(*rdata,*rdata_len,p2);
3450 if (!p2) {
3451 return False;
3453 p += 4;
3455 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3456 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3457 strupper_m(p2);
3458 p2 = skip_string(*rdata,*rdata_len,p2);
3459 if (!p2) {
3460 return False;
3462 p += 4;
3464 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3465 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3466 p += 2;
3468 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3469 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3470 p2 = skip_string(*rdata,*rdata_len,p2);
3471 if (!p2) {
3472 return False;
3474 p += 4;
3476 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3477 strlcpy(p2,"",PTR_DIFF(endp,p2));
3478 p2 = skip_string(*rdata,*rdata_len,p2);
3479 if (!p2) {
3480 return False;
3482 p += 4;
3484 *rdata_len = PTR_DIFF(p2,*rdata);
3486 SSVAL(*rparam,4,*rdata_len);
3488 return True;
3491 /****************************************************************************
3492 get info about a user
3494 struct user_info_11 {
3495 char usri11_name[21]; 0-20
3496 char usri11_pad; 21
3497 char *usri11_comment; 22-25
3498 char *usri11_usr_comment; 26-29
3499 unsigned short usri11_priv; 30-31
3500 unsigned long usri11_auth_flags; 32-35
3501 long usri11_password_age; 36-39
3502 char *usri11_homedir; 40-43
3503 char *usri11_parms; 44-47
3504 long usri11_last_logon; 48-51
3505 long usri11_last_logoff; 52-55
3506 unsigned short usri11_bad_pw_count; 56-57
3507 unsigned short usri11_num_logons; 58-59
3508 char *usri11_logon_server; 60-63
3509 unsigned short usri11_country_code; 64-65
3510 char *usri11_workstations; 66-69
3511 unsigned long usri11_max_storage; 70-73
3512 unsigned short usri11_units_per_week; 74-75
3513 unsigned char *usri11_logon_hours; 76-79
3514 unsigned short usri11_code_page; 80-81
3517 where:
3519 usri11_name specifies the user name for which information is retrieved
3521 usri11_pad aligns the next data structure element to a word boundary
3523 usri11_comment is a null terminated ASCII comment
3525 usri11_user_comment is a null terminated ASCII comment about the user
3527 usri11_priv specifies the level of the privilege assigned to the user.
3528 The possible values are:
3530 Name Value Description
3531 USER_PRIV_GUEST 0 Guest privilege
3532 USER_PRIV_USER 1 User privilege
3533 USER_PRV_ADMIN 2 Administrator privilege
3535 usri11_auth_flags specifies the account operator privileges. The
3536 possible values are:
3538 Name Value Description
3539 AF_OP_PRINT 0 Print operator
3542 Leach, Naik [Page 28]
3546 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3549 AF_OP_COMM 1 Communications operator
3550 AF_OP_SERVER 2 Server operator
3551 AF_OP_ACCOUNTS 3 Accounts operator
3554 usri11_password_age specifies how many seconds have elapsed since the
3555 password was last changed.
3557 usri11_home_dir points to a null terminated ASCII string that contains
3558 the path name of the user's home directory.
3560 usri11_parms points to a null terminated ASCII string that is set
3561 aside for use by applications.
3563 usri11_last_logon specifies the time when the user last logged on.
3564 This value is stored as the number of seconds elapsed since
3565 00:00:00, January 1, 1970.
3567 usri11_last_logoff specifies the time when the user last logged off.
3568 This value is stored as the number of seconds elapsed since
3569 00:00:00, January 1, 1970. A value of 0 means the last logoff
3570 time is unknown.
3572 usri11_bad_pw_count specifies the number of incorrect passwords
3573 entered since the last successful logon.
3575 usri11_log1_num_logons specifies the number of times this user has
3576 logged on. A value of -1 means the number of logons is unknown.
3578 usri11_logon_server points to a null terminated ASCII string that
3579 contains the name of the server to which logon requests are sent.
3580 A null string indicates logon requests should be sent to the
3581 domain controller.
3583 usri11_country_code specifies the country code for the user's language
3584 of choice.
3586 usri11_workstations points to a null terminated ASCII string that
3587 contains the names of workstations the user may log on from.
3588 There may be up to 8 workstations, with the names separated by
3589 commas. A null strings indicates there are no restrictions.
3591 usri11_max_storage specifies the maximum amount of disk space the user
3592 can occupy. A value of 0xffffffff indicates there are no
3593 restrictions.
3595 usri11_units_per_week specifies the equal number of time units into
3596 which a week is divided. This value must be equal to 168.
3598 usri11_logon_hours points to a 21 byte (168 bits) string that
3599 specifies the time during which the user can log on. Each bit
3600 represents one unique hour in a week. The first bit (bit 0, word
3601 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3605 Leach, Naik [Page 29]
3609 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3612 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3613 are no restrictions.
3615 usri11_code_page specifies the code page for the user's language of
3616 choice
3618 All of the pointers in this data structure need to be treated
3619 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3620 to be ignored. The converter word returned in the parameters section
3621 needs to be subtracted from the lower 16 bits to calculate an offset
3622 into the return buffer where this ASCII string resides.
3624 There is no auxiliary data in the response.
3626 ****************************************************************************/
3628 #define usri11_name 0
3629 #define usri11_pad 21
3630 #define usri11_comment 22
3631 #define usri11_usr_comment 26
3632 #define usri11_full_name 30
3633 #define usri11_priv 34
3634 #define usri11_auth_flags 36
3635 #define usri11_password_age 40
3636 #define usri11_homedir 44
3637 #define usri11_parms 48
3638 #define usri11_last_logon 52
3639 #define usri11_last_logoff 56
3640 #define usri11_bad_pw_count 60
3641 #define usri11_num_logons 62
3642 #define usri11_logon_server 64
3643 #define usri11_country_code 68
3644 #define usri11_workstations 70
3645 #define usri11_max_storage 74
3646 #define usri11_units_per_week 78
3647 #define usri11_logon_hours 80
3648 #define usri11_code_page 84
3649 #define usri11_end 86
3651 #define USER_PRIV_GUEST 0
3652 #define USER_PRIV_USER 1
3653 #define USER_PRIV_ADMIN 2
3655 #define AF_OP_PRINT 0
3656 #define AF_OP_COMM 1
3657 #define AF_OP_SERVER 2
3658 #define AF_OP_ACCOUNTS 3
3661 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3662 char *param, int tpscnt,
3663 char *data, int tdscnt,
3664 int mdrcnt,int mprcnt,
3665 char **rdata,char **rparam,
3666 int *rdata_len,int *rparam_len)
3668 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3669 char *str2 = skip_string(param,tpscnt,str1);
3670 char *UserName = skip_string(param,tpscnt,str2);
3671 char *p = skip_string(param,tpscnt,UserName);
3672 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3673 char *p2;
3674 char *endp;
3675 const char *level_string;
3677 /* get NIS home of a previously validated user - simeon */
3678 /* With share level security vuid will always be zero.
3679 Don't depend on vuser being non-null !!. JRA */
3680 user_struct *vuser = get_valid_user_struct(vuid);
3681 if(vuser != NULL) {
3682 DEBUG(3,(" Username of UID %d is %s\n",
3683 (int)vuser->server_info->utok.uid,
3684 vuser->server_info->unix_name));
3687 if (!str1 || !str2 || !UserName || !p) {
3688 return False;
3691 *rparam_len = 6;
3692 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3693 if (!*rparam) {
3694 return False;
3697 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3699 /* check it's a supported variant */
3700 if (strcmp(str1,"zWrLh") != 0) {
3701 return False;
3703 switch( uLevel ) {
3704 case 0: level_string = "B21"; break;
3705 case 1: level_string = "B21BB16DWzzWz"; break;
3706 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3707 case 10: level_string = "B21Bzzz"; break;
3708 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3709 default: return False;
3712 if (strcmp(level_string,str2) != 0) {
3713 return False;
3716 *rdata_len = mdrcnt + 1024;
3717 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3718 if (!*rdata) {
3719 return False;
3722 SSVAL(*rparam,0,NERR_Success);
3723 SSVAL(*rparam,2,0); /* converter word */
3725 p = *rdata;
3726 endp = *rdata + *rdata_len;
3727 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3728 if (!p2) {
3729 return False;
3732 memset(p,0,21);
3733 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3735 if (uLevel > 0) {
3736 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3737 *p2 = 0;
3740 if (uLevel >= 10) {
3741 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3742 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3743 p2 = skip_string(*rdata,*rdata_len,p2);
3744 if (!p2) {
3745 return False;
3748 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3749 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3750 p2 = skip_string(*rdata,*rdata_len,p2);
3751 if (!p2) {
3752 return False;
3755 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3756 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3757 strlcpy(p2,((vuser != NULL)
3758 ? pdb_get_fullname(vuser->server_info->sam_account)
3759 : UserName),PTR_DIFF(endp,p2));
3760 p2 = skip_string(*rdata,*rdata_len,p2);
3761 if (!p2) {
3762 return False;
3766 if (uLevel == 11) {
3767 const char *homedir = "";
3768 if (vuser != NULL) {
3769 homedir = pdb_get_homedir(
3770 vuser->server_info->sam_account);
3772 /* modelled after NTAS 3.51 reply */
3773 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3774 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3775 SIVALS(p,usri11_password_age,-1); /* password age */
3776 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3777 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3778 p2 = skip_string(*rdata,*rdata_len,p2);
3779 if (!p2) {
3780 return False;
3782 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3783 strlcpy(p2,"",PTR_DIFF(endp,p2));
3784 p2 = skip_string(*rdata,*rdata_len,p2);
3785 if (!p2) {
3786 return False;
3788 SIVAL(p,usri11_last_logon,0); /* last logon */
3789 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3790 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3791 SSVALS(p,usri11_num_logons,-1); /* num logons */
3792 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3793 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3794 p2 = skip_string(*rdata,*rdata_len,p2);
3795 if (!p2) {
3796 return False;
3798 SSVAL(p,usri11_country_code,0); /* country code */
3800 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3801 strlcpy(p2,"",PTR_DIFF(endp,p2));
3802 p2 = skip_string(*rdata,*rdata_len,p2);
3803 if (!p2) {
3804 return False;
3807 SIVALS(p,usri11_max_storage,-1); /* max storage */
3808 SSVAL(p,usri11_units_per_week,168); /* units per week */
3809 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3811 /* a simple way to get logon hours at all times. */
3812 memset(p2,0xff,21);
3813 SCVAL(p2,21,0); /* fix zero termination */
3814 p2 = skip_string(*rdata,*rdata_len,p2);
3815 if (!p2) {
3816 return False;
3819 SSVAL(p,usri11_code_page,0); /* code page */
3822 if (uLevel == 1 || uLevel == 2) {
3823 memset(p+22,' ',16); /* password */
3824 SIVALS(p,38,-1); /* password age */
3825 SSVAL(p,42,
3826 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3827 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3828 strlcpy(p2, vuser ? pdb_get_homedir(
3829 vuser->server_info->sam_account) : "",
3830 PTR_DIFF(endp,p2));
3831 p2 = skip_string(*rdata,*rdata_len,p2);
3832 if (!p2) {
3833 return False;
3835 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3836 *p2++ = 0;
3837 SSVAL(p,52,0); /* flags */
3838 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3839 strlcpy(p2, vuser ? pdb_get_logon_script(
3840 vuser->server_info->sam_account) : "",
3841 PTR_DIFF(endp,p2));
3842 p2 = skip_string(*rdata,*rdata_len,p2);
3843 if (!p2) {
3844 return False;
3846 if (uLevel == 2) {
3847 SIVAL(p,60,0); /* auth_flags */
3848 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3849 strlcpy(p2,((vuser != NULL)
3850 ? pdb_get_fullname(vuser->server_info->sam_account)
3851 : UserName),PTR_DIFF(endp,p2));
3852 p2 = skip_string(*rdata,*rdata_len,p2);
3853 if (!p2) {
3854 return False;
3856 SIVAL(p,68,0); /* urs_comment */
3857 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3858 strlcpy(p2,"",PTR_DIFF(endp,p2));
3859 p2 = skip_string(*rdata,*rdata_len,p2);
3860 if (!p2) {
3861 return False;
3863 SIVAL(p,76,0); /* workstations */
3864 SIVAL(p,80,0); /* last_logon */
3865 SIVAL(p,84,0); /* last_logoff */
3866 SIVALS(p,88,-1); /* acct_expires */
3867 SIVALS(p,92,-1); /* max_storage */
3868 SSVAL(p,96,168); /* units_per_week */
3869 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3870 memset(p2,-1,21);
3871 p2 += 21;
3872 SSVALS(p,102,-1); /* bad_pw_count */
3873 SSVALS(p,104,-1); /* num_logons */
3874 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3876 TALLOC_CTX *ctx = talloc_tos();
3877 int space_rem = *rdata_len - (p2 - *rdata);
3878 char *tmp;
3880 if (space_rem <= 0) {
3881 return false;
3883 tmp = talloc_strdup(ctx, "\\\\%L");
3884 if (!tmp) {
3885 return false;
3887 tmp = talloc_sub_basic(ctx,
3890 tmp);
3891 if (!tmp) {
3892 return false;
3895 push_ascii(p2,
3896 tmp,
3897 space_rem,
3898 STR_TERMINATE);
3900 p2 = skip_string(*rdata,*rdata_len,p2);
3901 if (!p2) {
3902 return False;
3904 SSVAL(p,110,49); /* country_code */
3905 SSVAL(p,112,860); /* code page */
3909 *rdata_len = PTR_DIFF(p2,*rdata);
3911 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3913 return(True);
3916 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3917 char *param, int tpscnt,
3918 char *data, int tdscnt,
3919 int mdrcnt,int mprcnt,
3920 char **rdata,char **rparam,
3921 int *rdata_len,int *rparam_len)
3923 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3924 char *str2 = skip_string(param,tpscnt,str1);
3925 char *p = skip_string(param,tpscnt,str2);
3926 int uLevel;
3927 struct pack_desc desc;
3928 char* name;
3929 /* With share level security vuid will always be zero.
3930 Don't depend on vuser being non-null !!. JRA */
3931 user_struct *vuser = get_valid_user_struct(vuid);
3933 if (!str1 || !str2 || !p) {
3934 return False;
3937 if(vuser != NULL) {
3938 DEBUG(3,(" Username of UID %d is %s\n",
3939 (int)vuser->server_info->utok.uid,
3940 vuser->server_info->unix_name));
3943 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3944 name = get_safe_str_ptr(param,tpscnt,p,2);
3945 if (!name) {
3946 return False;
3949 memset((char *)&desc,'\0',sizeof(desc));
3951 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3953 /* check it's a supported varient */
3954 if (strcmp(str1,"OOWb54WrLh") != 0) {
3955 return False;
3957 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3958 return False;
3960 if (mdrcnt > 0) {
3961 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3962 if (!*rdata) {
3963 return False;
3967 desc.base = *rdata;
3968 desc.buflen = mdrcnt;
3969 desc.subformat = NULL;
3970 desc.format = str2;
3972 if (init_package(&desc,1,0)) {
3973 PACKI(&desc,"W",0); /* code */
3974 PACKS(&desc,"B21",name); /* eff. name */
3975 PACKS(&desc,"B",""); /* pad */
3976 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3977 PACKI(&desc,"D",0); /* auth flags XXX */
3978 PACKI(&desc,"W",0); /* num logons */
3979 PACKI(&desc,"W",0); /* bad pw count */
3980 PACKI(&desc,"D",0); /* last logon */
3981 PACKI(&desc,"D",-1); /* last logoff */
3982 PACKI(&desc,"D",-1); /* logoff time */
3983 PACKI(&desc,"D",-1); /* kickoff time */
3984 PACKI(&desc,"D",0); /* password age */
3985 PACKI(&desc,"D",0); /* password can change */
3986 PACKI(&desc,"D",-1); /* password must change */
3989 fstring mypath;
3990 fstrcpy(mypath,"\\\\");
3991 fstrcat(mypath,get_local_machine_name());
3992 strupper_m(mypath);
3993 PACKS(&desc,"z",mypath); /* computer */
3996 PACKS(&desc,"z",lp_workgroup());/* domain */
3997 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3998 vuser->server_info->sam_account) : ""); /* script path */
3999 PACKI(&desc,"D",0x00000000); /* reserved */
4002 *rdata_len = desc.usedlen;
4003 *rparam_len = 6;
4004 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4005 if (!*rparam) {
4006 return False;
4008 SSVALS(*rparam,0,desc.errcode);
4009 SSVAL(*rparam,2,0);
4010 SSVAL(*rparam,4,desc.neededlen);
4012 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4014 return True;
4017 /****************************************************************************
4018 api_WAccessGetUserPerms
4019 ****************************************************************************/
4021 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4022 char *param, int tpscnt,
4023 char *data, int tdscnt,
4024 int mdrcnt,int mprcnt,
4025 char **rdata,char **rparam,
4026 int *rdata_len,int *rparam_len)
4028 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4029 char *str2 = skip_string(param,tpscnt,str1);
4030 char *user = skip_string(param,tpscnt,str2);
4031 char *resource = skip_string(param,tpscnt,user);
4033 if (!str1 || !str2 || !user || !resource) {
4034 return False;
4037 if (skip_string(param,tpscnt,resource) == NULL) {
4038 return False;
4040 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4042 /* check it's a supported varient */
4043 if (strcmp(str1,"zzh") != 0) {
4044 return False;
4046 if (strcmp(str2,"") != 0) {
4047 return False;
4050 *rparam_len = 6;
4051 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4052 if (!*rparam) {
4053 return False;
4055 SSVALS(*rparam,0,0); /* errorcode */
4056 SSVAL(*rparam,2,0); /* converter word */
4057 SSVAL(*rparam,4,0x7f); /* permission flags */
4059 return True;
4062 /****************************************************************************
4063 api_WPrintJobEnumerate
4064 ****************************************************************************/
4066 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4067 char *param, int tpscnt,
4068 char *data, int tdscnt,
4069 int mdrcnt,int mprcnt,
4070 char **rdata,char **rparam,
4071 int *rdata_len,int *rparam_len)
4073 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4074 char *str2 = skip_string(param,tpscnt,str1);
4075 char *p = skip_string(param,tpscnt,str2);
4076 int uLevel;
4077 int count;
4078 int i;
4079 int snum;
4080 fstring sharename;
4081 uint32 jobid;
4082 struct pack_desc desc;
4083 print_queue_struct *queue=NULL;
4084 print_status_struct status;
4085 char *tmpdata=NULL;
4087 if (!str1 || !str2 || !p) {
4088 return False;
4091 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4093 memset((char *)&desc,'\0',sizeof(desc));
4094 memset((char *)&status,'\0',sizeof(status));
4096 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4098 /* check it's a supported varient */
4099 if (strcmp(str1,"WWrLh") != 0) {
4100 return False;
4102 if (!check_printjob_info(&desc,uLevel,str2)) {
4103 return False;
4106 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4107 return False;
4110 snum = lp_servicenumber( sharename);
4111 if (snum < 0 || !VALID_SNUM(snum)) {
4112 return(False);
4115 count = print_queue_status(snum,&queue,&status);
4116 for (i = 0; i < count; i++) {
4117 if (queue[i].job == jobid) {
4118 break;
4122 if (mdrcnt > 0) {
4123 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4124 if (!*rdata) {
4125 return False;
4127 desc.base = *rdata;
4128 desc.buflen = mdrcnt;
4129 } else {
4131 * Don't return data but need to get correct length
4132 * init_package will return wrong size if buflen=0
4134 desc.buflen = getlen(desc.format);
4135 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4138 if (init_package(&desc,1,0)) {
4139 if (i < count) {
4140 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4141 *rdata_len = desc.usedlen;
4142 } else {
4143 desc.errcode = NERR_JobNotFound;
4144 *rdata_len = 0;
4148 *rparam_len = 6;
4149 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4150 if (!*rparam) {
4151 return False;
4153 SSVALS(*rparam,0,desc.errcode);
4154 SSVAL(*rparam,2,0);
4155 SSVAL(*rparam,4,desc.neededlen);
4157 SAFE_FREE(queue);
4158 SAFE_FREE(tmpdata);
4160 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4162 return True;
4165 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4166 char *param, int tpscnt,
4167 char *data, int tdscnt,
4168 int mdrcnt,int mprcnt,
4169 char **rdata,char **rparam,
4170 int *rdata_len,int *rparam_len)
4172 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4173 char *str2 = skip_string(param,tpscnt,str1);
4174 char *p = skip_string(param,tpscnt,str2);
4175 char *name = p;
4176 int uLevel;
4177 int count;
4178 int i, succnt=0;
4179 int snum;
4180 struct pack_desc desc;
4181 print_queue_struct *queue=NULL;
4182 print_status_struct status;
4184 if (!str1 || !str2 || !p) {
4185 return False;
4188 memset((char *)&desc,'\0',sizeof(desc));
4189 memset((char *)&status,'\0',sizeof(status));
4191 p = skip_string(param,tpscnt,p);
4192 if (!p) {
4193 return False;
4195 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4197 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4199 /* check it's a supported variant */
4200 if (strcmp(str1,"zWrLeh") != 0) {
4201 return False;
4204 if (uLevel > 2) {
4205 return False; /* defined only for uLevel 0,1,2 */
4208 if (!check_printjob_info(&desc,uLevel,str2)) {
4209 return False;
4212 snum = find_service(name);
4213 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4214 return False;
4217 count = print_queue_status(snum,&queue,&status);
4218 if (mdrcnt > 0) {
4219 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4220 if (!*rdata) {
4221 return False;
4224 desc.base = *rdata;
4225 desc.buflen = mdrcnt;
4227 if (init_package(&desc,count,0)) {
4228 succnt = 0;
4229 for (i = 0; i < count; i++) {
4230 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4231 if (desc.errcode == NERR_Success) {
4232 succnt = i+1;
4237 *rdata_len = desc.usedlen;
4239 *rparam_len = 8;
4240 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4241 if (!*rparam) {
4242 return False;
4244 SSVALS(*rparam,0,desc.errcode);
4245 SSVAL(*rparam,2,0);
4246 SSVAL(*rparam,4,succnt);
4247 SSVAL(*rparam,6,count);
4249 SAFE_FREE(queue);
4251 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4253 return True;
4256 static int check_printdest_info(struct pack_desc* desc,
4257 int uLevel, char* id)
4259 desc->subformat = NULL;
4260 switch( uLevel ) {
4261 case 0:
4262 desc->format = "B9";
4263 break;
4264 case 1:
4265 desc->format = "B9B21WWzW";
4266 break;
4267 case 2:
4268 desc->format = "z";
4269 break;
4270 case 3:
4271 desc->format = "zzzWWzzzWW";
4272 break;
4273 default:
4274 DEBUG(0,("check_printdest_info: invalid level %d\n",
4275 uLevel));
4276 return False;
4278 if (id == NULL || strcmp(desc->format,id) != 0) {
4279 DEBUG(0,("check_printdest_info: invalid string %s\n",
4280 id ? id : "<NULL>" ));
4281 return False;
4283 return True;
4286 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4287 struct pack_desc* desc)
4289 char buf[100];
4291 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4292 buf[sizeof(buf)-1] = 0;
4293 strupper_m(buf);
4295 if (uLevel <= 1) {
4296 PACKS(desc,"B9",buf); /* szName */
4297 if (uLevel == 1) {
4298 PACKS(desc,"B21",""); /* szUserName */
4299 PACKI(desc,"W",0); /* uJobId */
4300 PACKI(desc,"W",0); /* fsStatus */
4301 PACKS(desc,"z",""); /* pszStatus */
4302 PACKI(desc,"W",0); /* time */
4306 if (uLevel == 2 || uLevel == 3) {
4307 PACKS(desc,"z",buf); /* pszPrinterName */
4308 if (uLevel == 3) {
4309 PACKS(desc,"z",""); /* pszUserName */
4310 PACKS(desc,"z",""); /* pszLogAddr */
4311 PACKI(desc,"W",0); /* uJobId */
4312 PACKI(desc,"W",0); /* fsStatus */
4313 PACKS(desc,"z",""); /* pszStatus */
4314 PACKS(desc,"z",""); /* pszComment */
4315 PACKS(desc,"z","NULL"); /* pszDrivers */
4316 PACKI(desc,"W",0); /* time */
4317 PACKI(desc,"W",0); /* pad1 */
4322 static bool api_WPrintDestGetInfo(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)
4329 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4330 char *str2 = skip_string(param,tpscnt,str1);
4331 char *p = skip_string(param,tpscnt,str2);
4332 char* PrinterName = p;
4333 int uLevel;
4334 struct pack_desc desc;
4335 int snum;
4336 char *tmpdata=NULL;
4338 if (!str1 || !str2 || !p) {
4339 return False;
4342 memset((char *)&desc,'\0',sizeof(desc));
4344 p = skip_string(param,tpscnt,p);
4345 if (!p) {
4346 return False;
4348 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4350 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4352 /* check it's a supported varient */
4353 if (strcmp(str1,"zWrLh") != 0) {
4354 return False;
4356 if (!check_printdest_info(&desc,uLevel,str2)) {
4357 return False;
4360 snum = find_service(PrinterName);
4361 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4362 *rdata_len = 0;
4363 desc.errcode = NERR_DestNotFound;
4364 desc.neededlen = 0;
4365 } else {
4366 if (mdrcnt > 0) {
4367 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4368 if (!*rdata) {
4369 return False;
4371 desc.base = *rdata;
4372 desc.buflen = mdrcnt;
4373 } else {
4375 * Don't return data but need to get correct length
4376 * init_package will return wrong size if buflen=0
4378 desc.buflen = getlen(desc.format);
4379 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4381 if (init_package(&desc,1,0)) {
4382 fill_printdest_info(conn,snum,uLevel,&desc);
4384 *rdata_len = desc.usedlen;
4387 *rparam_len = 6;
4388 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4389 if (!*rparam) {
4390 return False;
4392 SSVALS(*rparam,0,desc.errcode);
4393 SSVAL(*rparam,2,0);
4394 SSVAL(*rparam,4,desc.neededlen);
4396 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4397 SAFE_FREE(tmpdata);
4399 return True;
4402 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4403 char *param, int tpscnt,
4404 char *data, int tdscnt,
4405 int mdrcnt,int mprcnt,
4406 char **rdata,char **rparam,
4407 int *rdata_len,int *rparam_len)
4409 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4410 char *str2 = skip_string(param,tpscnt,str1);
4411 char *p = skip_string(param,tpscnt,str2);
4412 int uLevel;
4413 int queuecnt;
4414 int i, n, succnt=0;
4415 struct pack_desc desc;
4416 int services = lp_numservices();
4418 if (!str1 || !str2 || !p) {
4419 return False;
4422 memset((char *)&desc,'\0',sizeof(desc));
4424 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4426 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4428 /* check it's a supported varient */
4429 if (strcmp(str1,"WrLeh") != 0) {
4430 return False;
4432 if (!check_printdest_info(&desc,uLevel,str2)) {
4433 return False;
4436 queuecnt = 0;
4437 for (i = 0; i < services; i++) {
4438 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4439 queuecnt++;
4443 if (mdrcnt > 0) {
4444 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4445 if (!*rdata) {
4446 return False;
4450 desc.base = *rdata;
4451 desc.buflen = mdrcnt;
4452 if (init_package(&desc,queuecnt,0)) {
4453 succnt = 0;
4454 n = 0;
4455 for (i = 0; i < services; i++) {
4456 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4457 fill_printdest_info(conn,i,uLevel,&desc);
4458 n++;
4459 if (desc.errcode == NERR_Success) {
4460 succnt = n;
4466 *rdata_len = desc.usedlen;
4468 *rparam_len = 8;
4469 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4470 if (!*rparam) {
4471 return False;
4473 SSVALS(*rparam,0,desc.errcode);
4474 SSVAL(*rparam,2,0);
4475 SSVAL(*rparam,4,succnt);
4476 SSVAL(*rparam,6,queuecnt);
4478 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4480 return True;
4483 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4484 char *param, int tpscnt,
4485 char *data, int tdscnt,
4486 int mdrcnt,int mprcnt,
4487 char **rdata,char **rparam,
4488 int *rdata_len,int *rparam_len)
4490 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4491 char *str2 = skip_string(param,tpscnt,str1);
4492 char *p = skip_string(param,tpscnt,str2);
4493 int uLevel;
4494 int succnt;
4495 struct pack_desc desc;
4497 if (!str1 || !str2 || !p) {
4498 return False;
4501 memset((char *)&desc,'\0',sizeof(desc));
4503 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4505 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4507 /* check it's a supported varient */
4508 if (strcmp(str1,"WrLeh") != 0) {
4509 return False;
4511 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4512 return False;
4515 if (mdrcnt > 0) {
4516 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4517 if (!*rdata) {
4518 return False;
4521 desc.base = *rdata;
4522 desc.buflen = mdrcnt;
4523 if (init_package(&desc,1,0)) {
4524 PACKS(&desc,"B41","NULL");
4527 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4529 *rdata_len = desc.usedlen;
4531 *rparam_len = 8;
4532 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4533 if (!*rparam) {
4534 return False;
4536 SSVALS(*rparam,0,desc.errcode);
4537 SSVAL(*rparam,2,0);
4538 SSVAL(*rparam,4,succnt);
4539 SSVAL(*rparam,6,1);
4541 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4543 return True;
4546 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4547 char *param, int tpscnt,
4548 char *data, int tdscnt,
4549 int mdrcnt,int mprcnt,
4550 char **rdata,char **rparam,
4551 int *rdata_len,int *rparam_len)
4553 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4554 char *str2 = skip_string(param,tpscnt,str1);
4555 char *p = skip_string(param,tpscnt,str2);
4556 int uLevel;
4557 int succnt;
4558 struct pack_desc desc;
4560 if (!str1 || !str2 || !p) {
4561 return False;
4563 memset((char *)&desc,'\0',sizeof(desc));
4565 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4567 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4569 /* check it's a supported varient */
4570 if (strcmp(str1,"WrLeh") != 0) {
4571 return False;
4573 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4574 return False;
4577 if (mdrcnt > 0) {
4578 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4579 if (!*rdata) {
4580 return False;
4583 desc.base = *rdata;
4584 desc.buflen = mdrcnt;
4585 desc.format = str2;
4586 if (init_package(&desc,1,0)) {
4587 PACKS(&desc,"B13","lpd");
4590 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4592 *rdata_len = desc.usedlen;
4594 *rparam_len = 8;
4595 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4596 if (!*rparam) {
4597 return False;
4599 SSVALS(*rparam,0,desc.errcode);
4600 SSVAL(*rparam,2,0);
4601 SSVAL(*rparam,4,succnt);
4602 SSVAL(*rparam,6,1);
4604 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4606 return True;
4609 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4610 char *param, int tpscnt,
4611 char *data, int tdscnt,
4612 int mdrcnt,int mprcnt,
4613 char **rdata,char **rparam,
4614 int *rdata_len,int *rparam_len)
4616 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4617 char *str2 = skip_string(param,tpscnt,str1);
4618 char *p = skip_string(param,tpscnt,str2);
4619 int uLevel;
4620 int succnt;
4621 struct pack_desc desc;
4623 if (!str1 || !str2 || !p) {
4624 return False;
4627 memset((char *)&desc,'\0',sizeof(desc));
4629 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4631 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4633 /* check it's a supported varient */
4634 if (strcmp(str1,"WrLeh") != 0) {
4635 return False;
4637 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4638 return False;
4641 if (mdrcnt > 0) {
4642 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4643 if (!*rdata) {
4644 return False;
4647 memset((char *)&desc,'\0',sizeof(desc));
4648 desc.base = *rdata;
4649 desc.buflen = mdrcnt;
4650 desc.format = str2;
4651 if (init_package(&desc,1,0)) {
4652 PACKS(&desc,"B13","lp0");
4655 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4657 *rdata_len = desc.usedlen;
4659 *rparam_len = 8;
4660 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4661 if (!*rparam) {
4662 return False;
4664 SSVALS(*rparam,0,desc.errcode);
4665 SSVAL(*rparam,2,0);
4666 SSVAL(*rparam,4,succnt);
4667 SSVAL(*rparam,6,1);
4669 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4671 return True;
4674 /****************************************************************************
4675 List open sessions
4676 ****************************************************************************/
4678 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4679 char *param, int tpscnt,
4680 char *data, int tdscnt,
4681 int mdrcnt,int mprcnt,
4682 char **rdata,char **rparam,
4683 int *rdata_len,int *rparam_len)
4686 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4687 char *str2 = skip_string(param,tpscnt,str1);
4688 char *p = skip_string(param,tpscnt,str2);
4689 int uLevel;
4690 struct pack_desc desc;
4691 struct sessionid *session_list;
4692 int i, num_sessions;
4694 if (!str1 || !str2 || !p) {
4695 return False;
4698 memset((char *)&desc,'\0',sizeof(desc));
4700 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4702 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4703 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4704 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4706 /* check it's a supported varient */
4707 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4708 return False;
4710 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4711 return False;
4714 num_sessions = list_sessions(talloc_tos(), &session_list);
4716 if (mdrcnt > 0) {
4717 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4718 if (!*rdata) {
4719 return False;
4722 memset((char *)&desc,'\0',sizeof(desc));
4723 desc.base = *rdata;
4724 desc.buflen = mdrcnt;
4725 desc.format = str2;
4726 if (!init_package(&desc,num_sessions,0)) {
4727 return False;
4730 for(i=0; i<num_sessions; i++) {
4731 PACKS(&desc, "z", session_list[i].remote_machine);
4732 PACKS(&desc, "z", session_list[i].username);
4733 PACKI(&desc, "W", 1); /* num conns */
4734 PACKI(&desc, "W", 0); /* num opens */
4735 PACKI(&desc, "W", 1); /* num users */
4736 PACKI(&desc, "D", 0); /* session time */
4737 PACKI(&desc, "D", 0); /* idle time */
4738 PACKI(&desc, "D", 0); /* flags */
4739 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4742 *rdata_len = desc.usedlen;
4744 *rparam_len = 8;
4745 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4746 if (!*rparam) {
4747 return False;
4749 SSVALS(*rparam,0,desc.errcode);
4750 SSVAL(*rparam,2,0); /* converter */
4751 SSVAL(*rparam,4,num_sessions); /* count */
4753 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4755 return True;
4759 /****************************************************************************
4760 The buffer was too small.
4761 ****************************************************************************/
4763 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4764 int mdrcnt, int mprcnt,
4765 char **rdata, char **rparam,
4766 int *rdata_len, int *rparam_len)
4768 *rparam_len = MIN(*rparam_len,mprcnt);
4769 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4770 if (!*rparam) {
4771 return False;
4774 *rdata_len = 0;
4776 SSVAL(*rparam,0,NERR_BufTooSmall);
4778 DEBUG(3,("Supplied buffer too small in API command\n"));
4780 return True;
4783 /****************************************************************************
4784 The request is not supported.
4785 ****************************************************************************/
4787 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4788 char *param, int tpscnt,
4789 char *data, int tdscnt,
4790 int mdrcnt, int mprcnt,
4791 char **rdata, char **rparam,
4792 int *rdata_len, int *rparam_len)
4794 *rparam_len = 4;
4795 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4796 if (!*rparam) {
4797 return False;
4800 *rdata_len = 0;
4802 SSVAL(*rparam,0,NERR_notsupported);
4803 SSVAL(*rparam,2,0); /* converter word */
4805 DEBUG(3,("Unsupported API command\n"));
4807 return True;
4810 static const struct {
4811 const char *name;
4812 int id;
4813 bool (*fn)(connection_struct *, uint16,
4814 char *, int,
4815 char *, int,
4816 int,int,char **,char **,int *,int *);
4817 bool auth_user; /* Deny anonymous access? */
4818 } api_commands[] = {
4819 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4820 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4821 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4822 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4823 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4824 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4825 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4826 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4827 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4828 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4829 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4830 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4831 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4832 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4833 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4834 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4835 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4836 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4837 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4838 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4839 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4840 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4841 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4842 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4843 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
4844 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
4845 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4846 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4847 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4848 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4849 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4850 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4851 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4852 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4853 {NULL, -1, api_Unsupported}
4854 /* The following RAP calls are not implemented by Samba:
4856 RAP_WFileEnum2 - anon not OK
4861 /****************************************************************************
4862 Handle remote api calls.
4863 ****************************************************************************/
4865 void api_reply(connection_struct *conn, uint16 vuid,
4866 struct smb_request *req,
4867 char *data, char *params,
4868 int tdscnt, int tpscnt,
4869 int mdrcnt, int mprcnt)
4871 int api_command;
4872 char *rdata = NULL;
4873 char *rparam = NULL;
4874 const char *name1 = NULL;
4875 const char *name2 = NULL;
4876 int rdata_len = 0;
4877 int rparam_len = 0;
4878 bool reply=False;
4879 int i;
4881 if (!params) {
4882 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4883 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4884 return;
4887 if (tpscnt < 2) {
4888 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4889 return;
4891 api_command = SVAL(params,0);
4892 /* Is there a string at position params+2 ? */
4893 if (skip_string(params,tpscnt,params+2)) {
4894 name1 = params + 2;
4895 } else {
4896 name1 = "";
4898 name2 = skip_string(params,tpscnt,params+2);
4899 if (!name2) {
4900 name2 = "";
4903 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4904 api_command,
4905 name1,
4906 name2,
4907 tdscnt,tpscnt,mdrcnt,mprcnt));
4909 for (i=0;api_commands[i].name;i++) {
4910 if (api_commands[i].id == api_command && api_commands[i].fn) {
4911 DEBUG(3,("Doing %s\n",api_commands[i].name));
4912 break;
4916 /* Check whether this api call can be done anonymously */
4918 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4919 user_struct *user = get_valid_user_struct(vuid);
4921 if (!user || user->server_info->guest) {
4922 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4923 return;
4927 rdata = (char *)SMB_MALLOC(1024);
4928 if (rdata) {
4929 memset(rdata,'\0',1024);
4932 rparam = (char *)SMB_MALLOC(1024);
4933 if (rparam) {
4934 memset(rparam,'\0',1024);
4937 if(!rdata || !rparam) {
4938 DEBUG(0,("api_reply: malloc fail !\n"));
4939 SAFE_FREE(rdata);
4940 SAFE_FREE(rparam);
4941 reply_nterror(req, NT_STATUS_NO_MEMORY);
4942 return;
4945 reply = api_commands[i].fn(conn,
4946 vuid,
4947 params,tpscnt, /* params + length */
4948 data,tdscnt, /* data + length */
4949 mdrcnt,mprcnt,
4950 &rdata,&rparam,&rdata_len,&rparam_len);
4953 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4954 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4955 &rdata,&rparam,&rdata_len,&rparam_len);
4958 /* if we get False back then it's actually unsupported */
4959 if (!reply) {
4960 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4961 &rdata,&rparam,&rdata_len,&rparam_len);
4964 /* If api_Unsupported returns false we can't return anything. */
4965 if (reply) {
4966 send_trans_reply(conn, req, rparam, rparam_len,
4967 rdata, rdata_len, False);
4970 SAFE_FREE(rdata);
4971 SAFE_FREE(rparam);
4972 return;