Fix for CVE-2009-2906.
[Samba.git] / source3 / smbd / lanman.c
blobb15e685183caedf10c271d9543de768a294d8400
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
30 #ifdef CHECK_TYPES
31 #undef CHECK_TYPES
32 #endif
33 #define CHECK_TYPES 0
35 #define NERR_Success 0
36 #define NERR_badpass 86
37 #define NERR_notsupported 50
39 #define NERR_BASE (2100)
40 #define NERR_BufTooSmall (NERR_BASE+23)
41 #define NERR_JobNotFound (NERR_BASE+51)
42 #define NERR_DestNotFound (NERR_BASE+52)
44 #define ACCESS_READ 0x01
45 #define ACCESS_WRITE 0x02
46 #define ACCESS_CREATE 0x04
48 #define SHPWLEN 8 /* share password length */
50 /* Limit size of ipc replies */
52 static char *smb_realloc_limit(void *ptr, size_t size)
54 char *val;
56 size = MAX((size),4*1024);
57 val = (char *)SMB_REALLOC(ptr,size);
58 if (val) {
59 memset(val,'\0',size);
61 return val;
64 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
65 char *param, int tpscnt,
66 char *data, int tdscnt,
67 int mdrcnt, int mprcnt,
68 char **rdata, char **rparam,
69 int *rdata_len, int *rparam_len);
71 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
72 int mdrcnt, int mprcnt,
73 char **rdata, char **rparam,
74 int *rdata_len, int *rparam_len);
77 static int CopyExpanded(connection_struct *conn,
78 int snum, char **dst, char *src, int *p_space_remaining)
80 TALLOC_CTX *ctx = talloc_tos();
81 char *buf = NULL;
82 int l;
84 if (!src || !dst || !p_space_remaining || !(*dst) ||
85 *p_space_remaining <= 0) {
86 return 0;
89 buf = talloc_strdup(ctx, src);
90 if (!buf) {
91 *p_space_remaining = 0;
92 return 0;
94 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
95 if (!buf) {
96 *p_space_remaining = 0;
97 return 0;
99 buf = talloc_sub_advanced(ctx,
100 lp_servicename(SNUM(conn)),
101 conn->server_info->unix_name,
102 conn->connectpath,
103 conn->server_info->utok.gid,
104 conn->server_info->sanitized_username,
105 pdb_get_domain(conn->server_info->sam_account),
106 buf);
107 if (!buf) {
108 *p_space_remaining = 0;
109 return 0;
111 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
112 if (l == -1) {
113 return 0;
115 (*dst) += l;
116 (*p_space_remaining) -= l;
117 return l;
120 static int CopyAndAdvance(char **dst, char *src, int *n)
122 int l;
123 if (!src || !dst || !n || !(*dst)) {
124 return 0;
126 l = push_ascii(*dst,src,*n, STR_TERMINATE);
127 if (l == -1) {
128 return 0;
130 (*dst) += l;
131 (*n) -= l;
132 return l;
135 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
137 TALLOC_CTX *ctx = talloc_tos();
138 char *buf = NULL;
139 if (!s) {
140 return 0;
142 buf = talloc_strdup(ctx,s);
143 if (!buf) {
144 return 0;
146 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
147 if (!buf) {
148 return 0;
150 buf = talloc_sub_advanced(ctx,
151 lp_servicename(SNUM(conn)),
152 conn->server_info->unix_name,
153 conn->connectpath,
154 conn->server_info->utok.gid,
155 conn->server_info->sanitized_username,
156 pdb_get_domain(conn->server_info->sam_account),
157 buf);
158 if (!buf) {
159 return 0;
161 return strlen(buf) + 1;
164 static char *Expand(connection_struct *conn, int snum, char *s)
166 TALLOC_CTX *ctx = talloc_tos();
167 char *buf = NULL;
169 if (!s) {
170 return NULL;
172 buf = talloc_strdup(ctx,s);
173 if (!buf) {
174 return 0;
176 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
177 if (!buf) {
178 return 0;
180 return talloc_sub_advanced(ctx,
181 lp_servicename(SNUM(conn)),
182 conn->server_info->unix_name,
183 conn->connectpath,
184 conn->server_info->utok.gid,
185 conn->server_info->sanitized_username,
186 pdb_get_domain(conn->server_info->sam_account),
187 buf);
190 /*******************************************************************
191 Check a API string for validity when we only need to check the prefix.
192 ******************************************************************/
194 static bool prefix_ok(const char *str, const char *prefix)
196 return(strncmp(str,prefix,strlen(prefix)) == 0);
199 struct pack_desc {
200 const char *format; /* formatstring for structure */
201 const char *subformat; /* subformat for structure */
202 char *base; /* baseaddress of buffer */
203 int buflen; /* remaining size for fixed part; on init: length of base */
204 int subcount; /* count of substructures */
205 char *structbuf; /* pointer into buffer for remaining fixed part */
206 int stringlen; /* remaining size for variable part */
207 char *stringbuf; /* pointer into buffer for remaining variable part */
208 int neededlen; /* total needed size */
209 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
210 const char *curpos; /* current position; pointer into format or subformat */
211 int errcode;
214 static int get_counter(const char **p)
216 int i, n;
217 if (!p || !(*p)) {
218 return 1;
220 if (!isdigit((int)**p)) {
221 return 1;
223 for (n = 0;;) {
224 i = **p;
225 if (isdigit(i)) {
226 n = 10 * n + (i - '0');
227 } else {
228 return n;
230 (*p)++;
234 static int getlen(const char *p)
236 int n = 0;
237 if (!p) {
238 return 0;
241 while (*p) {
242 switch( *p++ ) {
243 case 'W': /* word (2 byte) */
244 n += 2;
245 break;
246 case 'K': /* status word? (2 byte) */
247 n += 2;
248 break;
249 case 'N': /* count of substructures (word) at end */
250 n += 2;
251 break;
252 case 'D': /* double word (4 byte) */
253 case 'z': /* offset to zero terminated string (4 byte) */
254 case 'l': /* offset to user data (4 byte) */
255 n += 4;
256 break;
257 case 'b': /* offset to data (with counter) (4 byte) */
258 n += 4;
259 get_counter(&p);
260 break;
261 case 'B': /* byte (with optional counter) */
262 n += get_counter(&p);
263 break;
266 return n;
269 static bool init_package(struct pack_desc *p, int count, int subcount)
271 int n = p->buflen;
272 int i;
274 if (!p->format || !p->base) {
275 return False;
278 i = count * getlen(p->format);
279 if (p->subformat) {
280 i += subcount * getlen(p->subformat);
282 p->structbuf = p->base;
283 p->neededlen = 0;
284 p->usedlen = 0;
285 p->subcount = 0;
286 p->curpos = p->format;
287 if (i > n) {
288 p->neededlen = i;
289 i = n = 0;
290 #if 0
292 * This is the old error code we used. Aparently
293 * WinNT/2k systems return ERRbuftoosmall (2123) and
294 * OS/2 needs this. I'm leaving this here so we can revert
295 * if needed. JRA.
297 p->errcode = ERRmoredata;
298 #else
299 p->errcode = ERRbuftoosmall;
300 #endif
301 } else {
302 p->errcode = NERR_Success;
304 p->buflen = i;
305 n -= i;
306 p->stringbuf = p->base + i;
307 p->stringlen = n;
308 return (p->errcode == NERR_Success);
311 static int package(struct pack_desc *p, ...)
313 va_list args;
314 int needed=0, stringneeded;
315 const char *str=NULL;
316 int is_string=0, stringused;
317 int32 temp;
319 va_start(args,p);
321 if (!*p->curpos) {
322 if (!p->subcount) {
323 p->curpos = p->format;
324 } else {
325 p->curpos = p->subformat;
326 p->subcount--;
329 #if CHECK_TYPES
330 str = va_arg(args,char*);
331 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
332 #endif
333 stringneeded = -1;
335 if (!p->curpos) {
336 va_end(args);
337 return 0;
340 switch( *p->curpos++ ) {
341 case 'W': /* word (2 byte) */
342 needed = 2;
343 temp = va_arg(args,int);
344 if (p->buflen >= needed) {
345 SSVAL(p->structbuf,0,temp);
347 break;
348 case 'K': /* status word? (2 byte) */
349 needed = 2;
350 temp = va_arg(args,int);
351 if (p->buflen >= needed) {
352 SSVAL(p->structbuf,0,temp);
354 break;
355 case 'N': /* count of substructures (word) at end */
356 needed = 2;
357 p->subcount = va_arg(args,int);
358 if (p->buflen >= needed) {
359 SSVAL(p->structbuf,0,p->subcount);
361 break;
362 case 'D': /* double word (4 byte) */
363 needed = 4;
364 temp = va_arg(args,int);
365 if (p->buflen >= needed) {
366 SIVAL(p->structbuf,0,temp);
368 break;
369 case 'B': /* byte (with optional counter) */
370 needed = get_counter(&p->curpos);
372 char *s = va_arg(args,char*);
373 if (p->buflen >= needed) {
374 StrnCpy(p->structbuf,s?s:"",needed-1);
377 break;
378 case 'z': /* offset to zero terminated string (4 byte) */
379 str = va_arg(args,char*);
380 stringneeded = (str ? strlen(str)+1 : 0);
381 is_string = 1;
382 break;
383 case 'l': /* offset to user data (4 byte) */
384 str = va_arg(args,char*);
385 stringneeded = va_arg(args,int);
386 is_string = 0;
387 break;
388 case 'b': /* offset to data (with counter) (4 byte) */
389 str = va_arg(args,char*);
390 stringneeded = get_counter(&p->curpos);
391 is_string = 0;
392 break;
395 va_end(args);
396 if (stringneeded >= 0) {
397 needed = 4;
398 if (p->buflen >= needed) {
399 stringused = stringneeded;
400 if (stringused > p->stringlen) {
401 stringused = (is_string ? p->stringlen : 0);
402 if (p->errcode == NERR_Success) {
403 p->errcode = ERRmoredata;
406 if (!stringused) {
407 SIVAL(p->structbuf,0,0);
408 } else {
409 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
410 memcpy(p->stringbuf,str?str:"",stringused);
411 if (is_string) {
412 p->stringbuf[stringused-1] = '\0';
414 p->stringbuf += stringused;
415 p->stringlen -= stringused;
416 p->usedlen += stringused;
419 p->neededlen += stringneeded;
422 p->neededlen += needed;
423 if (p->buflen >= needed) {
424 p->structbuf += needed;
425 p->buflen -= needed;
426 p->usedlen += needed;
427 } else {
428 if (p->errcode == NERR_Success) {
429 p->errcode = ERRmoredata;
432 return 1;
435 #if CHECK_TYPES
436 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
437 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
438 #else
439 #define PACK(desc,t,v) package(desc,v)
440 #define PACKl(desc,t,v,l) package(desc,v,l)
441 #endif
443 static void PACKI(struct pack_desc* desc, const char *t,int v)
445 PACK(desc,t,v);
448 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
450 PACK(desc,t,v);
453 /****************************************************************************
454 Get a print queue.
455 ****************************************************************************/
457 static void PackDriverData(struct pack_desc* desc)
459 char drivdata[4+4+32];
460 SIVAL(drivdata,0,sizeof drivdata); /* cb */
461 SIVAL(drivdata,4,1000); /* lVersion */
462 memset(drivdata+8,0,32); /* szDeviceName */
463 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
464 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
467 static int check_printq_info(struct pack_desc* desc,
468 unsigned int uLevel, char *id1, char *id2)
470 desc->subformat = NULL;
471 switch( uLevel ) {
472 case 0:
473 desc->format = "B13";
474 break;
475 case 1:
476 desc->format = "B13BWWWzzzzzWW";
477 break;
478 case 2:
479 desc->format = "B13BWWWzzzzzWN";
480 desc->subformat = "WB21BB16B10zWWzDDz";
481 break;
482 case 3:
483 desc->format = "zWWWWzzzzWWzzl";
484 break;
485 case 4:
486 desc->format = "zWWWWzzzzWNzzl";
487 desc->subformat = "WWzWWDDzz";
488 break;
489 case 5:
490 desc->format = "z";
491 break;
492 case 51:
493 desc->format = "K";
494 break;
495 case 52:
496 desc->format = "WzzzzzzzzN";
497 desc->subformat = "z";
498 break;
499 default:
500 DEBUG(0,("check_printq_info: invalid level %d\n",
501 uLevel ));
502 return False;
504 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
505 DEBUG(0,("check_printq_info: invalid format %s\n",
506 id1 ? id1 : "<NULL>" ));
507 return False;
509 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
510 DEBUG(0,("check_printq_info: invalid subformat %s\n",
511 id2 ? id2 : "<NULL>" ));
512 return False;
514 return True;
518 #define RAP_JOB_STATUS_QUEUED 0
519 #define RAP_JOB_STATUS_PAUSED 1
520 #define RAP_JOB_STATUS_SPOOLING 2
521 #define RAP_JOB_STATUS_PRINTING 3
522 #define RAP_JOB_STATUS_PRINTED 4
524 #define RAP_QUEUE_STATUS_PAUSED 1
525 #define RAP_QUEUE_STATUS_ERROR 2
527 /* turn a print job status into a on the wire status
529 static int printj_status(int v)
531 switch (v) {
532 case LPQ_QUEUED:
533 return RAP_JOB_STATUS_QUEUED;
534 case LPQ_PAUSED:
535 return RAP_JOB_STATUS_PAUSED;
536 case LPQ_SPOOLING:
537 return RAP_JOB_STATUS_SPOOLING;
538 case LPQ_PRINTING:
539 return RAP_JOB_STATUS_PRINTING;
541 return 0;
544 /* turn a print queue status into a on the wire status
546 static int printq_status(int v)
548 switch (v) {
549 case LPQ_QUEUED:
550 return 0;
551 case LPQ_PAUSED:
552 return RAP_QUEUE_STATUS_PAUSED;
554 return RAP_QUEUE_STATUS_ERROR;
557 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
558 struct pack_desc *desc,
559 print_queue_struct *queue, int n)
561 time_t t = queue->time;
563 /* the client expects localtime */
564 t -= get_time_zone(t);
566 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
567 if (uLevel == 1) {
568 PACKS(desc,"B21",queue->fs_user); /* szUserName */
569 PACKS(desc,"B",""); /* pad */
570 PACKS(desc,"B16",""); /* szNotifyName */
571 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
572 PACKS(desc,"z",""); /* pszParms */
573 PACKI(desc,"W",n+1); /* uPosition */
574 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
575 PACKS(desc,"z",""); /* pszStatus */
576 PACKI(desc,"D",t); /* ulSubmitted */
577 PACKI(desc,"D",queue->size); /* ulSize */
578 PACKS(desc,"z",queue->fs_file); /* pszComment */
580 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
581 PACKI(desc,"W",queue->priority); /* uPriority */
582 PACKS(desc,"z",queue->fs_user); /* pszUserName */
583 PACKI(desc,"W",n+1); /* uPosition */
584 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
585 PACKI(desc,"D",t); /* ulSubmitted */
586 PACKI(desc,"D",queue->size); /* ulSize */
587 PACKS(desc,"z","Samba"); /* pszComment */
588 PACKS(desc,"z",queue->fs_file); /* pszDocument */
589 if (uLevel == 3) {
590 PACKS(desc,"z",""); /* pszNotifyName */
591 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
592 PACKS(desc,"z",""); /* pszParms */
593 PACKS(desc,"z",""); /* pszStatus */
594 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
595 PACKS(desc,"z","lpd"); /* pszQProcName */
596 PACKS(desc,"z",""); /* pszQProcParms */
597 PACKS(desc,"z","NULL"); /* pszDriverName */
598 PackDriverData(desc); /* pDriverData */
599 PACKS(desc,"z",""); /* pszPrinterName */
600 } else if (uLevel == 4) { /* OS2 */
601 PACKS(desc,"z",""); /* pszSpoolFileName */
602 PACKS(desc,"z",""); /* pszPortName */
603 PACKS(desc,"z",""); /* pszStatus */
604 PACKI(desc,"D",0); /* ulPagesSpooled */
605 PACKI(desc,"D",0); /* ulPagesSent */
606 PACKI(desc,"D",0); /* ulPagesPrinted */
607 PACKI(desc,"D",0); /* ulTimePrinted */
608 PACKI(desc,"D",0); /* ulExtendJobStatus */
609 PACKI(desc,"D",0); /* ulStartPage */
610 PACKI(desc,"D",0); /* ulEndPage */
615 /********************************************************************
616 Return a driver name given an snum.
617 Returns True if from tdb, False otherwise.
618 ********************************************************************/
620 static bool get_driver_name(int snum, char **pp_drivername)
622 NT_PRINTER_INFO_LEVEL *info = NULL;
623 bool in_tdb = false;
625 get_a_printer (NULL, &info, 2, lp_servicename(snum));
626 if (info != NULL) {
627 *pp_drivername = talloc_strdup(talloc_tos(),
628 info->info_2->drivername);
629 in_tdb = true;
630 free_a_printer(&info, 2);
631 if (!*pp_drivername) {
632 return false;
636 return in_tdb;
639 /********************************************************************
640 Respond to the DosPrintQInfo command with a level of 52
641 This is used to get printer driver information for Win9x clients
642 ********************************************************************/
643 static void fill_printq_info_52(connection_struct *conn, int snum,
644 struct pack_desc* desc, int count )
646 int i;
647 fstring location;
648 NT_PRINTER_DRIVER_INFO_LEVEL driver;
649 NT_PRINTER_INFO_LEVEL *printer = NULL;
651 ZERO_STRUCT(driver);
653 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
654 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
655 lp_servicename(snum)));
656 goto err;
659 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
660 "Windows 4.0", 0)) )
662 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
663 printer->info_2->drivername));
664 goto err;
667 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
668 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
669 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
671 PACKI(desc, "W", 0x0400); /* don't know */
672 PACKS(desc, "z", driver.info_3->name); /* long printer name */
673 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
674 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
675 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
677 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
678 standard_sub_basic( "", "", location, sizeof(location)-1 );
679 PACKS(desc,"z", location); /* share to retrieve files */
681 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
682 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
683 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
685 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
686 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
687 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
688 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
689 DEBUG(3,("Driver Location: %s:\n",location));
690 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
691 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
692 PACKI(desc,"N",count); /* number of files to copy */
694 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
696 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
697 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
698 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
701 /* sanity check */
702 if ( i != count )
703 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
704 count, i));
706 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
708 desc->errcode=NERR_Success;
709 goto done;
711 err:
712 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
713 desc->errcode=NERR_notsupported;
715 done:
716 if ( printer )
717 free_a_printer( &printer, 2 );
719 if ( driver.info_3 )
720 free_a_printer_driver( driver, 3 );
724 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
725 struct pack_desc* desc,
726 int count, print_queue_struct* queue,
727 print_status_struct* status)
729 switch (uLevel) {
730 case 1:
731 case 2:
732 PACKS(desc,"B13",SERVICE(snum));
733 break;
734 case 3:
735 case 4:
736 case 5:
737 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
738 break;
739 case 51:
740 PACKI(desc,"K",printq_status(status->status));
741 break;
744 if (uLevel == 1 || uLevel == 2) {
745 PACKS(desc,"B",""); /* alignment */
746 PACKI(desc,"W",5); /* priority */
747 PACKI(desc,"W",0); /* start time */
748 PACKI(desc,"W",0); /* until time */
749 PACKS(desc,"z",""); /* pSepFile */
750 PACKS(desc,"z","lpd"); /* pPrProc */
751 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
752 PACKS(desc,"z",""); /* pParms */
753 if (snum < 0) {
754 PACKS(desc,"z","UNKNOWN PRINTER");
755 PACKI(desc,"W",LPSTAT_ERROR);
757 else if (!status || !status->message[0]) {
758 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
759 PACKI(desc,"W",LPSTAT_OK); /* status */
760 } else {
761 PACKS(desc,"z",status->message);
762 PACKI(desc,"W",printq_status(status->status)); /* status */
764 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
767 if (uLevel == 3 || uLevel == 4) {
768 char *drivername = NULL;
770 PACKI(desc,"W",5); /* uPriority */
771 PACKI(desc,"W",0); /* uStarttime */
772 PACKI(desc,"W",0); /* uUntiltime */
773 PACKI(desc,"W",5); /* pad1 */
774 PACKS(desc,"z",""); /* pszSepFile */
775 PACKS(desc,"z","WinPrint"); /* pszPrProc */
776 PACKS(desc,"z",NULL); /* pszParms */
777 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
778 /* "don't ask" that it's done this way to fix corrupted
779 Win9X/ME printer comments. */
780 if (!status) {
781 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
782 } else {
783 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
785 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
786 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
787 get_driver_name(snum,&drivername);
788 if (!drivername) {
789 return;
791 PACKS(desc,"z",drivername); /* pszDriverName */
792 PackDriverData(desc); /* pDriverData */
795 if (uLevel == 2 || uLevel == 4) {
796 int i;
797 for (i=0;i<count;i++)
798 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
801 if (uLevel==52)
802 fill_printq_info_52( conn, snum, desc, count );
805 /* This function returns the number of files for a given driver */
806 static int get_printerdrivernumber(int snum)
808 int result = 0;
809 NT_PRINTER_DRIVER_INFO_LEVEL driver;
810 NT_PRINTER_INFO_LEVEL *printer = NULL;
812 ZERO_STRUCT(driver);
814 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
815 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
816 lp_servicename(snum)));
817 goto done;
820 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
821 "Windows 4.0", 0)) )
823 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
824 printer->info_2->drivername));
825 goto done;
828 /* count the number of files */
829 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
830 result++;
832 done:
833 if ( printer )
834 free_a_printer( &printer, 2 );
836 if ( driver.info_3 )
837 free_a_printer_driver( driver, 3 );
839 return result;
842 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
843 char *param, int tpscnt,
844 char *data, int tdscnt,
845 int mdrcnt,int mprcnt,
846 char **rdata,char **rparam,
847 int *rdata_len,int *rparam_len)
849 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
850 char *str2 = skip_string(param,tpscnt,str1);
851 char *p = skip_string(param,tpscnt,str2);
852 char *QueueName = p;
853 unsigned int uLevel;
854 int count=0;
855 int snum;
856 char *str3;
857 struct pack_desc desc;
858 print_queue_struct *queue=NULL;
859 print_status_struct status;
860 char* tmpdata=NULL;
862 if (!str1 || !str2 || !p) {
863 return False;
865 memset((char *)&status,'\0',sizeof(status));
866 memset((char *)&desc,'\0',sizeof(desc));
868 p = skip_string(param,tpscnt,p);
869 if (!p) {
870 return False;
872 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
873 str3 = get_safe_str_ptr(param,tpscnt,p,4);
874 /* str3 may be null here and is checked in check_printq_info(). */
876 /* remove any trailing username */
877 if ((p = strchr_m(QueueName,'%')))
878 *p = 0;
880 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
882 /* check it's a supported varient */
883 if (!prefix_ok(str1,"zWrLh"))
884 return False;
885 if (!check_printq_info(&desc,uLevel,str2,str3)) {
887 * Patch from Scott Moomaw <scott@bridgewater.edu>
888 * to return the 'invalid info level' error if an
889 * unknown level was requested.
891 *rdata_len = 0;
892 *rparam_len = 6;
893 *rparam = smb_realloc_limit(*rparam,*rparam_len);
894 if (!*rparam) {
895 return False;
897 SSVALS(*rparam,0,ERRunknownlevel);
898 SSVAL(*rparam,2,0);
899 SSVAL(*rparam,4,0);
900 return(True);
903 snum = find_service(QueueName);
904 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
905 return False;
907 if (uLevel==52) {
908 count = get_printerdrivernumber(snum);
909 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
910 } else {
911 count = print_queue_status(snum, &queue,&status);
914 if (mdrcnt > 0) {
915 *rdata = smb_realloc_limit(*rdata,mdrcnt);
916 if (!*rdata) {
917 SAFE_FREE(queue);
918 return False;
920 desc.base = *rdata;
921 desc.buflen = mdrcnt;
922 } else {
924 * Don't return data but need to get correct length
925 * init_package will return wrong size if buflen=0
927 desc.buflen = getlen(desc.format);
928 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
931 if (init_package(&desc,1,count)) {
932 desc.subcount = count;
933 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
936 *rdata_len = desc.usedlen;
939 * We must set the return code to ERRbuftoosmall
940 * in order to support lanman style printing with Win NT/2k
941 * clients --jerry
943 if (!mdrcnt && lp_disable_spoolss())
944 desc.errcode = ERRbuftoosmall;
946 *rdata_len = desc.usedlen;
947 *rparam_len = 6;
948 *rparam = smb_realloc_limit(*rparam,*rparam_len);
949 if (!*rparam) {
950 SAFE_FREE(queue);
951 SAFE_FREE(tmpdata);
952 return False;
954 SSVALS(*rparam,0,desc.errcode);
955 SSVAL(*rparam,2,0);
956 SSVAL(*rparam,4,desc.neededlen);
958 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
960 SAFE_FREE(queue);
961 SAFE_FREE(tmpdata);
963 return(True);
966 /****************************************************************************
967 View list of all print jobs on all queues.
968 ****************************************************************************/
970 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
971 char *param, int tpscnt,
972 char *data, int tdscnt,
973 int mdrcnt, int mprcnt,
974 char **rdata, char** rparam,
975 int *rdata_len, int *rparam_len)
977 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
978 char *output_format1 = skip_string(param,tpscnt,param_format);
979 char *p = skip_string(param,tpscnt,output_format1);
980 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
981 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
982 int services = lp_numservices();
983 int i, n;
984 struct pack_desc desc;
985 print_queue_struct **queue = NULL;
986 print_status_struct *status = NULL;
987 int *subcntarr = NULL;
988 int queuecnt = 0, subcnt = 0, succnt = 0;
990 if (!param_format || !output_format1 || !p) {
991 return False;
994 memset((char *)&desc,'\0',sizeof(desc));
996 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
998 if (!prefix_ok(param_format,"WrLeh")) {
999 return False;
1001 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1003 * Patch from Scott Moomaw <scott@bridgewater.edu>
1004 * to return the 'invalid info level' error if an
1005 * unknown level was requested.
1007 *rdata_len = 0;
1008 *rparam_len = 6;
1009 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1010 if (!*rparam) {
1011 return False;
1013 SSVALS(*rparam,0,ERRunknownlevel);
1014 SSVAL(*rparam,2,0);
1015 SSVAL(*rparam,4,0);
1016 return(True);
1019 for (i = 0; i < services; i++) {
1020 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1021 queuecnt++;
1025 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1026 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1027 goto err;
1029 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1030 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1031 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1032 goto err;
1034 memset(status,0,queuecnt*sizeof(print_status_struct));
1035 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1036 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1037 goto err;
1040 subcnt = 0;
1041 n = 0;
1042 for (i = 0; i < services; i++) {
1043 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1044 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1045 subcnt += subcntarr[n];
1046 n++;
1050 if (mdrcnt > 0) {
1051 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1052 if (!*rdata) {
1053 goto err;
1056 desc.base = *rdata;
1057 desc.buflen = mdrcnt;
1059 if (init_package(&desc,queuecnt,subcnt)) {
1060 n = 0;
1061 succnt = 0;
1062 for (i = 0; i < services; i++) {
1063 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1064 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1065 n++;
1066 if (desc.errcode == NERR_Success) {
1067 succnt = n;
1073 SAFE_FREE(subcntarr);
1075 *rdata_len = desc.usedlen;
1076 *rparam_len = 8;
1077 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1078 if (!*rparam) {
1079 goto err;
1081 SSVALS(*rparam,0,desc.errcode);
1082 SSVAL(*rparam,2,0);
1083 SSVAL(*rparam,4,succnt);
1084 SSVAL(*rparam,6,queuecnt);
1086 for (i = 0; i < queuecnt; i++) {
1087 if (queue) {
1088 SAFE_FREE(queue[i]);
1092 SAFE_FREE(queue);
1093 SAFE_FREE(status);
1095 return True;
1097 err:
1099 SAFE_FREE(subcntarr);
1100 for (i = 0; i < queuecnt; i++) {
1101 if (queue) {
1102 SAFE_FREE(queue[i]);
1105 SAFE_FREE(queue);
1106 SAFE_FREE(status);
1108 return False;
1111 /****************************************************************************
1112 Get info level for a server list query.
1113 ****************************************************************************/
1115 static bool check_server_info(int uLevel, char* id)
1117 switch( uLevel ) {
1118 case 0:
1119 if (strcmp(id,"B16") != 0) {
1120 return False;
1122 break;
1123 case 1:
1124 if (strcmp(id,"B16BBDz") != 0) {
1125 return False;
1127 break;
1128 default:
1129 return False;
1131 return True;
1134 struct srv_info_struct {
1135 fstring name;
1136 uint32 type;
1137 fstring comment;
1138 fstring domain;
1139 bool server_added;
1142 /*******************************************************************
1143 Get server info lists from the files saved by nmbd. Return the
1144 number of entries.
1145 ******************************************************************/
1147 static int get_server_info(uint32 servertype,
1148 struct srv_info_struct **servers,
1149 const char *domain)
1151 int count=0;
1152 int alloced=0;
1153 char **lines;
1154 bool local_list_only;
1155 int i;
1157 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1158 if (!lines) {
1159 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1160 return 0;
1163 /* request for everything is code for request all servers */
1164 if (servertype == SV_TYPE_ALL) {
1165 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1168 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1170 DEBUG(4,("Servertype search: %8x\n",servertype));
1172 for (i=0;lines[i];i++) {
1173 fstring stype;
1174 struct srv_info_struct *s;
1175 const char *ptr = lines[i];
1176 bool ok = True;
1177 TALLOC_CTX *frame = NULL;
1178 char *p;
1180 if (!*ptr) {
1181 continue;
1184 if (count == alloced) {
1185 alloced += 10;
1186 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1187 if (!*servers) {
1188 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1189 TALLOC_FREE(lines);
1190 return 0;
1192 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1194 s = &(*servers)[count];
1196 frame = talloc_stackframe();
1197 s->name[0] = '\0';
1198 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1199 TALLOC_FREE(frame);
1200 continue;
1202 fstrcpy(s->name, p);
1204 stype[0] = '\0';
1205 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1206 TALLOC_FREE(frame);
1207 continue;
1209 fstrcpy(stype, p);
1211 s->comment[0] = '\0';
1212 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1213 TALLOC_FREE(frame);
1214 continue;
1216 fstrcpy(s->comment, p);
1217 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1219 s->domain[0] = '\0';
1220 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1221 /* this allows us to cope with an old nmbd */
1222 fstrcpy(s->domain,lp_workgroup());
1223 } else {
1224 fstrcpy(s->domain, p);
1226 TALLOC_FREE(frame);
1228 if (sscanf(stype,"%X",&s->type) != 1) {
1229 DEBUG(4,("r:host file "));
1230 ok = False;
1233 /* Filter the servers/domains we return based on what was asked for. */
1235 /* Check to see if we are being asked for a local list only. */
1236 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1237 DEBUG(4,("r: local list only"));
1238 ok = False;
1241 /* doesn't match up: don't want it */
1242 if (!(servertype & s->type)) {
1243 DEBUG(4,("r:serv type "));
1244 ok = False;
1247 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1248 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1249 DEBUG(4,("s: dom mismatch "));
1250 ok = False;
1253 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1254 ok = False;
1257 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1258 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1260 if (ok) {
1261 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1262 s->name, s->type, s->comment, s->domain));
1263 s->server_added = True;
1264 count++;
1265 } else {
1266 DEBUG(4,("%20s %8x %25s %15s\n",
1267 s->name, s->type, s->comment, s->domain));
1271 TALLOC_FREE(lines);
1272 return count;
1275 /*******************************************************************
1276 Fill in a server info structure.
1277 ******************************************************************/
1279 static int fill_srv_info(struct srv_info_struct *service,
1280 int uLevel, char **buf, int *buflen,
1281 char **stringbuf, int *stringspace, char *baseaddr)
1283 int struct_len;
1284 char* p;
1285 char* p2;
1286 int l2;
1287 int len;
1289 switch (uLevel) {
1290 case 0:
1291 struct_len = 16;
1292 break;
1293 case 1:
1294 struct_len = 26;
1295 break;
1296 default:
1297 return -1;
1300 if (!buf) {
1301 len = 0;
1302 switch (uLevel) {
1303 case 1:
1304 len = strlen(service->comment)+1;
1305 break;
1308 *buflen = struct_len;
1309 *stringspace = len;
1310 return struct_len + len;
1313 len = struct_len;
1314 p = *buf;
1315 if (*buflen < struct_len) {
1316 return -1;
1318 if (stringbuf) {
1319 p2 = *stringbuf;
1320 l2 = *stringspace;
1321 } else {
1322 p2 = p + struct_len;
1323 l2 = *buflen - struct_len;
1325 if (!baseaddr) {
1326 baseaddr = p;
1329 switch (uLevel) {
1330 case 0:
1331 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1332 break;
1334 case 1:
1335 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1336 SIVAL(p,18,service->type);
1337 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1338 len += CopyAndAdvance(&p2,service->comment,&l2);
1339 break;
1342 if (stringbuf) {
1343 *buf = p + struct_len;
1344 *buflen -= struct_len;
1345 *stringbuf = p2;
1346 *stringspace = l2;
1347 } else {
1348 *buf = p2;
1349 *buflen -= len;
1351 return len;
1355 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1357 return(strcmp(s1->name,s2->name));
1360 /****************************************************************************
1361 View list of servers available (or possibly domains). The info is
1362 extracted from lists saved by nmbd on the local host.
1363 ****************************************************************************/
1365 static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1366 char *param, int tpscnt,
1367 char *data, int tdscnt,
1368 int mdrcnt, int mprcnt, char **rdata,
1369 char **rparam, int *rdata_len, int *rparam_len)
1371 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1372 char *str2 = skip_string(param,tpscnt,str1);
1373 char *p = skip_string(param,tpscnt,str2);
1374 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1375 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1376 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1377 char *p2;
1378 int data_len, fixed_len, string_len;
1379 int f_len = 0, s_len = 0;
1380 struct srv_info_struct *servers=NULL;
1381 int counted=0,total=0;
1382 int i,missed;
1383 fstring domain;
1384 bool domain_request;
1385 bool local_request;
1387 if (!str1 || !str2 || !p) {
1388 return False;
1391 /* If someone sets all the bits they don't really mean to set
1392 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1393 known servers. */
1395 if (servertype == SV_TYPE_ALL) {
1396 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1399 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1400 any other bit (they may just set this bit on its own) they
1401 want all the locally seen servers. However this bit can be
1402 set on its own so set the requested servers to be
1403 ALL - DOMAIN_ENUM. */
1405 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1406 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1409 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1410 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1412 p += 8;
1414 if (!prefix_ok(str1,"WrLehD")) {
1415 return False;
1417 if (!check_server_info(uLevel,str2)) {
1418 return False;
1421 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1422 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1423 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1425 if (strcmp(str1, "WrLehDz") == 0) {
1426 if (skip_string(param,tpscnt,p) == NULL) {
1427 return False;
1429 pull_ascii_fstring(domain, p);
1430 } else {
1431 fstrcpy(domain, lp_workgroup());
1434 if (lp_browse_list()) {
1435 total = get_server_info(servertype,&servers,domain);
1438 data_len = fixed_len = string_len = 0;
1439 missed = 0;
1441 if (total > 0) {
1442 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1446 char *lastname=NULL;
1448 for (i=0;i<total;i++) {
1449 struct srv_info_struct *s = &servers[i];
1451 if (lastname && strequal(lastname,s->name)) {
1452 continue;
1454 lastname = s->name;
1455 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1456 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1457 s->name, s->type, s->comment, s->domain));
1459 if (data_len <= buf_len) {
1460 counted++;
1461 fixed_len += f_len;
1462 string_len += s_len;
1463 } else {
1464 missed++;
1469 *rdata_len = fixed_len + string_len;
1470 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1471 if (!*rdata) {
1472 return False;
1475 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1476 p = *rdata;
1477 f_len = fixed_len;
1478 s_len = string_len;
1481 char *lastname=NULL;
1482 int count2 = counted;
1484 for (i = 0; i < total && count2;i++) {
1485 struct srv_info_struct *s = &servers[i];
1487 if (lastname && strequal(lastname,s->name)) {
1488 continue;
1490 lastname = s->name;
1491 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1492 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1493 s->name, s->type, s->comment, s->domain));
1494 count2--;
1498 *rparam_len = 8;
1499 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1500 if (!*rparam) {
1501 return False;
1503 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1504 SSVAL(*rparam,2,0);
1505 SSVAL(*rparam,4,counted);
1506 SSVAL(*rparam,6,counted+missed);
1508 SAFE_FREE(servers);
1510 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1511 domain,uLevel,counted,counted+missed));
1513 return True;
1516 /****************************************************************************
1517 command 0x34 - suspected of being a "Lookup Names" stub api
1518 ****************************************************************************/
1520 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1521 char *param, int tpscnt,
1522 char *data, int tdscnt,
1523 int mdrcnt, int mprcnt, char **rdata,
1524 char **rparam, int *rdata_len, int *rparam_len)
1526 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1527 char *str2 = skip_string(param,tpscnt,str1);
1528 char *p = skip_string(param,tpscnt,str2);
1529 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1530 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1531 int counted=0;
1532 int missed=0;
1534 if (!str1 || !str2 || !p) {
1535 return False;
1538 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1539 str1, str2, p, uLevel, buf_len));
1541 if (!prefix_ok(str1,"zWrLeh")) {
1542 return False;
1545 *rdata_len = 0;
1547 *rparam_len = 8;
1548 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1549 if (!*rparam) {
1550 return False;
1553 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1554 SSVAL(*rparam,2,0);
1555 SSVAL(*rparam,4,counted);
1556 SSVAL(*rparam,6,counted+missed);
1558 return True;
1561 /****************************************************************************
1562 get info about a share
1563 ****************************************************************************/
1565 static bool check_share_info(int uLevel, char* id)
1567 switch( uLevel ) {
1568 case 0:
1569 if (strcmp(id,"B13") != 0) {
1570 return False;
1572 break;
1573 case 1:
1574 if (strcmp(id,"B13BWz") != 0) {
1575 return False;
1577 break;
1578 case 2:
1579 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1580 return False;
1582 break;
1583 case 91:
1584 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1585 return False;
1587 break;
1588 default:
1589 return False;
1591 return True;
1594 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1595 char** buf, int* buflen,
1596 char** stringbuf, int* stringspace, char* baseaddr)
1598 int struct_len;
1599 char* p;
1600 char* p2;
1601 int l2;
1602 int len;
1604 switch( uLevel ) {
1605 case 0:
1606 struct_len = 13;
1607 break;
1608 case 1:
1609 struct_len = 20;
1610 break;
1611 case 2:
1612 struct_len = 40;
1613 break;
1614 case 91:
1615 struct_len = 68;
1616 break;
1617 default:
1618 return -1;
1621 if (!buf) {
1622 len = 0;
1624 if (uLevel > 0) {
1625 len += StrlenExpanded(conn,snum,lp_comment(snum));
1627 if (uLevel > 1) {
1628 len += strlen(lp_pathname(snum)) + 1;
1630 if (buflen) {
1631 *buflen = struct_len;
1633 if (stringspace) {
1634 *stringspace = len;
1636 return struct_len + len;
1639 len = struct_len;
1640 p = *buf;
1641 if ((*buflen) < struct_len) {
1642 return -1;
1645 if (stringbuf) {
1646 p2 = *stringbuf;
1647 l2 = *stringspace;
1648 } else {
1649 p2 = p + struct_len;
1650 l2 = (*buflen) - struct_len;
1653 if (!baseaddr) {
1654 baseaddr = p;
1657 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1659 if (uLevel > 0) {
1660 int type;
1662 SCVAL(p,13,0);
1663 type = STYPE_DISKTREE;
1664 if (lp_print_ok(snum)) {
1665 type = STYPE_PRINTQ;
1667 if (strequal("IPC",lp_fstype(snum))) {
1668 type = STYPE_IPC;
1670 SSVAL(p,14,type); /* device type */
1671 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1672 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1675 if (uLevel > 1) {
1676 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1677 SSVALS(p,22,-1); /* max uses */
1678 SSVAL(p,24,1); /* current uses */
1679 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1680 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1681 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1684 if (uLevel > 2) {
1685 memset(p+40,0,SHPWLEN+2);
1686 SSVAL(p,50,0);
1687 SIVAL(p,52,0);
1688 SSVAL(p,56,0);
1689 SSVAL(p,58,0);
1690 SIVAL(p,60,0);
1691 SSVAL(p,64,0);
1692 SSVAL(p,66,0);
1695 if (stringbuf) {
1696 (*buf) = p + struct_len;
1697 (*buflen) -= struct_len;
1698 (*stringbuf) = p2;
1699 (*stringspace) = l2;
1700 } else {
1701 (*buf) = p2;
1702 (*buflen) -= len;
1705 return len;
1708 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1709 char *param, int tpscnt,
1710 char *data, int tdscnt,
1711 int mdrcnt,int mprcnt,
1712 char **rdata,char **rparam,
1713 int *rdata_len,int *rparam_len)
1715 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1716 char *str2 = skip_string(param,tpscnt,str1);
1717 char *netname = skip_string(param,tpscnt,str2);
1718 char *p = skip_string(param,tpscnt,netname);
1719 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1720 int snum;
1722 if (!str1 || !str2 || !netname || !p) {
1723 return False;
1726 snum = find_service(netname);
1727 if (snum < 0) {
1728 return False;
1731 /* check it's a supported varient */
1732 if (!prefix_ok(str1,"zWrLh")) {
1733 return False;
1735 if (!check_share_info(uLevel,str2)) {
1736 return False;
1739 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1740 if (!*rdata) {
1741 return False;
1743 p = *rdata;
1744 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1745 if (*rdata_len < 0) {
1746 return False;
1749 *rparam_len = 6;
1750 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1751 if (!*rparam) {
1752 return False;
1754 SSVAL(*rparam,0,NERR_Success);
1755 SSVAL(*rparam,2,0); /* converter word */
1756 SSVAL(*rparam,4,*rdata_len);
1758 return True;
1761 /****************************************************************************
1762 View the list of available shares.
1764 This function is the server side of the NetShareEnum() RAP call.
1765 It fills the return buffer with share names and share comments.
1766 Note that the return buffer normally (in all known cases) allows only
1767 twelve byte strings for share names (plus one for a nul terminator).
1768 Share names longer than 12 bytes must be skipped.
1769 ****************************************************************************/
1771 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1772 char *param, int tpscnt,
1773 char *data, int tdscnt,
1774 int mdrcnt,
1775 int mprcnt,
1776 char **rdata,
1777 char **rparam,
1778 int *rdata_len,
1779 int *rparam_len )
1781 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1782 char *str2 = skip_string(param,tpscnt,str1);
1783 char *p = skip_string(param,tpscnt,str2);
1784 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1785 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1786 char *p2;
1787 int count = 0;
1788 int total=0,counted=0;
1789 bool missed = False;
1790 int i;
1791 int data_len, fixed_len, string_len;
1792 int f_len = 0, s_len = 0;
1794 if (!str1 || !str2 || !p) {
1795 return False;
1798 if (!prefix_ok(str1,"WrLeh")) {
1799 return False;
1801 if (!check_share_info(uLevel,str2)) {
1802 return False;
1805 /* Ensure all the usershares are loaded. */
1806 become_root();
1807 load_registry_shares();
1808 count = load_usershare_shares();
1809 unbecome_root();
1811 data_len = fixed_len = string_len = 0;
1812 for (i=0;i<count;i++) {
1813 fstring servicename_dos;
1814 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1815 continue;
1817 push_ascii_fstring(servicename_dos, lp_servicename(i));
1818 /* Maximum name length = 13. */
1819 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1820 total++;
1821 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1822 if (data_len <= buf_len) {
1823 counted++;
1824 fixed_len += f_len;
1825 string_len += s_len;
1826 } else {
1827 missed = True;
1832 *rdata_len = fixed_len + string_len;
1833 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1834 if (!*rdata) {
1835 return False;
1838 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1839 p = *rdata;
1840 f_len = fixed_len;
1841 s_len = string_len;
1843 for( i = 0; i < count; i++ ) {
1844 fstring servicename_dos;
1845 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1846 continue;
1849 push_ascii_fstring(servicename_dos, lp_servicename(i));
1850 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1851 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1852 break;
1857 *rparam_len = 8;
1858 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1859 if (!*rparam) {
1860 return False;
1862 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1863 SSVAL(*rparam,2,0);
1864 SSVAL(*rparam,4,counted);
1865 SSVAL(*rparam,6,total);
1867 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1868 counted,total,uLevel,
1869 buf_len,*rdata_len,mdrcnt));
1871 return True;
1874 /****************************************************************************
1875 Add a share
1876 ****************************************************************************/
1878 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1879 char *param, int tpscnt,
1880 char *data, int tdscnt,
1881 int mdrcnt,int mprcnt,
1882 char **rdata,char **rparam,
1883 int *rdata_len,int *rparam_len)
1885 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1886 char *str2 = skip_string(param,tpscnt,str1);
1887 char *p = skip_string(param,tpscnt,str2);
1888 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1889 fstring sharename;
1890 fstring comment;
1891 char *pathname = NULL;
1892 char *command, *cmdname;
1893 unsigned int offset;
1894 int snum;
1895 int res = ERRunsup;
1896 size_t converted_size;
1898 if (!str1 || !str2 || !p) {
1899 return False;
1902 /* check it's a supported varient */
1903 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1904 return False;
1906 if (!check_share_info(uLevel,str2)) {
1907 return False;
1909 if (uLevel != 2) {
1910 return False;
1913 /* Do we have a string ? */
1914 if (skip_string(data,mdrcnt,data) == NULL) {
1915 return False;
1917 pull_ascii_fstring(sharename,data);
1918 snum = find_service(sharename);
1919 if (snum >= 0) { /* already exists */
1920 res = ERRfilexists;
1921 goto error_exit;
1924 if (mdrcnt < 28) {
1925 return False;
1928 /* only support disk share adds */
1929 if (SVAL(data,14)!=STYPE_DISKTREE) {
1930 return False;
1933 offset = IVAL(data, 16);
1934 if (offset >= mdrcnt) {
1935 res = ERRinvalidparam;
1936 goto error_exit;
1939 /* Do we have a string ? */
1940 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1941 return False;
1943 pull_ascii_fstring(comment, offset? (data+offset) : "");
1945 offset = IVAL(data, 26);
1947 if (offset >= mdrcnt) {
1948 res = ERRinvalidparam;
1949 goto error_exit;
1952 /* Do we have a string ? */
1953 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1954 return False;
1957 if (!pull_ascii_talloc(talloc_tos(), &pathname,
1958 offset ? (data+offset) : "", &converted_size))
1960 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
1961 strerror(errno)));
1964 if (!pathname) {
1965 return false;
1968 string_replace(sharename, '"', ' ');
1969 string_replace(pathname, '"', ' ');
1970 string_replace(comment, '"', ' ');
1972 cmdname = lp_add_share_cmd();
1974 if (!cmdname || *cmdname == '\0') {
1975 return False;
1978 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1979 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
1980 pathname, comment) == -1) {
1981 return false;
1984 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1986 if ((res = smbrun(command, NULL)) != 0) {
1987 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
1988 command, res ));
1989 SAFE_FREE(command);
1990 res = ERRnoaccess;
1991 goto error_exit;
1992 } else {
1993 SAFE_FREE(command);
1994 message_send_all(smbd_messaging_context(),
1995 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1998 *rparam_len = 6;
1999 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2000 if (!*rparam) {
2001 return False;
2003 SSVAL(*rparam,0,NERR_Success);
2004 SSVAL(*rparam,2,0); /* converter word */
2005 SSVAL(*rparam,4,*rdata_len);
2006 *rdata_len = 0;
2008 return True;
2010 error_exit:
2012 *rparam_len = 4;
2013 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2014 if (!*rparam) {
2015 return False;
2017 *rdata_len = 0;
2018 SSVAL(*rparam,0,res);
2019 SSVAL(*rparam,2,0);
2020 return True;
2023 /****************************************************************************
2024 view list of groups available
2025 ****************************************************************************/
2027 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2028 char *param, int tpscnt,
2029 char *data, int tdscnt,
2030 int mdrcnt,int mprcnt,
2031 char **rdata,char **rparam,
2032 int *rdata_len,int *rparam_len)
2034 int i;
2035 int errflags=0;
2036 int resume_context, cli_buf_size;
2037 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2038 char *str2 = skip_string(param,tpscnt,str1);
2039 char *p = skip_string(param,tpscnt,str2);
2041 uint32_t num_groups;
2042 uint32_t resume_handle;
2043 struct rpc_pipe_client *samr_pipe;
2044 struct policy_handle samr_handle, domain_handle;
2045 NTSTATUS status;
2047 if (!str1 || !str2 || !p) {
2048 return False;
2051 if (strcmp(str1,"WrLeh") != 0) {
2052 return False;
2055 /* parameters
2056 * W-> resume context (number of users to skip)
2057 * r -> return parameter pointer to receive buffer
2058 * L -> length of receive buffer
2059 * e -> return parameter number of entries
2060 * h -> return parameter total number of users
2063 if (strcmp("B21",str2) != 0) {
2064 return False;
2067 status = rpc_pipe_open_internal(
2068 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2069 conn->server_info, &samr_pipe);
2070 if (!NT_STATUS_IS_OK(status)) {
2071 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2072 nt_errstr(status)));
2073 return false;
2076 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2077 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2078 if (!NT_STATUS_IS_OK(status)) {
2079 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2080 nt_errstr(status)));
2081 return false;
2084 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2085 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2086 get_global_sam_sid(), &domain_handle);
2087 if (!NT_STATUS_IS_OK(status)) {
2088 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2089 nt_errstr(status)));
2090 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2091 return false;
2094 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2095 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2096 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2097 "%d\n", resume_context, cli_buf_size));
2099 *rdata_len = cli_buf_size;
2100 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2101 if (!*rdata) {
2102 return False;
2105 p = *rdata;
2107 errflags = NERR_Success;
2108 num_groups = 0;
2109 resume_handle = 0;
2111 while (true) {
2112 struct samr_SamArray *sam_entries;
2113 uint32_t num_entries;
2115 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2116 &domain_handle,
2117 &resume_handle,
2118 &sam_entries, 1,
2119 &num_entries);
2120 if (!NT_STATUS_IS_OK(status)) {
2121 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2122 "%s\n", nt_errstr(status)));
2123 break;
2126 if (num_entries == 0) {
2127 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2128 "no entries -- done\n"));
2129 break;
2132 for(i=0; i<num_entries; i++) {
2133 const char *name;
2135 name = sam_entries->entries[i].name.string;
2137 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2138 /* set overflow error */
2139 DEBUG(3,("overflow on entry %d group %s\n", i,
2140 name));
2141 errflags=234;
2142 break;
2145 /* truncate the name at 21 chars. */
2146 memset(p, 0, 21);
2147 strlcpy(p, name, 21);
2148 DEBUG(10,("adding entry %d group %s\n", i, p));
2149 p += 21;
2150 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2151 * idea why... */
2152 num_groups += 1;
2155 if (errflags != NERR_Success) {
2156 break;
2159 TALLOC_FREE(sam_entries);
2162 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2163 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2165 *rdata_len = PTR_DIFF(p,*rdata);
2167 *rparam_len = 8;
2168 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2169 if (!*rparam) {
2170 return False;
2172 SSVAL(*rparam, 0, errflags);
2173 SSVAL(*rparam, 2, 0); /* converter word */
2174 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2175 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2177 return(True);
2180 /*******************************************************************
2181 Get groups that a user is a member of.
2182 ******************************************************************/
2184 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2185 char *param, int tpscnt,
2186 char *data, int tdscnt,
2187 int mdrcnt,int mprcnt,
2188 char **rdata,char **rparam,
2189 int *rdata_len,int *rparam_len)
2191 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2192 char *str2 = skip_string(param,tpscnt,str1);
2193 char *UserName = skip_string(param,tpscnt,str2);
2194 char *p = skip_string(param,tpscnt,UserName);
2195 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2196 const char *level_string;
2197 int count=0;
2198 bool ret = False;
2199 uint32_t i;
2200 char *endp = NULL;
2202 struct rpc_pipe_client *samr_pipe;
2203 struct policy_handle samr_handle, domain_handle, user_handle;
2204 struct lsa_String name;
2205 struct lsa_Strings names;
2206 struct samr_Ids type, rid;
2207 struct samr_RidWithAttributeArray *rids;
2208 NTSTATUS status;
2210 if (!str1 || !str2 || !UserName || !p) {
2211 return False;
2214 *rparam_len = 8;
2215 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2216 if (!*rparam) {
2217 return False;
2220 /* check it's a supported varient */
2222 if ( strcmp(str1,"zWrLeh") != 0 )
2223 return False;
2225 switch( uLevel ) {
2226 case 0:
2227 level_string = "B21";
2228 break;
2229 default:
2230 return False;
2233 if (strcmp(level_string,str2) != 0)
2234 return False;
2236 *rdata_len = mdrcnt + 1024;
2237 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2238 if (!*rdata) {
2239 return False;
2242 SSVAL(*rparam,0,NERR_Success);
2243 SSVAL(*rparam,2,0); /* converter word */
2245 p = *rdata;
2246 endp = *rdata + *rdata_len;
2248 status = rpc_pipe_open_internal(
2249 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2250 conn->server_info, &samr_pipe);
2251 if (!NT_STATUS_IS_OK(status)) {
2252 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2253 nt_errstr(status)));
2254 return false;
2257 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2258 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2259 if (!NT_STATUS_IS_OK(status)) {
2260 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2261 nt_errstr(status)));
2262 return false;
2265 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2266 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2267 get_global_sam_sid(), &domain_handle);
2268 if (!NT_STATUS_IS_OK(status)) {
2269 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2270 nt_errstr(status)));
2271 goto close_sam;
2274 name.string = UserName;
2276 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2277 &domain_handle, 1, &name,
2278 &rid, &type);
2279 if (!NT_STATUS_IS_OK(status)) {
2280 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2281 nt_errstr(status)));
2282 goto close_domain;
2285 if (type.ids[0] != SID_NAME_USER) {
2286 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2287 sid_type_lookup(type.ids[0])));
2288 goto close_domain;
2291 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2292 &domain_handle,
2293 SAMR_USER_ACCESS_GET_GROUPS,
2294 rid.ids[0], &user_handle);
2295 if (!NT_STATUS_IS_OK(status)) {
2296 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2297 nt_errstr(status)));
2298 goto close_domain;
2301 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2302 &user_handle, &rids);
2303 if (!NT_STATUS_IS_OK(status)) {
2304 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2305 nt_errstr(status)));
2306 goto close_user;
2309 for (i=0; i<rids->count; i++) {
2311 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2312 &domain_handle,
2313 1, &rids->rids[i].rid,
2314 &names, &type);
2315 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2316 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2317 p += 21;
2318 count++;
2322 *rdata_len = PTR_DIFF(p,*rdata);
2324 SSVAL(*rparam,4,count); /* is this right?? */
2325 SSVAL(*rparam,6,count); /* is this right?? */
2327 ret = True;
2329 close_user:
2330 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2331 close_domain:
2332 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2333 close_sam:
2334 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2336 return ret;
2339 /*******************************************************************
2340 Get all users.
2341 ******************************************************************/
2343 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2344 char *param, int tpscnt,
2345 char *data, int tdscnt,
2346 int mdrcnt,int mprcnt,
2347 char **rdata,char **rparam,
2348 int *rdata_len,int *rparam_len)
2350 int count_sent=0;
2351 int num_users=0;
2352 int errflags=0;
2353 int i, resume_context, cli_buf_size;
2354 uint32_t resume_handle;
2356 struct rpc_pipe_client *samr_pipe;
2357 struct policy_handle samr_handle, domain_handle;
2358 NTSTATUS status;
2360 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2361 char *str2 = skip_string(param,tpscnt,str1);
2362 char *p = skip_string(param,tpscnt,str2);
2363 char *endp = NULL;
2365 if (!str1 || !str2 || !p) {
2366 return False;
2369 if (strcmp(str1,"WrLeh") != 0)
2370 return False;
2371 /* parameters
2372 * W-> resume context (number of users to skip)
2373 * r -> return parameter pointer to receive buffer
2374 * L -> length of receive buffer
2375 * e -> return parameter number of entries
2376 * h -> return parameter total number of users
2379 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2380 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2381 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2382 resume_context, cli_buf_size));
2384 *rparam_len = 8;
2385 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2386 if (!*rparam) {
2387 return False;
2390 /* check it's a supported varient */
2391 if (strcmp("B21",str2) != 0)
2392 return False;
2394 *rdata_len = cli_buf_size;
2395 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2396 if (!*rdata) {
2397 return False;
2400 p = *rdata;
2401 endp = *rdata + *rdata_len;
2403 status = rpc_pipe_open_internal(
2404 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2405 conn->server_info, &samr_pipe);
2406 if (!NT_STATUS_IS_OK(status)) {
2407 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2408 nt_errstr(status)));
2409 return false;
2412 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2413 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2414 if (!NT_STATUS_IS_OK(status)) {
2415 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2416 nt_errstr(status)));
2417 return false;
2420 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2421 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2422 get_global_sam_sid(), &domain_handle);
2423 if (!NT_STATUS_IS_OK(status)) {
2424 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2425 nt_errstr(status)));
2426 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2427 return false;
2430 errflags=NERR_Success;
2432 resume_handle = 0;
2434 while (true) {
2435 struct samr_SamArray *sam_entries;
2436 uint32_t num_entries;
2438 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2439 &domain_handle,
2440 &resume_handle,
2441 0, &sam_entries, 1,
2442 &num_entries);
2444 if (!NT_STATUS_IS_OK(status)) {
2445 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2446 "%s\n", nt_errstr(status)));
2447 break;
2450 if (num_entries == 0) {
2451 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2452 "no entries -- done\n"));
2453 break;
2456 for (i=0; i<num_entries; i++) {
2457 const char *name;
2459 name = sam_entries->entries[i].name.string;
2461 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2462 &&(strlen(name)<=21)) {
2463 strlcpy(p,name,PTR_DIFF(endp,p));
2464 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2465 "username %s\n",count_sent,p));
2466 p += 21;
2467 count_sent++;
2468 } else {
2469 /* set overflow error */
2470 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2471 "username %s\n",count_sent,name));
2472 errflags=234;
2473 break;
2477 if (errflags != NERR_Success) {
2478 break;
2481 TALLOC_FREE(sam_entries);
2484 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2485 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2487 *rdata_len = PTR_DIFF(p,*rdata);
2489 SSVAL(*rparam,0,errflags);
2490 SSVAL(*rparam,2,0); /* converter word */
2491 SSVAL(*rparam,4,count_sent); /* is this right?? */
2492 SSVAL(*rparam,6,num_users); /* is this right?? */
2494 return True;
2497 /****************************************************************************
2498 Get the time of day info.
2499 ****************************************************************************/
2501 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2502 char *param, int tpscnt,
2503 char *data, int tdscnt,
2504 int mdrcnt,int mprcnt,
2505 char **rdata,char **rparam,
2506 int *rdata_len,int *rparam_len)
2508 struct tm *t;
2509 time_t unixdate = time(NULL);
2510 char *p;
2512 *rparam_len = 4;
2513 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2514 if (!*rparam) {
2515 return False;
2518 *rdata_len = 21;
2519 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2520 if (!*rdata) {
2521 return False;
2524 SSVAL(*rparam,0,NERR_Success);
2525 SSVAL(*rparam,2,0); /* converter word */
2527 p = *rdata;
2529 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2530 by NT in a "net time" operation,
2531 it seems to ignore the one below */
2533 /* the client expects to get localtime, not GMT, in this bit
2534 (I think, this needs testing) */
2535 t = localtime(&unixdate);
2536 if (!t) {
2537 return False;
2540 SIVAL(p,4,0); /* msecs ? */
2541 SCVAL(p,8,t->tm_hour);
2542 SCVAL(p,9,t->tm_min);
2543 SCVAL(p,10,t->tm_sec);
2544 SCVAL(p,11,0); /* hundredths of seconds */
2545 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2546 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2547 SCVAL(p,16,t->tm_mday);
2548 SCVAL(p,17,t->tm_mon + 1);
2549 SSVAL(p,18,1900+t->tm_year);
2550 SCVAL(p,20,t->tm_wday);
2552 return True;
2555 /****************************************************************************
2556 Set the user password.
2557 *****************************************************************************/
2559 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2560 char *param, int tpscnt,
2561 char *data, int tdscnt,
2562 int mdrcnt,int mprcnt,
2563 char **rdata,char **rparam,
2564 int *rdata_len,int *rparam_len)
2566 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2567 char *p = NULL;
2568 fstring user;
2569 fstring pass1,pass2;
2571 /* Skip 2 strings. */
2572 p = skip_string(param,tpscnt,np);
2573 p = skip_string(param,tpscnt,p);
2575 if (!np || !p) {
2576 return False;
2579 /* Do we have a string ? */
2580 if (skip_string(param,tpscnt,p) == NULL) {
2581 return False;
2583 pull_ascii_fstring(user,p);
2585 p = skip_string(param,tpscnt,p);
2586 if (!p) {
2587 return False;
2590 memset(pass1,'\0',sizeof(pass1));
2591 memset(pass2,'\0',sizeof(pass2));
2593 * We use 31 here not 32 as we're checking
2594 * the last byte we want to access is safe.
2596 if (!is_offset_safe(param,tpscnt,p,31)) {
2597 return False;
2599 memcpy(pass1,p,16);
2600 memcpy(pass2,p+16,16);
2602 *rparam_len = 4;
2603 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2604 if (!*rparam) {
2605 return False;
2608 *rdata_len = 0;
2610 SSVAL(*rparam,0,NERR_badpass);
2611 SSVAL(*rparam,2,0); /* converter word */
2613 DEBUG(3,("Set password for <%s>\n",user));
2616 * Attempt to verify the old password against smbpasswd entries
2617 * Win98 clients send old and new password in plaintext for this call.
2621 auth_serversupplied_info *server_info = NULL;
2622 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2624 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2626 become_root();
2627 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2628 SSVAL(*rparam,0,NERR_Success);
2630 unbecome_root();
2632 TALLOC_FREE(server_info);
2634 data_blob_clear_free(&password);
2638 * If the plaintext change failed, attempt
2639 * the old encrypted method. NT will generate this
2640 * after trying the samr method. Note that this
2641 * method is done as a last resort as this
2642 * password change method loses the NT password hash
2643 * and cannot change the UNIX password as no plaintext
2644 * is received.
2647 if(SVAL(*rparam,0) != NERR_Success) {
2648 struct samu *hnd = NULL;
2650 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2651 become_root();
2652 if (change_lanman_password(hnd,(uchar *)pass2)) {
2653 SSVAL(*rparam,0,NERR_Success);
2655 unbecome_root();
2656 TALLOC_FREE(hnd);
2660 memset((char *)pass1,'\0',sizeof(fstring));
2661 memset((char *)pass2,'\0',sizeof(fstring));
2663 return(True);
2666 /****************************************************************************
2667 Set the user password (SamOEM version - gets plaintext).
2668 ****************************************************************************/
2670 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2671 char *param, int tpscnt,
2672 char *data, int tdscnt,
2673 int mdrcnt,int mprcnt,
2674 char **rdata,char **rparam,
2675 int *rdata_len,int *rparam_len)
2677 fstring user;
2678 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2679 *rparam_len = 2;
2680 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2681 if (!*rparam) {
2682 return False;
2685 if (!p) {
2686 return False;
2688 *rdata_len = 0;
2690 SSVAL(*rparam,0,NERR_badpass);
2693 * Check the parameter definition is correct.
2696 /* Do we have a string ? */
2697 if (skip_string(param,tpscnt,p) == 0) {
2698 return False;
2700 if(!strequal(p, "zsT")) {
2701 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2702 return False;
2704 p = skip_string(param, tpscnt, p);
2705 if (!p) {
2706 return False;
2709 /* Do we have a string ? */
2710 if (skip_string(param,tpscnt,p) == 0) {
2711 return False;
2713 if(!strequal(p, "B516B16")) {
2714 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2715 return False;
2717 p = skip_string(param,tpscnt,p);
2718 if (!p) {
2719 return False;
2721 /* Do we have a string ? */
2722 if (skip_string(param,tpscnt,p) == 0) {
2723 return False;
2725 p += pull_ascii_fstring(user,p);
2727 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2730 * Pass the user through the NT -> unix user mapping
2731 * function.
2734 (void)map_username(user);
2736 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2737 SSVAL(*rparam,0,NERR_Success);
2740 return(True);
2743 /****************************************************************************
2744 delete a print job
2745 Form: <W> <>
2746 ****************************************************************************/
2748 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2749 char *param, int tpscnt,
2750 char *data, int tdscnt,
2751 int mdrcnt,int mprcnt,
2752 char **rdata,char **rparam,
2753 int *rdata_len,int *rparam_len)
2755 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2756 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2757 char *str2 = skip_string(param,tpscnt,str1);
2758 char *p = skip_string(param,tpscnt,str2);
2759 uint32 jobid;
2760 int snum;
2761 fstring sharename;
2762 int errcode;
2763 WERROR werr = WERR_OK;
2765 if (!str1 || !str2 || !p) {
2766 return False;
2769 * We use 1 here not 2 as we're checking
2770 * the last byte we want to access is safe.
2772 if (!is_offset_safe(param,tpscnt,p,1)) {
2773 return False;
2775 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2776 return False;
2778 /* check it's a supported varient */
2779 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2780 return(False);
2782 *rparam_len = 4;
2783 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2784 if (!*rparam) {
2785 return False;
2787 *rdata_len = 0;
2789 if (!print_job_exists(sharename, jobid)) {
2790 errcode = NERR_JobNotFound;
2791 goto out;
2794 snum = lp_servicenumber( sharename);
2795 if (snum == -1) {
2796 errcode = NERR_DestNotFound;
2797 goto out;
2800 errcode = NERR_notsupported;
2802 switch (function) {
2803 case 81: /* delete */
2804 if (print_job_delete(conn->server_info, snum, jobid, &werr))
2805 errcode = NERR_Success;
2806 break;
2807 case 82: /* pause */
2808 if (print_job_pause(conn->server_info, snum, jobid, &werr))
2809 errcode = NERR_Success;
2810 break;
2811 case 83: /* resume */
2812 if (print_job_resume(conn->server_info, snum, jobid, &werr))
2813 errcode = NERR_Success;
2814 break;
2817 if (!W_ERROR_IS_OK(werr))
2818 errcode = W_ERROR_V(werr);
2820 out:
2821 SSVAL(*rparam,0,errcode);
2822 SSVAL(*rparam,2,0); /* converter word */
2824 return(True);
2827 /****************************************************************************
2828 Purge a print queue - or pause or resume it.
2829 ****************************************************************************/
2831 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2832 char *param, int tpscnt,
2833 char *data, int tdscnt,
2834 int mdrcnt,int mprcnt,
2835 char **rdata,char **rparam,
2836 int *rdata_len,int *rparam_len)
2838 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2839 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2840 char *str2 = skip_string(param,tpscnt,str1);
2841 char *QueueName = skip_string(param,tpscnt,str2);
2842 int errcode = NERR_notsupported;
2843 int snum;
2844 WERROR werr = WERR_OK;
2846 if (!str1 || !str2 || !QueueName) {
2847 return False;
2850 /* check it's a supported varient */
2851 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2852 return(False);
2854 *rparam_len = 4;
2855 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2856 if (!*rparam) {
2857 return False;
2859 *rdata_len = 0;
2861 if (skip_string(param,tpscnt,QueueName) == NULL) {
2862 return False;
2864 snum = print_queue_snum(QueueName);
2866 if (snum == -1) {
2867 errcode = NERR_JobNotFound;
2868 goto out;
2871 switch (function) {
2872 case 74: /* Pause queue */
2873 werr = print_queue_pause(conn->server_info, snum);
2874 break;
2875 case 75: /* Resume queue */
2876 werr = print_queue_resume(conn->server_info, snum);
2877 break;
2878 case 103: /* Purge */
2879 werr = print_queue_purge(conn->server_info, snum);
2880 break;
2881 default:
2882 werr = WERR_NOT_SUPPORTED;
2883 break;
2886 errcode = W_ERROR_V(werr);
2888 out:
2889 SSVAL(*rparam,0,errcode);
2890 SSVAL(*rparam,2,0); /* converter word */
2892 return(True);
2895 /****************************************************************************
2896 set the property of a print job (undocumented?)
2897 ? function = 0xb -> set name of print job
2898 ? function = 0x6 -> move print job up/down
2899 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2900 or <WWsTP> <WB21BB16B10zWWzDDz>
2901 ****************************************************************************/
2903 static int check_printjob_info(struct pack_desc* desc,
2904 int uLevel, char* id)
2906 desc->subformat = NULL;
2907 switch( uLevel ) {
2908 case 0: desc->format = "W"; break;
2909 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2910 case 2: desc->format = "WWzWWDDzz"; break;
2911 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2912 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2913 default:
2914 DEBUG(0,("check_printjob_info: invalid level %d\n",
2915 uLevel ));
2916 return False;
2918 if (id == NULL || strcmp(desc->format,id) != 0) {
2919 DEBUG(0,("check_printjob_info: invalid format %s\n",
2920 id ? id : "<NULL>" ));
2921 return False;
2923 return True;
2926 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2927 char *param, int tpscnt,
2928 char *data, int tdscnt,
2929 int mdrcnt,int mprcnt,
2930 char **rdata,char **rparam,
2931 int *rdata_len,int *rparam_len)
2933 struct pack_desc desc;
2934 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2935 char *str2 = skip_string(param,tpscnt,str1);
2936 char *p = skip_string(param,tpscnt,str2);
2937 uint32 jobid;
2938 fstring sharename;
2939 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2940 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2941 int place, errcode;
2943 if (!str1 || !str2 || !p) {
2944 return False;
2947 * We use 1 here not 2 as we're checking
2948 * the last byte we want to access is safe.
2950 if (!is_offset_safe(param,tpscnt,p,1)) {
2951 return False;
2953 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2954 return False;
2955 *rparam_len = 4;
2956 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2957 if (!*rparam) {
2958 return False;
2961 if (!share_defined(sharename)) {
2962 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2963 sharename));
2964 return False;
2967 *rdata_len = 0;
2969 /* check it's a supported varient */
2970 if ((strcmp(str1,"WWsTP")) ||
2971 (!check_printjob_info(&desc,uLevel,str2)))
2972 return(False);
2974 if (!print_job_exists(sharename, jobid)) {
2975 errcode=NERR_JobNotFound;
2976 goto out;
2979 errcode = NERR_notsupported;
2981 switch (function) {
2982 case 0x6:
2983 /* change job place in the queue,
2984 data gives the new place */
2985 place = SVAL(data,0);
2986 if (print_job_set_place(sharename, jobid, place)) {
2987 errcode=NERR_Success;
2989 break;
2991 case 0xb:
2992 /* change print job name, data gives the name */
2993 if (print_job_set_name(sharename, jobid, data)) {
2994 errcode=NERR_Success;
2996 break;
2998 default:
2999 return False;
3002 out:
3003 SSVALS(*rparam,0,errcode);
3004 SSVAL(*rparam,2,0); /* converter word */
3006 return(True);
3010 /****************************************************************************
3011 Get info about the server.
3012 ****************************************************************************/
3014 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3015 char *param, int tpscnt,
3016 char *data, int tdscnt,
3017 int mdrcnt,int mprcnt,
3018 char **rdata,char **rparam,
3019 int *rdata_len,int *rparam_len)
3021 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3022 char *str2 = skip_string(param,tpscnt,str1);
3023 char *p = skip_string(param,tpscnt,str2);
3024 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3025 char *p2;
3026 int struct_len;
3028 if (!str1 || !str2 || !p) {
3029 return False;
3032 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3034 /* check it's a supported varient */
3035 if (!prefix_ok(str1,"WrLh")) {
3036 return False;
3039 switch( uLevel ) {
3040 case 0:
3041 if (strcmp(str2,"B16") != 0) {
3042 return False;
3044 struct_len = 16;
3045 break;
3046 case 1:
3047 if (strcmp(str2,"B16BBDz") != 0) {
3048 return False;
3050 struct_len = 26;
3051 break;
3052 case 2:
3053 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3054 return False;
3056 struct_len = 134;
3057 break;
3058 case 3:
3059 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3060 return False;
3062 struct_len = 144;
3063 break;
3064 case 20:
3065 if (strcmp(str2,"DN") != 0) {
3066 return False;
3068 struct_len = 6;
3069 break;
3070 case 50:
3071 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3072 return False;
3074 struct_len = 42;
3075 break;
3076 default:
3077 return False;
3080 *rdata_len = mdrcnt;
3081 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3082 if (!*rdata) {
3083 return False;
3086 p = *rdata;
3087 p2 = p + struct_len;
3088 if (uLevel != 20) {
3089 srvstr_push(NULL, 0, p,global_myname(),16,
3090 STR_ASCII|STR_UPPER|STR_TERMINATE);
3092 p += 16;
3093 if (uLevel > 0) {
3094 struct srv_info_struct *servers=NULL;
3095 int i,count;
3096 char *comment = NULL;
3097 TALLOC_CTX *ctx = talloc_tos();
3098 uint32 servertype= lp_default_server_announce();
3100 comment = talloc_strdup(ctx,lp_serverstring());
3101 if (!comment) {
3102 return false;
3105 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3106 for (i=0;i<count;i++) {
3107 if (strequal(servers[i].name,global_myname())) {
3108 servertype = servers[i].type;
3109 TALLOC_FREE(comment);
3110 comment = talloc_strdup(ctx,
3111 servers[i].comment);
3112 if (comment) {
3113 return false;
3119 SAFE_FREE(servers);
3121 SCVAL(p,0,lp_major_announce_version());
3122 SCVAL(p,1,lp_minor_announce_version());
3123 SIVAL(p,2,servertype);
3125 if (mdrcnt == struct_len) {
3126 SIVAL(p,6,0);
3127 } else {
3128 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3129 comment = talloc_sub_advanced(
3130 ctx,
3131 lp_servicename(SNUM(conn)),
3132 conn->server_info->unix_name,
3133 conn->connectpath,
3134 conn->server_info->utok.gid,
3135 conn->server_info->sanitized_username,
3136 pdb_get_domain(conn->server_info->sam_account),
3137 comment);
3138 if (comment) {
3139 return false;
3141 if (mdrcnt - struct_len <= 0) {
3142 return false;
3144 push_ascii(p2,
3145 comment,
3146 MIN(mdrcnt - struct_len,
3147 MAX_SERVER_STRING_LENGTH),
3148 STR_TERMINATE);
3149 p2 = skip_string(*rdata,*rdata_len,p2);
3150 if (!p2) {
3151 return False;
3156 if (uLevel > 1) {
3157 return False; /* not yet implemented */
3160 *rdata_len = PTR_DIFF(p2,*rdata);
3162 *rparam_len = 6;
3163 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3164 if (!*rparam) {
3165 return False;
3167 SSVAL(*rparam,0,NERR_Success);
3168 SSVAL(*rparam,2,0); /* converter word */
3169 SSVAL(*rparam,4,*rdata_len);
3171 return True;
3174 /****************************************************************************
3175 Get info about the server.
3176 ****************************************************************************/
3178 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3179 char *param, int tpscnt,
3180 char *data, int tdscnt,
3181 int mdrcnt,int mprcnt,
3182 char **rdata,char **rparam,
3183 int *rdata_len,int *rparam_len)
3185 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3186 char *str2 = skip_string(param,tpscnt,str1);
3187 char *p = skip_string(param,tpscnt,str2);
3188 char *p2;
3189 char *endp;
3190 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3192 if (!str1 || !str2 || !p) {
3193 return False;
3196 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3198 *rparam_len = 6;
3199 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3200 if (!*rparam) {
3201 return False;
3204 /* check it's a supported varient */
3205 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3206 return False;
3209 *rdata_len = mdrcnt + 1024;
3210 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3211 if (!*rdata) {
3212 return False;
3215 SSVAL(*rparam,0,NERR_Success);
3216 SSVAL(*rparam,2,0); /* converter word */
3218 p = *rdata;
3219 endp = *rdata + *rdata_len;
3221 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3222 if (!p2) {
3223 return False;
3226 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3227 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3228 strupper_m(p2);
3229 p2 = skip_string(*rdata,*rdata_len,p2);
3230 if (!p2) {
3231 return False;
3233 p += 4;
3235 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3236 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3237 p2 = skip_string(*rdata,*rdata_len,p2);
3238 if (!p2) {
3239 return False;
3241 p += 4;
3243 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3244 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3245 strupper_m(p2);
3246 p2 = skip_string(*rdata,*rdata_len,p2);
3247 if (!p2) {
3248 return False;
3250 p += 4;
3252 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3253 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3254 p += 2;
3256 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3257 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3258 p2 = skip_string(*rdata,*rdata_len,p2);
3259 if (!p2) {
3260 return False;
3262 p += 4;
3264 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3265 strlcpy(p2,"",PTR_DIFF(endp,p2));
3266 p2 = skip_string(*rdata,*rdata_len,p2);
3267 if (!p2) {
3268 return False;
3270 p += 4;
3272 *rdata_len = PTR_DIFF(p2,*rdata);
3274 SSVAL(*rparam,4,*rdata_len);
3276 return True;
3279 /****************************************************************************
3280 get info about a user
3282 struct user_info_11 {
3283 char usri11_name[21]; 0-20
3284 char usri11_pad; 21
3285 char *usri11_comment; 22-25
3286 char *usri11_usr_comment; 26-29
3287 unsigned short usri11_priv; 30-31
3288 unsigned long usri11_auth_flags; 32-35
3289 long usri11_password_age; 36-39
3290 char *usri11_homedir; 40-43
3291 char *usri11_parms; 44-47
3292 long usri11_last_logon; 48-51
3293 long usri11_last_logoff; 52-55
3294 unsigned short usri11_bad_pw_count; 56-57
3295 unsigned short usri11_num_logons; 58-59
3296 char *usri11_logon_server; 60-63
3297 unsigned short usri11_country_code; 64-65
3298 char *usri11_workstations; 66-69
3299 unsigned long usri11_max_storage; 70-73
3300 unsigned short usri11_units_per_week; 74-75
3301 unsigned char *usri11_logon_hours; 76-79
3302 unsigned short usri11_code_page; 80-81
3305 where:
3307 usri11_name specifies the user name for which information is retrieved
3309 usri11_pad aligns the next data structure element to a word boundary
3311 usri11_comment is a null terminated ASCII comment
3313 usri11_user_comment is a null terminated ASCII comment about the user
3315 usri11_priv specifies the level of the privilege assigned to the user.
3316 The possible values are:
3318 Name Value Description
3319 USER_PRIV_GUEST 0 Guest privilege
3320 USER_PRIV_USER 1 User privilege
3321 USER_PRV_ADMIN 2 Administrator privilege
3323 usri11_auth_flags specifies the account operator privileges. The
3324 possible values are:
3326 Name Value Description
3327 AF_OP_PRINT 0 Print operator
3330 Leach, Naik [Page 28]
3334 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3337 AF_OP_COMM 1 Communications operator
3338 AF_OP_SERVER 2 Server operator
3339 AF_OP_ACCOUNTS 3 Accounts operator
3342 usri11_password_age specifies how many seconds have elapsed since the
3343 password was last changed.
3345 usri11_home_dir points to a null terminated ASCII string that contains
3346 the path name of the user's home directory.
3348 usri11_parms points to a null terminated ASCII string that is set
3349 aside for use by applications.
3351 usri11_last_logon specifies the time when the user last logged on.
3352 This value is stored as the number of seconds elapsed since
3353 00:00:00, January 1, 1970.
3355 usri11_last_logoff specifies the time when the user last logged off.
3356 This value is stored as the number of seconds elapsed since
3357 00:00:00, January 1, 1970. A value of 0 means the last logoff
3358 time is unknown.
3360 usri11_bad_pw_count specifies the number of incorrect passwords
3361 entered since the last successful logon.
3363 usri11_log1_num_logons specifies the number of times this user has
3364 logged on. A value of -1 means the number of logons is unknown.
3366 usri11_logon_server points to a null terminated ASCII string that
3367 contains the name of the server to which logon requests are sent.
3368 A null string indicates logon requests should be sent to the
3369 domain controller.
3371 usri11_country_code specifies the country code for the user's language
3372 of choice.
3374 usri11_workstations points to a null terminated ASCII string that
3375 contains the names of workstations the user may log on from.
3376 There may be up to 8 workstations, with the names separated by
3377 commas. A null strings indicates there are no restrictions.
3379 usri11_max_storage specifies the maximum amount of disk space the user
3380 can occupy. A value of 0xffffffff indicates there are no
3381 restrictions.
3383 usri11_units_per_week specifies the equal number of time units into
3384 which a week is divided. This value must be equal to 168.
3386 usri11_logon_hours points to a 21 byte (168 bits) string that
3387 specifies the time during which the user can log on. Each bit
3388 represents one unique hour in a week. The first bit (bit 0, word
3389 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3393 Leach, Naik [Page 29]
3397 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3400 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3401 are no restrictions.
3403 usri11_code_page specifies the code page for the user's language of
3404 choice
3406 All of the pointers in this data structure need to be treated
3407 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3408 to be ignored. The converter word returned in the parameters section
3409 needs to be subtracted from the lower 16 bits to calculate an offset
3410 into the return buffer where this ASCII string resides.
3412 There is no auxiliary data in the response.
3414 ****************************************************************************/
3416 #define usri11_name 0
3417 #define usri11_pad 21
3418 #define usri11_comment 22
3419 #define usri11_usr_comment 26
3420 #define usri11_full_name 30
3421 #define usri11_priv 34
3422 #define usri11_auth_flags 36
3423 #define usri11_password_age 40
3424 #define usri11_homedir 44
3425 #define usri11_parms 48
3426 #define usri11_last_logon 52
3427 #define usri11_last_logoff 56
3428 #define usri11_bad_pw_count 60
3429 #define usri11_num_logons 62
3430 #define usri11_logon_server 64
3431 #define usri11_country_code 68
3432 #define usri11_workstations 70
3433 #define usri11_max_storage 74
3434 #define usri11_units_per_week 78
3435 #define usri11_logon_hours 80
3436 #define usri11_code_page 84
3437 #define usri11_end 86
3439 #define USER_PRIV_GUEST 0
3440 #define USER_PRIV_USER 1
3441 #define USER_PRIV_ADMIN 2
3443 #define AF_OP_PRINT 0
3444 #define AF_OP_COMM 1
3445 #define AF_OP_SERVER 2
3446 #define AF_OP_ACCOUNTS 3
3449 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3450 char *param, int tpscnt,
3451 char *data, int tdscnt,
3452 int mdrcnt,int mprcnt,
3453 char **rdata,char **rparam,
3454 int *rdata_len,int *rparam_len)
3456 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3457 char *str2 = skip_string(param,tpscnt,str1);
3458 char *UserName = skip_string(param,tpscnt,str2);
3459 char *p = skip_string(param,tpscnt,UserName);
3460 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3461 char *p2;
3462 char *endp;
3463 const char *level_string;
3465 /* get NIS home of a previously validated user - simeon */
3466 /* With share level security vuid will always be zero.
3467 Don't depend on vuser being non-null !!. JRA */
3468 user_struct *vuser = get_valid_user_struct(vuid);
3469 if(vuser != NULL) {
3470 DEBUG(3,(" Username of UID %d is %s\n",
3471 (int)vuser->server_info->utok.uid,
3472 vuser->server_info->unix_name));
3475 if (!str1 || !str2 || !UserName || !p) {
3476 return False;
3479 *rparam_len = 6;
3480 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3481 if (!*rparam) {
3482 return False;
3485 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3487 /* check it's a supported variant */
3488 if (strcmp(str1,"zWrLh") != 0) {
3489 return False;
3491 switch( uLevel ) {
3492 case 0: level_string = "B21"; break;
3493 case 1: level_string = "B21BB16DWzzWz"; break;
3494 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3495 case 10: level_string = "B21Bzzz"; break;
3496 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3497 default: return False;
3500 if (strcmp(level_string,str2) != 0) {
3501 return False;
3504 *rdata_len = mdrcnt + 1024;
3505 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3506 if (!*rdata) {
3507 return False;
3510 SSVAL(*rparam,0,NERR_Success);
3511 SSVAL(*rparam,2,0); /* converter word */
3513 p = *rdata;
3514 endp = *rdata + *rdata_len;
3515 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3516 if (!p2) {
3517 return False;
3520 memset(p,0,21);
3521 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3523 if (uLevel > 0) {
3524 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3525 *p2 = 0;
3528 if (uLevel >= 10) {
3529 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3530 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3531 p2 = skip_string(*rdata,*rdata_len,p2);
3532 if (!p2) {
3533 return False;
3536 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3537 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3538 p2 = skip_string(*rdata,*rdata_len,p2);
3539 if (!p2) {
3540 return False;
3543 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3544 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3545 strlcpy(p2,((vuser != NULL)
3546 ? pdb_get_fullname(vuser->server_info->sam_account)
3547 : UserName),PTR_DIFF(endp,p2));
3548 p2 = skip_string(*rdata,*rdata_len,p2);
3549 if (!p2) {
3550 return False;
3554 if (uLevel == 11) {
3555 const char *homedir = "";
3556 if (vuser != NULL) {
3557 homedir = pdb_get_homedir(
3558 vuser->server_info->sam_account);
3560 /* modelled after NTAS 3.51 reply */
3561 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3562 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3563 SIVALS(p,usri11_password_age,-1); /* password age */
3564 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3565 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3566 p2 = skip_string(*rdata,*rdata_len,p2);
3567 if (!p2) {
3568 return False;
3570 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3571 strlcpy(p2,"",PTR_DIFF(endp,p2));
3572 p2 = skip_string(*rdata,*rdata_len,p2);
3573 if (!p2) {
3574 return False;
3576 SIVAL(p,usri11_last_logon,0); /* last logon */
3577 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3578 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3579 SSVALS(p,usri11_num_logons,-1); /* num logons */
3580 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3581 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3582 p2 = skip_string(*rdata,*rdata_len,p2);
3583 if (!p2) {
3584 return False;
3586 SSVAL(p,usri11_country_code,0); /* country code */
3588 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3589 strlcpy(p2,"",PTR_DIFF(endp,p2));
3590 p2 = skip_string(*rdata,*rdata_len,p2);
3591 if (!p2) {
3592 return False;
3595 SIVALS(p,usri11_max_storage,-1); /* max storage */
3596 SSVAL(p,usri11_units_per_week,168); /* units per week */
3597 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3599 /* a simple way to get logon hours at all times. */
3600 memset(p2,0xff,21);
3601 SCVAL(p2,21,0); /* fix zero termination */
3602 p2 = skip_string(*rdata,*rdata_len,p2);
3603 if (!p2) {
3604 return False;
3607 SSVAL(p,usri11_code_page,0); /* code page */
3610 if (uLevel == 1 || uLevel == 2) {
3611 memset(p+22,' ',16); /* password */
3612 SIVALS(p,38,-1); /* password age */
3613 SSVAL(p,42,
3614 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3615 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3616 strlcpy(p2, vuser ? pdb_get_homedir(
3617 vuser->server_info->sam_account) : "",
3618 PTR_DIFF(endp,p2));
3619 p2 = skip_string(*rdata,*rdata_len,p2);
3620 if (!p2) {
3621 return False;
3623 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3624 *p2++ = 0;
3625 SSVAL(p,52,0); /* flags */
3626 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3627 strlcpy(p2, vuser ? pdb_get_logon_script(
3628 vuser->server_info->sam_account) : "",
3629 PTR_DIFF(endp,p2));
3630 p2 = skip_string(*rdata,*rdata_len,p2);
3631 if (!p2) {
3632 return False;
3634 if (uLevel == 2) {
3635 SIVAL(p,60,0); /* auth_flags */
3636 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3637 strlcpy(p2,((vuser != NULL)
3638 ? pdb_get_fullname(vuser->server_info->sam_account)
3639 : UserName),PTR_DIFF(endp,p2));
3640 p2 = skip_string(*rdata,*rdata_len,p2);
3641 if (!p2) {
3642 return False;
3644 SIVAL(p,68,0); /* urs_comment */
3645 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3646 strlcpy(p2,"",PTR_DIFF(endp,p2));
3647 p2 = skip_string(*rdata,*rdata_len,p2);
3648 if (!p2) {
3649 return False;
3651 SIVAL(p,76,0); /* workstations */
3652 SIVAL(p,80,0); /* last_logon */
3653 SIVAL(p,84,0); /* last_logoff */
3654 SIVALS(p,88,-1); /* acct_expires */
3655 SIVALS(p,92,-1); /* max_storage */
3656 SSVAL(p,96,168); /* units_per_week */
3657 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3658 memset(p2,-1,21);
3659 p2 += 21;
3660 SSVALS(p,102,-1); /* bad_pw_count */
3661 SSVALS(p,104,-1); /* num_logons */
3662 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3664 TALLOC_CTX *ctx = talloc_tos();
3665 int space_rem = *rdata_len - (p2 - *rdata);
3666 char *tmp;
3668 if (space_rem <= 0) {
3669 return false;
3671 tmp = talloc_strdup(ctx, "\\\\%L");
3672 if (!tmp) {
3673 return false;
3675 tmp = talloc_sub_basic(ctx,
3678 tmp);
3679 if (!tmp) {
3680 return false;
3683 push_ascii(p2,
3684 tmp,
3685 space_rem,
3686 STR_TERMINATE);
3688 p2 = skip_string(*rdata,*rdata_len,p2);
3689 if (!p2) {
3690 return False;
3692 SSVAL(p,110,49); /* country_code */
3693 SSVAL(p,112,860); /* code page */
3697 *rdata_len = PTR_DIFF(p2,*rdata);
3699 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3701 return(True);
3704 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3705 char *param, int tpscnt,
3706 char *data, int tdscnt,
3707 int mdrcnt,int mprcnt,
3708 char **rdata,char **rparam,
3709 int *rdata_len,int *rparam_len)
3711 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3712 char *str2 = skip_string(param,tpscnt,str1);
3713 char *p = skip_string(param,tpscnt,str2);
3714 int uLevel;
3715 struct pack_desc desc;
3716 char* name;
3717 /* With share level security vuid will always be zero.
3718 Don't depend on vuser being non-null !!. JRA */
3719 user_struct *vuser = get_valid_user_struct(vuid);
3721 if (!str1 || !str2 || !p) {
3722 return False;
3725 if(vuser != NULL) {
3726 DEBUG(3,(" Username of UID %d is %s\n",
3727 (int)vuser->server_info->utok.uid,
3728 vuser->server_info->unix_name));
3731 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3732 name = get_safe_str_ptr(param,tpscnt,p,2);
3733 if (!name) {
3734 return False;
3737 memset((char *)&desc,'\0',sizeof(desc));
3739 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3741 /* check it's a supported varient */
3742 if (strcmp(str1,"OOWb54WrLh") != 0) {
3743 return False;
3745 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3746 return False;
3748 if (mdrcnt > 0) {
3749 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3750 if (!*rdata) {
3751 return False;
3755 desc.base = *rdata;
3756 desc.buflen = mdrcnt;
3757 desc.subformat = NULL;
3758 desc.format = str2;
3760 if (init_package(&desc,1,0)) {
3761 PACKI(&desc,"W",0); /* code */
3762 PACKS(&desc,"B21",name); /* eff. name */
3763 PACKS(&desc,"B",""); /* pad */
3764 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3765 PACKI(&desc,"D",0); /* auth flags XXX */
3766 PACKI(&desc,"W",0); /* num logons */
3767 PACKI(&desc,"W",0); /* bad pw count */
3768 PACKI(&desc,"D",0); /* last logon */
3769 PACKI(&desc,"D",-1); /* last logoff */
3770 PACKI(&desc,"D",-1); /* logoff time */
3771 PACKI(&desc,"D",-1); /* kickoff time */
3772 PACKI(&desc,"D",0); /* password age */
3773 PACKI(&desc,"D",0); /* password can change */
3774 PACKI(&desc,"D",-1); /* password must change */
3777 fstring mypath;
3778 fstrcpy(mypath,"\\\\");
3779 fstrcat(mypath,get_local_machine_name());
3780 strupper_m(mypath);
3781 PACKS(&desc,"z",mypath); /* computer */
3784 PACKS(&desc,"z",lp_workgroup());/* domain */
3785 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3786 vuser->server_info->sam_account) : ""); /* script path */
3787 PACKI(&desc,"D",0x00000000); /* reserved */
3790 *rdata_len = desc.usedlen;
3791 *rparam_len = 6;
3792 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3793 if (!*rparam) {
3794 return False;
3796 SSVALS(*rparam,0,desc.errcode);
3797 SSVAL(*rparam,2,0);
3798 SSVAL(*rparam,4,desc.neededlen);
3800 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3802 return True;
3805 /****************************************************************************
3806 api_WAccessGetUserPerms
3807 ****************************************************************************/
3809 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3810 char *param, int tpscnt,
3811 char *data, int tdscnt,
3812 int mdrcnt,int mprcnt,
3813 char **rdata,char **rparam,
3814 int *rdata_len,int *rparam_len)
3816 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3817 char *str2 = skip_string(param,tpscnt,str1);
3818 char *user = skip_string(param,tpscnt,str2);
3819 char *resource = skip_string(param,tpscnt,user);
3821 if (!str1 || !str2 || !user || !resource) {
3822 return False;
3825 if (skip_string(param,tpscnt,resource) == NULL) {
3826 return False;
3828 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3830 /* check it's a supported varient */
3831 if (strcmp(str1,"zzh") != 0) {
3832 return False;
3834 if (strcmp(str2,"") != 0) {
3835 return False;
3838 *rparam_len = 6;
3839 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3840 if (!*rparam) {
3841 return False;
3843 SSVALS(*rparam,0,0); /* errorcode */
3844 SSVAL(*rparam,2,0); /* converter word */
3845 SSVAL(*rparam,4,0x7f); /* permission flags */
3847 return True;
3850 /****************************************************************************
3851 api_WPrintJobEnumerate
3852 ****************************************************************************/
3854 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3855 char *param, int tpscnt,
3856 char *data, int tdscnt,
3857 int mdrcnt,int mprcnt,
3858 char **rdata,char **rparam,
3859 int *rdata_len,int *rparam_len)
3861 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3862 char *str2 = skip_string(param,tpscnt,str1);
3863 char *p = skip_string(param,tpscnt,str2);
3864 int uLevel;
3865 int count;
3866 int i;
3867 int snum;
3868 fstring sharename;
3869 uint32 jobid;
3870 struct pack_desc desc;
3871 print_queue_struct *queue=NULL;
3872 print_status_struct status;
3873 char *tmpdata=NULL;
3875 if (!str1 || !str2 || !p) {
3876 return False;
3879 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3881 memset((char *)&desc,'\0',sizeof(desc));
3882 memset((char *)&status,'\0',sizeof(status));
3884 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3886 /* check it's a supported varient */
3887 if (strcmp(str1,"WWrLh") != 0) {
3888 return False;
3890 if (!check_printjob_info(&desc,uLevel,str2)) {
3891 return False;
3894 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3895 return False;
3898 snum = lp_servicenumber( sharename);
3899 if (snum < 0 || !VALID_SNUM(snum)) {
3900 return(False);
3903 count = print_queue_status(snum,&queue,&status);
3904 for (i = 0; i < count; i++) {
3905 if (queue[i].job == jobid) {
3906 break;
3910 if (mdrcnt > 0) {
3911 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3912 if (!*rdata) {
3913 return False;
3915 desc.base = *rdata;
3916 desc.buflen = mdrcnt;
3917 } else {
3919 * Don't return data but need to get correct length
3920 * init_package will return wrong size if buflen=0
3922 desc.buflen = getlen(desc.format);
3923 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3926 if (init_package(&desc,1,0)) {
3927 if (i < count) {
3928 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3929 *rdata_len = desc.usedlen;
3930 } else {
3931 desc.errcode = NERR_JobNotFound;
3932 *rdata_len = 0;
3936 *rparam_len = 6;
3937 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3938 if (!*rparam) {
3939 return False;
3941 SSVALS(*rparam,0,desc.errcode);
3942 SSVAL(*rparam,2,0);
3943 SSVAL(*rparam,4,desc.neededlen);
3945 SAFE_FREE(queue);
3946 SAFE_FREE(tmpdata);
3948 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3950 return True;
3953 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3954 char *param, int tpscnt,
3955 char *data, int tdscnt,
3956 int mdrcnt,int mprcnt,
3957 char **rdata,char **rparam,
3958 int *rdata_len,int *rparam_len)
3960 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3961 char *str2 = skip_string(param,tpscnt,str1);
3962 char *p = skip_string(param,tpscnt,str2);
3963 char *name = p;
3964 int uLevel;
3965 int count;
3966 int i, succnt=0;
3967 int snum;
3968 struct pack_desc desc;
3969 print_queue_struct *queue=NULL;
3970 print_status_struct status;
3972 if (!str1 || !str2 || !p) {
3973 return False;
3976 memset((char *)&desc,'\0',sizeof(desc));
3977 memset((char *)&status,'\0',sizeof(status));
3979 p = skip_string(param,tpscnt,p);
3980 if (!p) {
3981 return False;
3983 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3985 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3987 /* check it's a supported variant */
3988 if (strcmp(str1,"zWrLeh") != 0) {
3989 return False;
3992 if (uLevel > 2) {
3993 return False; /* defined only for uLevel 0,1,2 */
3996 if (!check_printjob_info(&desc,uLevel,str2)) {
3997 return False;
4000 snum = find_service(name);
4001 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4002 return False;
4005 count = print_queue_status(snum,&queue,&status);
4006 if (mdrcnt > 0) {
4007 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4008 if (!*rdata) {
4009 return False;
4012 desc.base = *rdata;
4013 desc.buflen = mdrcnt;
4015 if (init_package(&desc,count,0)) {
4016 succnt = 0;
4017 for (i = 0; i < count; i++) {
4018 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4019 if (desc.errcode == NERR_Success) {
4020 succnt = i+1;
4025 *rdata_len = desc.usedlen;
4027 *rparam_len = 8;
4028 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4029 if (!*rparam) {
4030 return False;
4032 SSVALS(*rparam,0,desc.errcode);
4033 SSVAL(*rparam,2,0);
4034 SSVAL(*rparam,4,succnt);
4035 SSVAL(*rparam,6,count);
4037 SAFE_FREE(queue);
4039 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4041 return True;
4044 static int check_printdest_info(struct pack_desc* desc,
4045 int uLevel, char* id)
4047 desc->subformat = NULL;
4048 switch( uLevel ) {
4049 case 0:
4050 desc->format = "B9";
4051 break;
4052 case 1:
4053 desc->format = "B9B21WWzW";
4054 break;
4055 case 2:
4056 desc->format = "z";
4057 break;
4058 case 3:
4059 desc->format = "zzzWWzzzWW";
4060 break;
4061 default:
4062 DEBUG(0,("check_printdest_info: invalid level %d\n",
4063 uLevel));
4064 return False;
4066 if (id == NULL || strcmp(desc->format,id) != 0) {
4067 DEBUG(0,("check_printdest_info: invalid string %s\n",
4068 id ? id : "<NULL>" ));
4069 return False;
4071 return True;
4074 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4075 struct pack_desc* desc)
4077 char buf[100];
4079 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4080 buf[sizeof(buf)-1] = 0;
4081 strupper_m(buf);
4083 if (uLevel <= 1) {
4084 PACKS(desc,"B9",buf); /* szName */
4085 if (uLevel == 1) {
4086 PACKS(desc,"B21",""); /* szUserName */
4087 PACKI(desc,"W",0); /* uJobId */
4088 PACKI(desc,"W",0); /* fsStatus */
4089 PACKS(desc,"z",""); /* pszStatus */
4090 PACKI(desc,"W",0); /* time */
4094 if (uLevel == 2 || uLevel == 3) {
4095 PACKS(desc,"z",buf); /* pszPrinterName */
4096 if (uLevel == 3) {
4097 PACKS(desc,"z",""); /* pszUserName */
4098 PACKS(desc,"z",""); /* pszLogAddr */
4099 PACKI(desc,"W",0); /* uJobId */
4100 PACKI(desc,"W",0); /* fsStatus */
4101 PACKS(desc,"z",""); /* pszStatus */
4102 PACKS(desc,"z",""); /* pszComment */
4103 PACKS(desc,"z","NULL"); /* pszDrivers */
4104 PACKI(desc,"W",0); /* time */
4105 PACKI(desc,"W",0); /* pad1 */
4110 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4111 char *param, int tpscnt,
4112 char *data, int tdscnt,
4113 int mdrcnt,int mprcnt,
4114 char **rdata,char **rparam,
4115 int *rdata_len,int *rparam_len)
4117 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4118 char *str2 = skip_string(param,tpscnt,str1);
4119 char *p = skip_string(param,tpscnt,str2);
4120 char* PrinterName = p;
4121 int uLevel;
4122 struct pack_desc desc;
4123 int snum;
4124 char *tmpdata=NULL;
4126 if (!str1 || !str2 || !p) {
4127 return False;
4130 memset((char *)&desc,'\0',sizeof(desc));
4132 p = skip_string(param,tpscnt,p);
4133 if (!p) {
4134 return False;
4136 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4138 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4140 /* check it's a supported varient */
4141 if (strcmp(str1,"zWrLh") != 0) {
4142 return False;
4144 if (!check_printdest_info(&desc,uLevel,str2)) {
4145 return False;
4148 snum = find_service(PrinterName);
4149 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4150 *rdata_len = 0;
4151 desc.errcode = NERR_DestNotFound;
4152 desc.neededlen = 0;
4153 } else {
4154 if (mdrcnt > 0) {
4155 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4156 if (!*rdata) {
4157 return False;
4159 desc.base = *rdata;
4160 desc.buflen = mdrcnt;
4161 } else {
4163 * Don't return data but need to get correct length
4164 * init_package will return wrong size if buflen=0
4166 desc.buflen = getlen(desc.format);
4167 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4169 if (init_package(&desc,1,0)) {
4170 fill_printdest_info(conn,snum,uLevel,&desc);
4172 *rdata_len = desc.usedlen;
4175 *rparam_len = 6;
4176 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4177 if (!*rparam) {
4178 return False;
4180 SSVALS(*rparam,0,desc.errcode);
4181 SSVAL(*rparam,2,0);
4182 SSVAL(*rparam,4,desc.neededlen);
4184 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4185 SAFE_FREE(tmpdata);
4187 return True;
4190 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4191 char *param, int tpscnt,
4192 char *data, int tdscnt,
4193 int mdrcnt,int mprcnt,
4194 char **rdata,char **rparam,
4195 int *rdata_len,int *rparam_len)
4197 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4198 char *str2 = skip_string(param,tpscnt,str1);
4199 char *p = skip_string(param,tpscnt,str2);
4200 int uLevel;
4201 int queuecnt;
4202 int i, n, succnt=0;
4203 struct pack_desc desc;
4204 int services = lp_numservices();
4206 if (!str1 || !str2 || !p) {
4207 return False;
4210 memset((char *)&desc,'\0',sizeof(desc));
4212 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4214 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4216 /* check it's a supported varient */
4217 if (strcmp(str1,"WrLeh") != 0) {
4218 return False;
4220 if (!check_printdest_info(&desc,uLevel,str2)) {
4221 return False;
4224 queuecnt = 0;
4225 for (i = 0; i < services; i++) {
4226 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4227 queuecnt++;
4231 if (mdrcnt > 0) {
4232 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4233 if (!*rdata) {
4234 return False;
4238 desc.base = *rdata;
4239 desc.buflen = mdrcnt;
4240 if (init_package(&desc,queuecnt,0)) {
4241 succnt = 0;
4242 n = 0;
4243 for (i = 0; i < services; i++) {
4244 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4245 fill_printdest_info(conn,i,uLevel,&desc);
4246 n++;
4247 if (desc.errcode == NERR_Success) {
4248 succnt = n;
4254 *rdata_len = desc.usedlen;
4256 *rparam_len = 8;
4257 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4258 if (!*rparam) {
4259 return False;
4261 SSVALS(*rparam,0,desc.errcode);
4262 SSVAL(*rparam,2,0);
4263 SSVAL(*rparam,4,succnt);
4264 SSVAL(*rparam,6,queuecnt);
4266 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4268 return True;
4271 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4272 char *param, int tpscnt,
4273 char *data, int tdscnt,
4274 int mdrcnt,int mprcnt,
4275 char **rdata,char **rparam,
4276 int *rdata_len,int *rparam_len)
4278 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4279 char *str2 = skip_string(param,tpscnt,str1);
4280 char *p = skip_string(param,tpscnt,str2);
4281 int uLevel;
4282 int succnt;
4283 struct pack_desc desc;
4285 if (!str1 || !str2 || !p) {
4286 return False;
4289 memset((char *)&desc,'\0',sizeof(desc));
4291 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4293 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4295 /* check it's a supported varient */
4296 if (strcmp(str1,"WrLeh") != 0) {
4297 return False;
4299 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4300 return False;
4303 if (mdrcnt > 0) {
4304 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4305 if (!*rdata) {
4306 return False;
4309 desc.base = *rdata;
4310 desc.buflen = mdrcnt;
4311 if (init_package(&desc,1,0)) {
4312 PACKS(&desc,"B41","NULL");
4315 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4317 *rdata_len = desc.usedlen;
4319 *rparam_len = 8;
4320 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4321 if (!*rparam) {
4322 return False;
4324 SSVALS(*rparam,0,desc.errcode);
4325 SSVAL(*rparam,2,0);
4326 SSVAL(*rparam,4,succnt);
4327 SSVAL(*rparam,6,1);
4329 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4331 return True;
4334 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4335 char *param, int tpscnt,
4336 char *data, int tdscnt,
4337 int mdrcnt,int mprcnt,
4338 char **rdata,char **rparam,
4339 int *rdata_len,int *rparam_len)
4341 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4342 char *str2 = skip_string(param,tpscnt,str1);
4343 char *p = skip_string(param,tpscnt,str2);
4344 int uLevel;
4345 int succnt;
4346 struct pack_desc desc;
4348 if (!str1 || !str2 || !p) {
4349 return False;
4351 memset((char *)&desc,'\0',sizeof(desc));
4353 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4355 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4357 /* check it's a supported varient */
4358 if (strcmp(str1,"WrLeh") != 0) {
4359 return False;
4361 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4362 return False;
4365 if (mdrcnt > 0) {
4366 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4367 if (!*rdata) {
4368 return False;
4371 desc.base = *rdata;
4372 desc.buflen = mdrcnt;
4373 desc.format = str2;
4374 if (init_package(&desc,1,0)) {
4375 PACKS(&desc,"B13","lpd");
4378 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4380 *rdata_len = desc.usedlen;
4382 *rparam_len = 8;
4383 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4384 if (!*rparam) {
4385 return False;
4387 SSVALS(*rparam,0,desc.errcode);
4388 SSVAL(*rparam,2,0);
4389 SSVAL(*rparam,4,succnt);
4390 SSVAL(*rparam,6,1);
4392 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4394 return True;
4397 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4398 char *param, int tpscnt,
4399 char *data, int tdscnt,
4400 int mdrcnt,int mprcnt,
4401 char **rdata,char **rparam,
4402 int *rdata_len,int *rparam_len)
4404 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4405 char *str2 = skip_string(param,tpscnt,str1);
4406 char *p = skip_string(param,tpscnt,str2);
4407 int uLevel;
4408 int succnt;
4409 struct pack_desc desc;
4411 if (!str1 || !str2 || !p) {
4412 return False;
4415 memset((char *)&desc,'\0',sizeof(desc));
4417 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4419 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4421 /* check it's a supported varient */
4422 if (strcmp(str1,"WrLeh") != 0) {
4423 return False;
4425 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4426 return False;
4429 if (mdrcnt > 0) {
4430 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4431 if (!*rdata) {
4432 return False;
4435 memset((char *)&desc,'\0',sizeof(desc));
4436 desc.base = *rdata;
4437 desc.buflen = mdrcnt;
4438 desc.format = str2;
4439 if (init_package(&desc,1,0)) {
4440 PACKS(&desc,"B13","lp0");
4443 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4445 *rdata_len = desc.usedlen;
4447 *rparam_len = 8;
4448 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4449 if (!*rparam) {
4450 return False;
4452 SSVALS(*rparam,0,desc.errcode);
4453 SSVAL(*rparam,2,0);
4454 SSVAL(*rparam,4,succnt);
4455 SSVAL(*rparam,6,1);
4457 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4459 return True;
4462 /****************************************************************************
4463 List open sessions
4464 ****************************************************************************/
4466 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4467 char *param, int tpscnt,
4468 char *data, int tdscnt,
4469 int mdrcnt,int mprcnt,
4470 char **rdata,char **rparam,
4471 int *rdata_len,int *rparam_len)
4474 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4475 char *str2 = skip_string(param,tpscnt,str1);
4476 char *p = skip_string(param,tpscnt,str2);
4477 int uLevel;
4478 struct pack_desc desc;
4479 struct sessionid *session_list;
4480 int i, num_sessions;
4482 if (!str1 || !str2 || !p) {
4483 return False;
4486 memset((char *)&desc,'\0',sizeof(desc));
4488 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4490 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4491 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4492 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4494 /* check it's a supported varient */
4495 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4496 return False;
4498 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4499 return False;
4502 num_sessions = list_sessions(talloc_tos(), &session_list);
4504 if (mdrcnt > 0) {
4505 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4506 if (!*rdata) {
4507 return False;
4510 memset((char *)&desc,'\0',sizeof(desc));
4511 desc.base = *rdata;
4512 desc.buflen = mdrcnt;
4513 desc.format = str2;
4514 if (!init_package(&desc,num_sessions,0)) {
4515 return False;
4518 for(i=0; i<num_sessions; i++) {
4519 PACKS(&desc, "z", session_list[i].remote_machine);
4520 PACKS(&desc, "z", session_list[i].username);
4521 PACKI(&desc, "W", 1); /* num conns */
4522 PACKI(&desc, "W", 0); /* num opens */
4523 PACKI(&desc, "W", 1); /* num users */
4524 PACKI(&desc, "D", 0); /* session time */
4525 PACKI(&desc, "D", 0); /* idle time */
4526 PACKI(&desc, "D", 0); /* flags */
4527 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4530 *rdata_len = desc.usedlen;
4532 *rparam_len = 8;
4533 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4534 if (!*rparam) {
4535 return False;
4537 SSVALS(*rparam,0,desc.errcode);
4538 SSVAL(*rparam,2,0); /* converter */
4539 SSVAL(*rparam,4,num_sessions); /* count */
4541 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4543 return True;
4547 /****************************************************************************
4548 The buffer was too small.
4549 ****************************************************************************/
4551 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4552 int mdrcnt, int mprcnt,
4553 char **rdata, char **rparam,
4554 int *rdata_len, int *rparam_len)
4556 *rparam_len = MIN(*rparam_len,mprcnt);
4557 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4558 if (!*rparam) {
4559 return False;
4562 *rdata_len = 0;
4564 SSVAL(*rparam,0,NERR_BufTooSmall);
4566 DEBUG(3,("Supplied buffer too small in API command\n"));
4568 return True;
4571 /****************************************************************************
4572 The request is not supported.
4573 ****************************************************************************/
4575 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4576 char *param, int tpscnt,
4577 char *data, int tdscnt,
4578 int mdrcnt, int mprcnt,
4579 char **rdata, char **rparam,
4580 int *rdata_len, int *rparam_len)
4582 *rparam_len = 4;
4583 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4584 if (!*rparam) {
4585 return False;
4588 *rdata_len = 0;
4590 SSVAL(*rparam,0,NERR_notsupported);
4591 SSVAL(*rparam,2,0); /* converter word */
4593 DEBUG(3,("Unsupported API command\n"));
4595 return True;
4598 static const struct {
4599 const char *name;
4600 int id;
4601 bool (*fn)(connection_struct *, uint16,
4602 char *, int,
4603 char *, int,
4604 int,int,char **,char **,int *,int *);
4605 bool auth_user; /* Deny anonymous access? */
4606 } api_commands[] = {
4607 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4608 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4609 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4610 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4611 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4612 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4613 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4614 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4615 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4616 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4617 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4618 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4619 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4620 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4621 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4622 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4623 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4624 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4625 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4626 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4627 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4628 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4629 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4630 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4631 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4632 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4633 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4634 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4635 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4636 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4637 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4638 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4639 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4640 {NULL, -1, api_Unsupported}
4641 /* The following RAP calls are not implemented by Samba:
4643 RAP_WFileEnum2 - anon not OK
4648 /****************************************************************************
4649 Handle remote api calls.
4650 ****************************************************************************/
4652 void api_reply(connection_struct *conn, uint16 vuid,
4653 struct smb_request *req,
4654 char *data, char *params,
4655 int tdscnt, int tpscnt,
4656 int mdrcnt, int mprcnt)
4658 int api_command;
4659 char *rdata = NULL;
4660 char *rparam = NULL;
4661 const char *name1 = NULL;
4662 const char *name2 = NULL;
4663 int rdata_len = 0;
4664 int rparam_len = 0;
4665 bool reply=False;
4666 int i;
4668 if (!params) {
4669 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4670 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4671 return;
4674 if (tpscnt < 2) {
4675 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4676 return;
4678 api_command = SVAL(params,0);
4679 /* Is there a string at position params+2 ? */
4680 if (skip_string(params,tpscnt,params+2)) {
4681 name1 = params + 2;
4682 } else {
4683 name1 = "";
4685 name2 = skip_string(params,tpscnt,params+2);
4686 if (!name2) {
4687 name2 = "";
4690 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4691 api_command,
4692 name1,
4693 name2,
4694 tdscnt,tpscnt,mdrcnt,mprcnt));
4696 for (i=0;api_commands[i].name;i++) {
4697 if (api_commands[i].id == api_command && api_commands[i].fn) {
4698 DEBUG(3,("Doing %s\n",api_commands[i].name));
4699 break;
4703 /* Check whether this api call can be done anonymously */
4705 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4706 user_struct *user = get_valid_user_struct(vuid);
4708 if (!user || user->server_info->guest) {
4709 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4710 return;
4714 rdata = (char *)SMB_MALLOC(1024);
4715 if (rdata) {
4716 memset(rdata,'\0',1024);
4719 rparam = (char *)SMB_MALLOC(1024);
4720 if (rparam) {
4721 memset(rparam,'\0',1024);
4724 if(!rdata || !rparam) {
4725 DEBUG(0,("api_reply: malloc fail !\n"));
4726 SAFE_FREE(rdata);
4727 SAFE_FREE(rparam);
4728 reply_nterror(req, NT_STATUS_NO_MEMORY);
4729 return;
4732 reply = api_commands[i].fn(conn,
4733 vuid,
4734 params,tpscnt, /* params + length */
4735 data,tdscnt, /* data + length */
4736 mdrcnt,mprcnt,
4737 &rdata,&rparam,&rdata_len,&rparam_len);
4740 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4741 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4742 &rdata,&rparam,&rdata_len,&rparam_len);
4745 /* if we get False back then it's actually unsupported */
4746 if (!reply) {
4747 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4748 &rdata,&rparam,&rdata_len,&rparam_len);
4751 /* If api_Unsupported returns false we can't return anything. */
4752 if (reply) {
4753 send_trans_reply(conn, req, rparam, rparam_len,
4754 rdata, rdata_len, False);
4757 SAFE_FREE(rdata);
4758 SAFE_FREE(rparam);
4759 return;