s3: Rename new parameter "ldap ref follow" to "ldap follow referral".
[Samba/gebeck_regimport.git] / source3 / smbd / lanman.c
blob6fc72c27ea62e27a6967d296971967c8abac5b9a
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
29 #include "smbd/globals.h"
31 #ifdef CHECK_TYPES
32 #undef CHECK_TYPES
33 #endif
34 #define CHECK_TYPES 0
36 #define NERR_Success 0
37 #define NERR_badpass 86
38 #define NERR_notsupported 50
40 #define NERR_BASE (2100)
41 #define NERR_BufTooSmall (NERR_BASE+23)
42 #define NERR_JobNotFound (NERR_BASE+51)
43 #define NERR_DestNotFound (NERR_BASE+52)
45 #define ACCESS_READ 0x01
46 #define ACCESS_WRITE 0x02
47 #define ACCESS_CREATE 0x04
49 #define SHPWLEN 8 /* share password length */
51 /* Limit size of ipc replies */
53 static char *smb_realloc_limit(void *ptr, size_t size)
55 char *val;
57 size = MAX((size),4*1024);
58 val = (char *)SMB_REALLOC(ptr,size);
59 if (val) {
60 memset(val,'\0',size);
62 return val;
65 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
66 char *param, int tpscnt,
67 char *data, int tdscnt,
68 int mdrcnt, int mprcnt,
69 char **rdata, char **rparam,
70 int *rdata_len, int *rparam_len);
72 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
73 int mdrcnt, int mprcnt,
74 char **rdata, char **rparam,
75 int *rdata_len, int *rparam_len);
78 static int CopyExpanded(connection_struct *conn,
79 int snum, char **dst, char *src, int *p_space_remaining)
81 TALLOC_CTX *ctx = talloc_tos();
82 char *buf = NULL;
83 int l;
85 if (!src || !dst || !p_space_remaining || !(*dst) ||
86 *p_space_remaining <= 0) {
87 return 0;
90 buf = talloc_strdup(ctx, src);
91 if (!buf) {
92 *p_space_remaining = 0;
93 return 0;
95 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
96 if (!buf) {
97 *p_space_remaining = 0;
98 return 0;
100 buf = talloc_sub_advanced(ctx,
101 lp_servicename(SNUM(conn)),
102 conn->server_info->unix_name,
103 conn->connectpath,
104 conn->server_info->utok.gid,
105 conn->server_info->sanitized_username,
106 pdb_get_domain(conn->server_info->sam_account),
107 buf);
108 if (!buf) {
109 *p_space_remaining = 0;
110 return 0;
112 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
113 if (l == -1) {
114 return 0;
116 (*dst) += l;
117 (*p_space_remaining) -= l;
118 return l;
121 static int CopyAndAdvance(char **dst, char *src, int *n)
123 int l;
124 if (!src || !dst || !n || !(*dst)) {
125 return 0;
127 l = push_ascii(*dst,src,*n, STR_TERMINATE);
128 if (l == -1) {
129 return 0;
131 (*dst) += l;
132 (*n) -= l;
133 return l;
136 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
138 TALLOC_CTX *ctx = talloc_tos();
139 char *buf = NULL;
140 if (!s) {
141 return 0;
143 buf = talloc_strdup(ctx,s);
144 if (!buf) {
145 return 0;
147 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
148 if (!buf) {
149 return 0;
151 buf = talloc_sub_advanced(ctx,
152 lp_servicename(SNUM(conn)),
153 conn->server_info->unix_name,
154 conn->connectpath,
155 conn->server_info->utok.gid,
156 conn->server_info->sanitized_username,
157 pdb_get_domain(conn->server_info->sam_account),
158 buf);
159 if (!buf) {
160 return 0;
162 return strlen(buf) + 1;
165 static char *Expand(connection_struct *conn, int snum, char *s)
167 TALLOC_CTX *ctx = talloc_tos();
168 char *buf = NULL;
170 if (!s) {
171 return NULL;
173 buf = talloc_strdup(ctx,s);
174 if (!buf) {
175 return 0;
177 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
178 if (!buf) {
179 return 0;
181 return talloc_sub_advanced(ctx,
182 lp_servicename(SNUM(conn)),
183 conn->server_info->unix_name,
184 conn->connectpath,
185 conn->server_info->utok.gid,
186 conn->server_info->sanitized_username,
187 pdb_get_domain(conn->server_info->sam_account),
188 buf);
191 /*******************************************************************
192 Check a API string for validity when we only need to check the prefix.
193 ******************************************************************/
195 static bool prefix_ok(const char *str, const char *prefix)
197 return(strncmp(str,prefix,strlen(prefix)) == 0);
200 struct pack_desc {
201 const char *format; /* formatstring for structure */
202 const char *subformat; /* subformat for structure */
203 char *base; /* baseaddress of buffer */
204 int buflen; /* remaining size for fixed part; on init: length of base */
205 int subcount; /* count of substructures */
206 char *structbuf; /* pointer into buffer for remaining fixed part */
207 int stringlen; /* remaining size for variable part */
208 char *stringbuf; /* pointer into buffer for remaining variable part */
209 int neededlen; /* total needed size */
210 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
211 const char *curpos; /* current position; pointer into format or subformat */
212 int errcode;
215 static int get_counter(const char **p)
217 int i, n;
218 if (!p || !(*p)) {
219 return 1;
221 if (!isdigit((int)**p)) {
222 return 1;
224 for (n = 0;;) {
225 i = **p;
226 if (isdigit(i)) {
227 n = 10 * n + (i - '0');
228 } else {
229 return n;
231 (*p)++;
235 static int getlen(const char *p)
237 int n = 0;
238 if (!p) {
239 return 0;
242 while (*p) {
243 switch( *p++ ) {
244 case 'W': /* word (2 byte) */
245 n += 2;
246 break;
247 case 'K': /* status word? (2 byte) */
248 n += 2;
249 break;
250 case 'N': /* count of substructures (word) at end */
251 n += 2;
252 break;
253 case 'D': /* double word (4 byte) */
254 case 'z': /* offset to zero terminated string (4 byte) */
255 case 'l': /* offset to user data (4 byte) */
256 n += 4;
257 break;
258 case 'b': /* offset to data (with counter) (4 byte) */
259 n += 4;
260 get_counter(&p);
261 break;
262 case 'B': /* byte (with optional counter) */
263 n += get_counter(&p);
264 break;
267 return n;
270 static bool init_package(struct pack_desc *p, int count, int subcount)
272 int n = p->buflen;
273 int i;
275 if (!p->format || !p->base) {
276 return False;
279 i = count * getlen(p->format);
280 if (p->subformat) {
281 i += subcount * getlen(p->subformat);
283 p->structbuf = p->base;
284 p->neededlen = 0;
285 p->usedlen = 0;
286 p->subcount = 0;
287 p->curpos = p->format;
288 if (i > n) {
289 p->neededlen = i;
290 i = n = 0;
291 #if 0
293 * This is the old error code we used. Aparently
294 * WinNT/2k systems return ERRbuftoosmall (2123) and
295 * OS/2 needs this. I'm leaving this here so we can revert
296 * if needed. JRA.
298 p->errcode = ERRmoredata;
299 #else
300 p->errcode = ERRbuftoosmall;
301 #endif
302 } else {
303 p->errcode = NERR_Success;
305 p->buflen = i;
306 n -= i;
307 p->stringbuf = p->base + i;
308 p->stringlen = n;
309 return (p->errcode == NERR_Success);
312 static int package(struct pack_desc *p, ...)
314 va_list args;
315 int needed=0, stringneeded;
316 const char *str=NULL;
317 int is_string=0, stringused;
318 int32 temp;
320 va_start(args,p);
322 if (!*p->curpos) {
323 if (!p->subcount) {
324 p->curpos = p->format;
325 } else {
326 p->curpos = p->subformat;
327 p->subcount--;
330 #if CHECK_TYPES
331 str = va_arg(args,char*);
332 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
333 #endif
334 stringneeded = -1;
336 if (!p->curpos) {
337 va_end(args);
338 return 0;
341 switch( *p->curpos++ ) {
342 case 'W': /* word (2 byte) */
343 needed = 2;
344 temp = va_arg(args,int);
345 if (p->buflen >= needed) {
346 SSVAL(p->structbuf,0,temp);
348 break;
349 case 'K': /* status word? (2 byte) */
350 needed = 2;
351 temp = va_arg(args,int);
352 if (p->buflen >= needed) {
353 SSVAL(p->structbuf,0,temp);
355 break;
356 case 'N': /* count of substructures (word) at end */
357 needed = 2;
358 p->subcount = va_arg(args,int);
359 if (p->buflen >= needed) {
360 SSVAL(p->structbuf,0,p->subcount);
362 break;
363 case 'D': /* double word (4 byte) */
364 needed = 4;
365 temp = va_arg(args,int);
366 if (p->buflen >= needed) {
367 SIVAL(p->structbuf,0,temp);
369 break;
370 case 'B': /* byte (with optional counter) */
371 needed = get_counter(&p->curpos);
373 char *s = va_arg(args,char*);
374 if (p->buflen >= needed) {
375 StrnCpy(p->structbuf,s?s:"",needed-1);
378 break;
379 case 'z': /* offset to zero terminated string (4 byte) */
380 str = va_arg(args,char*);
381 stringneeded = (str ? strlen(str)+1 : 0);
382 is_string = 1;
383 break;
384 case 'l': /* offset to user data (4 byte) */
385 str = va_arg(args,char*);
386 stringneeded = va_arg(args,int);
387 is_string = 0;
388 break;
389 case 'b': /* offset to data (with counter) (4 byte) */
390 str = va_arg(args,char*);
391 stringneeded = get_counter(&p->curpos);
392 is_string = 0;
393 break;
396 va_end(args);
397 if (stringneeded >= 0) {
398 needed = 4;
399 if (p->buflen >= needed) {
400 stringused = stringneeded;
401 if (stringused > p->stringlen) {
402 stringused = (is_string ? p->stringlen : 0);
403 if (p->errcode == NERR_Success) {
404 p->errcode = ERRmoredata;
407 if (!stringused) {
408 SIVAL(p->structbuf,0,0);
409 } else {
410 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
411 memcpy(p->stringbuf,str?str:"",stringused);
412 if (is_string) {
413 p->stringbuf[stringused-1] = '\0';
415 p->stringbuf += stringused;
416 p->stringlen -= stringused;
417 p->usedlen += stringused;
420 p->neededlen += stringneeded;
423 p->neededlen += needed;
424 if (p->buflen >= needed) {
425 p->structbuf += needed;
426 p->buflen -= needed;
427 p->usedlen += needed;
428 } else {
429 if (p->errcode == NERR_Success) {
430 p->errcode = ERRmoredata;
433 return 1;
436 #if CHECK_TYPES
437 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
438 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
439 #else
440 #define PACK(desc,t,v) package(desc,v)
441 #define PACKl(desc,t,v,l) package(desc,v,l)
442 #endif
444 static void PACKI(struct pack_desc* desc, const char *t,int v)
446 PACK(desc,t,v);
449 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
451 PACK(desc,t,v);
454 /****************************************************************************
455 Get a print queue.
456 ****************************************************************************/
458 static void PackDriverData(struct pack_desc* desc)
460 char drivdata[4+4+32];
461 SIVAL(drivdata,0,sizeof drivdata); /* cb */
462 SIVAL(drivdata,4,1000); /* lVersion */
463 memset(drivdata+8,0,32); /* szDeviceName */
464 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
465 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
468 static int check_printq_info(struct pack_desc* desc,
469 unsigned int uLevel, char *id1, char *id2)
471 desc->subformat = NULL;
472 switch( uLevel ) {
473 case 0:
474 desc->format = "B13";
475 break;
476 case 1:
477 desc->format = "B13BWWWzzzzzWW";
478 break;
479 case 2:
480 desc->format = "B13BWWWzzzzzWN";
481 desc->subformat = "WB21BB16B10zWWzDDz";
482 break;
483 case 3:
484 desc->format = "zWWWWzzzzWWzzl";
485 break;
486 case 4:
487 desc->format = "zWWWWzzzzWNzzl";
488 desc->subformat = "WWzWWDDzz";
489 break;
490 case 5:
491 desc->format = "z";
492 break;
493 case 51:
494 desc->format = "K";
495 break;
496 case 52:
497 desc->format = "WzzzzzzzzN";
498 desc->subformat = "z";
499 break;
500 default:
501 DEBUG(0,("check_printq_info: invalid level %d\n",
502 uLevel ));
503 return False;
505 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
506 DEBUG(0,("check_printq_info: invalid format %s\n",
507 id1 ? id1 : "<NULL>" ));
508 return False;
510 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
511 DEBUG(0,("check_printq_info: invalid subformat %s\n",
512 id2 ? id2 : "<NULL>" ));
513 return False;
515 return True;
519 #define RAP_JOB_STATUS_QUEUED 0
520 #define RAP_JOB_STATUS_PAUSED 1
521 #define RAP_JOB_STATUS_SPOOLING 2
522 #define RAP_JOB_STATUS_PRINTING 3
523 #define RAP_JOB_STATUS_PRINTED 4
525 #define RAP_QUEUE_STATUS_PAUSED 1
526 #define RAP_QUEUE_STATUS_ERROR 2
528 /* turn a print job status into a on the wire status
530 static int printj_status(int v)
532 switch (v) {
533 case LPQ_QUEUED:
534 return RAP_JOB_STATUS_QUEUED;
535 case LPQ_PAUSED:
536 return RAP_JOB_STATUS_PAUSED;
537 case LPQ_SPOOLING:
538 return RAP_JOB_STATUS_SPOOLING;
539 case LPQ_PRINTING:
540 return RAP_JOB_STATUS_PRINTING;
542 return 0;
545 /* turn a print queue status into a on the wire status
547 static int printq_status(int v)
549 switch (v) {
550 case LPQ_QUEUED:
551 return 0;
552 case LPQ_PAUSED:
553 return RAP_QUEUE_STATUS_PAUSED;
555 return RAP_QUEUE_STATUS_ERROR;
558 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
559 struct pack_desc *desc,
560 print_queue_struct *queue, int n)
562 time_t t = queue->time;
564 /* the client expects localtime */
565 t -= get_time_zone(t);
567 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
568 if (uLevel == 1) {
569 PACKS(desc,"B21",queue->fs_user); /* szUserName */
570 PACKS(desc,"B",""); /* pad */
571 PACKS(desc,"B16",""); /* szNotifyName */
572 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
573 PACKS(desc,"z",""); /* pszParms */
574 PACKI(desc,"W",n+1); /* uPosition */
575 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
576 PACKS(desc,"z",""); /* pszStatus */
577 PACKI(desc,"D",t); /* ulSubmitted */
578 PACKI(desc,"D",queue->size); /* ulSize */
579 PACKS(desc,"z",queue->fs_file); /* pszComment */
581 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
582 PACKI(desc,"W",queue->priority); /* uPriority */
583 PACKS(desc,"z",queue->fs_user); /* pszUserName */
584 PACKI(desc,"W",n+1); /* uPosition */
585 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
586 PACKI(desc,"D",t); /* ulSubmitted */
587 PACKI(desc,"D",queue->size); /* ulSize */
588 PACKS(desc,"z","Samba"); /* pszComment */
589 PACKS(desc,"z",queue->fs_file); /* pszDocument */
590 if (uLevel == 3) {
591 PACKS(desc,"z",""); /* pszNotifyName */
592 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
593 PACKS(desc,"z",""); /* pszParms */
594 PACKS(desc,"z",""); /* pszStatus */
595 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
596 PACKS(desc,"z","lpd"); /* pszQProcName */
597 PACKS(desc,"z",""); /* pszQProcParms */
598 PACKS(desc,"z","NULL"); /* pszDriverName */
599 PackDriverData(desc); /* pDriverData */
600 PACKS(desc,"z",""); /* pszPrinterName */
601 } else if (uLevel == 4) { /* OS2 */
602 PACKS(desc,"z",""); /* pszSpoolFileName */
603 PACKS(desc,"z",""); /* pszPortName */
604 PACKS(desc,"z",""); /* pszStatus */
605 PACKI(desc,"D",0); /* ulPagesSpooled */
606 PACKI(desc,"D",0); /* ulPagesSent */
607 PACKI(desc,"D",0); /* ulPagesPrinted */
608 PACKI(desc,"D",0); /* ulTimePrinted */
609 PACKI(desc,"D",0); /* ulExtendJobStatus */
610 PACKI(desc,"D",0); /* ulStartPage */
611 PACKI(desc,"D",0); /* ulEndPage */
616 /********************************************************************
617 Return a driver name given an snum.
618 Returns True if from tdb, False otherwise.
619 ********************************************************************/
621 static bool get_driver_name(int snum, char **pp_drivername)
623 NT_PRINTER_INFO_LEVEL *info = NULL;
624 bool in_tdb = false;
626 get_a_printer (NULL, &info, 2, lp_servicename(snum));
627 if (info != NULL) {
628 *pp_drivername = talloc_strdup(talloc_tos(),
629 info->info_2->drivername);
630 in_tdb = true;
631 free_a_printer(&info, 2);
632 if (!*pp_drivername) {
633 return false;
637 return in_tdb;
640 /********************************************************************
641 Respond to the DosPrintQInfo command with a level of 52
642 This is used to get printer driver information for Win9x clients
643 ********************************************************************/
644 static void fill_printq_info_52(connection_struct *conn, int snum,
645 struct pack_desc* desc, int count )
647 int i;
648 fstring location;
649 NT_PRINTER_DRIVER_INFO_LEVEL driver;
650 NT_PRINTER_INFO_LEVEL *printer = NULL;
652 ZERO_STRUCT(driver);
654 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
655 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
656 lp_servicename(snum)));
657 goto err;
660 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
661 "Windows 4.0", 0)) )
663 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
664 printer->info_2->drivername));
665 goto err;
668 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
669 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
670 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
672 PACKI(desc, "W", 0x0400); /* don't know */
673 PACKS(desc, "z", driver.info_3->name); /* long printer name */
674 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
675 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
676 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
678 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
679 standard_sub_basic( "", "", location, sizeof(location)-1 );
680 PACKS(desc,"z", location); /* share to retrieve files */
682 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
683 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
684 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
686 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
687 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
688 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
689 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
690 DEBUG(3,("Driver Location: %s:\n",location));
691 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
692 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
693 PACKI(desc,"N",count); /* number of files to copy */
695 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
697 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
698 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
699 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
702 /* sanity check */
703 if ( i != count )
704 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
705 count, i));
707 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
709 desc->errcode=NERR_Success;
710 goto done;
712 err:
713 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
714 desc->errcode=NERR_notsupported;
716 done:
717 if ( printer )
718 free_a_printer( &printer, 2 );
720 if ( driver.info_3 )
721 free_a_printer_driver( driver, 3 );
725 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
726 struct pack_desc* desc,
727 int count, print_queue_struct* queue,
728 print_status_struct* status)
730 switch (uLevel) {
731 case 1:
732 case 2:
733 PACKS(desc,"B13",SERVICE(snum));
734 break;
735 case 3:
736 case 4:
737 case 5:
738 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
739 break;
740 case 51:
741 PACKI(desc,"K",printq_status(status->status));
742 break;
745 if (uLevel == 1 || uLevel == 2) {
746 PACKS(desc,"B",""); /* alignment */
747 PACKI(desc,"W",5); /* priority */
748 PACKI(desc,"W",0); /* start time */
749 PACKI(desc,"W",0); /* until time */
750 PACKS(desc,"z",""); /* pSepFile */
751 PACKS(desc,"z","lpd"); /* pPrProc */
752 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
753 PACKS(desc,"z",""); /* pParms */
754 if (snum < 0) {
755 PACKS(desc,"z","UNKNOWN PRINTER");
756 PACKI(desc,"W",LPSTAT_ERROR);
758 else if (!status || !status->message[0]) {
759 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
760 PACKI(desc,"W",LPSTAT_OK); /* status */
761 } else {
762 PACKS(desc,"z",status->message);
763 PACKI(desc,"W",printq_status(status->status)); /* status */
765 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
768 if (uLevel == 3 || uLevel == 4) {
769 char *drivername = NULL;
771 PACKI(desc,"W",5); /* uPriority */
772 PACKI(desc,"W",0); /* uStarttime */
773 PACKI(desc,"W",0); /* uUntiltime */
774 PACKI(desc,"W",5); /* pad1 */
775 PACKS(desc,"z",""); /* pszSepFile */
776 PACKS(desc,"z","WinPrint"); /* pszPrProc */
777 PACKS(desc,"z",NULL); /* pszParms */
778 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
779 /* "don't ask" that it's done this way to fix corrupted
780 Win9X/ME printer comments. */
781 if (!status) {
782 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
783 } else {
784 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
786 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
787 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
788 get_driver_name(snum,&drivername);
789 if (!drivername) {
790 return;
792 PACKS(desc,"z",drivername); /* pszDriverName */
793 PackDriverData(desc); /* pDriverData */
796 if (uLevel == 2 || uLevel == 4) {
797 int i;
798 for (i=0;i<count;i++)
799 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
802 if (uLevel==52)
803 fill_printq_info_52( conn, snum, desc, count );
806 /* This function returns the number of files for a given driver */
807 static int get_printerdrivernumber(int snum)
809 int result = 0;
810 NT_PRINTER_DRIVER_INFO_LEVEL driver;
811 NT_PRINTER_INFO_LEVEL *printer = NULL;
813 ZERO_STRUCT(driver);
815 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
816 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
817 lp_servicename(snum)));
818 goto done;
821 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
822 "Windows 4.0", 0)) )
824 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
825 printer->info_2->drivername));
826 goto done;
829 /* count the number of files */
830 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
831 result++;
833 done:
834 if ( printer )
835 free_a_printer( &printer, 2 );
837 if ( driver.info_3 )
838 free_a_printer_driver( driver, 3 );
840 return result;
843 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
844 char *param, int tpscnt,
845 char *data, int tdscnt,
846 int mdrcnt,int mprcnt,
847 char **rdata,char **rparam,
848 int *rdata_len,int *rparam_len)
850 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
851 char *str2 = skip_string(param,tpscnt,str1);
852 char *p = skip_string(param,tpscnt,str2);
853 char *QueueName = p;
854 unsigned int uLevel;
855 int count=0;
856 int snum;
857 char *str3;
858 struct pack_desc desc;
859 print_queue_struct *queue=NULL;
860 print_status_struct status;
861 char* tmpdata=NULL;
863 if (!str1 || !str2 || !p) {
864 return False;
866 memset((char *)&status,'\0',sizeof(status));
867 memset((char *)&desc,'\0',sizeof(desc));
869 p = skip_string(param,tpscnt,p);
870 if (!p) {
871 return False;
873 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
874 str3 = get_safe_str_ptr(param,tpscnt,p,4);
875 /* str3 may be null here and is checked in check_printq_info(). */
877 /* remove any trailing username */
878 if ((p = strchr_m(QueueName,'%')))
879 *p = 0;
881 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
883 /* check it's a supported varient */
884 if (!prefix_ok(str1,"zWrLh"))
885 return False;
886 if (!check_printq_info(&desc,uLevel,str2,str3)) {
888 * Patch from Scott Moomaw <scott@bridgewater.edu>
889 * to return the 'invalid info level' error if an
890 * unknown level was requested.
892 *rdata_len = 0;
893 *rparam_len = 6;
894 *rparam = smb_realloc_limit(*rparam,*rparam_len);
895 if (!*rparam) {
896 return False;
898 SSVALS(*rparam,0,ERRunknownlevel);
899 SSVAL(*rparam,2,0);
900 SSVAL(*rparam,4,0);
901 return(True);
904 snum = find_service(QueueName);
905 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
906 return False;
908 if (uLevel==52) {
909 count = get_printerdrivernumber(snum);
910 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
911 } else {
912 count = print_queue_status(snum, &queue,&status);
915 if (mdrcnt > 0) {
916 *rdata = smb_realloc_limit(*rdata,mdrcnt);
917 if (!*rdata) {
918 SAFE_FREE(queue);
919 return False;
921 desc.base = *rdata;
922 desc.buflen = mdrcnt;
923 } else {
925 * Don't return data but need to get correct length
926 * init_package will return wrong size if buflen=0
928 desc.buflen = getlen(desc.format);
929 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
932 if (init_package(&desc,1,count)) {
933 desc.subcount = count;
934 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
937 *rdata_len = desc.usedlen;
940 * We must set the return code to ERRbuftoosmall
941 * in order to support lanman style printing with Win NT/2k
942 * clients --jerry
944 if (!mdrcnt && lp_disable_spoolss())
945 desc.errcode = ERRbuftoosmall;
947 *rdata_len = desc.usedlen;
948 *rparam_len = 6;
949 *rparam = smb_realloc_limit(*rparam,*rparam_len);
950 if (!*rparam) {
951 SAFE_FREE(queue);
952 SAFE_FREE(tmpdata);
953 return False;
955 SSVALS(*rparam,0,desc.errcode);
956 SSVAL(*rparam,2,0);
957 SSVAL(*rparam,4,desc.neededlen);
959 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
961 SAFE_FREE(queue);
962 SAFE_FREE(tmpdata);
964 return(True);
967 /****************************************************************************
968 View list of all print jobs on all queues.
969 ****************************************************************************/
971 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
972 char *param, int tpscnt,
973 char *data, int tdscnt,
974 int mdrcnt, int mprcnt,
975 char **rdata, char** rparam,
976 int *rdata_len, int *rparam_len)
978 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
979 char *output_format1 = skip_string(param,tpscnt,param_format);
980 char *p = skip_string(param,tpscnt,output_format1);
981 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
982 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
983 int services = lp_numservices();
984 int i, n;
985 struct pack_desc desc;
986 print_queue_struct **queue = NULL;
987 print_status_struct *status = NULL;
988 int *subcntarr = NULL;
989 int queuecnt = 0, subcnt = 0, succnt = 0;
991 if (!param_format || !output_format1 || !p) {
992 return False;
995 memset((char *)&desc,'\0',sizeof(desc));
997 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
999 if (!prefix_ok(param_format,"WrLeh")) {
1000 return False;
1002 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1004 * Patch from Scott Moomaw <scott@bridgewater.edu>
1005 * to return the 'invalid info level' error if an
1006 * unknown level was requested.
1008 *rdata_len = 0;
1009 *rparam_len = 6;
1010 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1011 if (!*rparam) {
1012 return False;
1014 SSVALS(*rparam,0,ERRunknownlevel);
1015 SSVAL(*rparam,2,0);
1016 SSVAL(*rparam,4,0);
1017 return(True);
1020 for (i = 0; i < services; i++) {
1021 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1022 queuecnt++;
1026 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1027 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1028 goto err;
1030 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1031 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1032 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1033 goto err;
1035 memset(status,0,queuecnt*sizeof(print_status_struct));
1036 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1037 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1038 goto err;
1041 subcnt = 0;
1042 n = 0;
1043 for (i = 0; i < services; i++) {
1044 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1045 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1046 subcnt += subcntarr[n];
1047 n++;
1051 if (mdrcnt > 0) {
1052 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1053 if (!*rdata) {
1054 goto err;
1057 desc.base = *rdata;
1058 desc.buflen = mdrcnt;
1060 if (init_package(&desc,queuecnt,subcnt)) {
1061 n = 0;
1062 succnt = 0;
1063 for (i = 0; i < services; i++) {
1064 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1065 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1066 n++;
1067 if (desc.errcode == NERR_Success) {
1068 succnt = n;
1074 SAFE_FREE(subcntarr);
1076 *rdata_len = desc.usedlen;
1077 *rparam_len = 8;
1078 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1079 if (!*rparam) {
1080 goto err;
1082 SSVALS(*rparam,0,desc.errcode);
1083 SSVAL(*rparam,2,0);
1084 SSVAL(*rparam,4,succnt);
1085 SSVAL(*rparam,6,queuecnt);
1087 for (i = 0; i < queuecnt; i++) {
1088 if (queue) {
1089 SAFE_FREE(queue[i]);
1093 SAFE_FREE(queue);
1094 SAFE_FREE(status);
1096 return True;
1098 err:
1100 SAFE_FREE(subcntarr);
1101 for (i = 0; i < queuecnt; i++) {
1102 if (queue) {
1103 SAFE_FREE(queue[i]);
1106 SAFE_FREE(queue);
1107 SAFE_FREE(status);
1109 return False;
1112 /****************************************************************************
1113 Get info level for a server list query.
1114 ****************************************************************************/
1116 static bool check_server_info(int uLevel, char* id)
1118 switch( uLevel ) {
1119 case 0:
1120 if (strcmp(id,"B16") != 0) {
1121 return False;
1123 break;
1124 case 1:
1125 if (strcmp(id,"B16BBDz") != 0) {
1126 return False;
1128 break;
1129 default:
1130 return False;
1132 return True;
1135 struct srv_info_struct {
1136 fstring name;
1137 uint32 type;
1138 fstring comment;
1139 fstring domain;
1140 bool server_added;
1143 /*******************************************************************
1144 Get server info lists from the files saved by nmbd. Return the
1145 number of entries.
1146 ******************************************************************/
1148 static int get_server_info(uint32 servertype,
1149 struct srv_info_struct **servers,
1150 const char *domain)
1152 int count=0;
1153 int alloced=0;
1154 char **lines;
1155 bool local_list_only;
1156 int i;
1158 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1159 if (!lines) {
1160 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1161 return 0;
1164 /* request for everything is code for request all servers */
1165 if (servertype == SV_TYPE_ALL) {
1166 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1169 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1171 DEBUG(4,("Servertype search: %8x\n",servertype));
1173 for (i=0;lines[i];i++) {
1174 fstring stype;
1175 struct srv_info_struct *s;
1176 const char *ptr = lines[i];
1177 bool ok = True;
1178 TALLOC_CTX *frame = NULL;
1179 char *p;
1181 if (!*ptr) {
1182 continue;
1185 if (count == alloced) {
1186 alloced += 10;
1187 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1188 if (!*servers) {
1189 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1190 TALLOC_FREE(lines);
1191 return 0;
1193 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1195 s = &(*servers)[count];
1197 frame = talloc_stackframe();
1198 s->name[0] = '\0';
1199 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1200 TALLOC_FREE(frame);
1201 continue;
1203 fstrcpy(s->name, p);
1205 stype[0] = '\0';
1206 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1207 TALLOC_FREE(frame);
1208 continue;
1210 fstrcpy(stype, p);
1212 s->comment[0] = '\0';
1213 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1214 TALLOC_FREE(frame);
1215 continue;
1217 fstrcpy(s->comment, p);
1218 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1220 s->domain[0] = '\0';
1221 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1222 /* this allows us to cope with an old nmbd */
1223 fstrcpy(s->domain,lp_workgroup());
1224 } else {
1225 fstrcpy(s->domain, p);
1227 TALLOC_FREE(frame);
1229 if (sscanf(stype,"%X",&s->type) != 1) {
1230 DEBUG(4,("r:host file "));
1231 ok = False;
1234 /* Filter the servers/domains we return based on what was asked for. */
1236 /* Check to see if we are being asked for a local list only. */
1237 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1238 DEBUG(4,("r: local list only"));
1239 ok = False;
1242 /* doesn't match up: don't want it */
1243 if (!(servertype & s->type)) {
1244 DEBUG(4,("r:serv type "));
1245 ok = False;
1248 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1249 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1250 DEBUG(4,("s: dom mismatch "));
1251 ok = False;
1254 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1255 ok = False;
1258 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1259 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1261 if (ok) {
1262 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1263 s->name, s->type, s->comment, s->domain));
1264 s->server_added = True;
1265 count++;
1266 } else {
1267 DEBUG(4,("%20s %8x %25s %15s\n",
1268 s->name, s->type, s->comment, s->domain));
1272 TALLOC_FREE(lines);
1273 return count;
1276 /*******************************************************************
1277 Fill in a server info structure.
1278 ******************************************************************/
1280 static int fill_srv_info(struct srv_info_struct *service,
1281 int uLevel, char **buf, int *buflen,
1282 char **stringbuf, int *stringspace, char *baseaddr)
1284 int struct_len;
1285 char* p;
1286 char* p2;
1287 int l2;
1288 int len;
1290 switch (uLevel) {
1291 case 0:
1292 struct_len = 16;
1293 break;
1294 case 1:
1295 struct_len = 26;
1296 break;
1297 default:
1298 return -1;
1301 if (!buf) {
1302 len = 0;
1303 switch (uLevel) {
1304 case 1:
1305 len = strlen(service->comment)+1;
1306 break;
1309 *buflen = struct_len;
1310 *stringspace = len;
1311 return struct_len + len;
1314 len = struct_len;
1315 p = *buf;
1316 if (*buflen < struct_len) {
1317 return -1;
1319 if (stringbuf) {
1320 p2 = *stringbuf;
1321 l2 = *stringspace;
1322 } else {
1323 p2 = p + struct_len;
1324 l2 = *buflen - struct_len;
1326 if (!baseaddr) {
1327 baseaddr = p;
1330 switch (uLevel) {
1331 case 0:
1332 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1333 break;
1335 case 1:
1336 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1337 SIVAL(p,18,service->type);
1338 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1339 len += CopyAndAdvance(&p2,service->comment,&l2);
1340 break;
1343 if (stringbuf) {
1344 *buf = p + struct_len;
1345 *buflen -= struct_len;
1346 *stringbuf = p2;
1347 *stringspace = l2;
1348 } else {
1349 *buf = p2;
1350 *buflen -= len;
1352 return len;
1356 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1358 return(strcmp(s1->name,s2->name));
1361 /****************************************************************************
1362 View list of servers available (or possibly domains). The info is
1363 extracted from lists saved by nmbd on the local host.
1364 ****************************************************************************/
1366 static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
1367 char *param, int tpscnt,
1368 char *data, int tdscnt,
1369 int mdrcnt, int mprcnt, char **rdata,
1370 char **rparam, int *rdata_len, int *rparam_len)
1372 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1373 char *str2 = skip_string(param,tpscnt,str1);
1374 char *p = skip_string(param,tpscnt,str2);
1375 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1376 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1377 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1378 char *p2;
1379 int data_len, fixed_len, string_len;
1380 int f_len = 0, s_len = 0;
1381 struct srv_info_struct *servers=NULL;
1382 int counted=0,total=0;
1383 int i,missed;
1384 fstring domain;
1385 bool domain_request;
1386 bool local_request;
1388 if (!str1 || !str2 || !p) {
1389 return False;
1392 /* If someone sets all the bits they don't really mean to set
1393 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1394 known servers. */
1396 if (servertype == SV_TYPE_ALL) {
1397 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1400 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1401 any other bit (they may just set this bit on its own) they
1402 want all the locally seen servers. However this bit can be
1403 set on its own so set the requested servers to be
1404 ALL - DOMAIN_ENUM. */
1406 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1407 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1410 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1411 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1413 p += 8;
1415 if (!prefix_ok(str1,"WrLehD")) {
1416 return False;
1418 if (!check_server_info(uLevel,str2)) {
1419 return False;
1422 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1423 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1424 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1426 if (strcmp(str1, "WrLehDz") == 0) {
1427 if (skip_string(param,tpscnt,p) == NULL) {
1428 return False;
1430 pull_ascii_fstring(domain, p);
1431 } else {
1432 fstrcpy(domain, lp_workgroup());
1435 if (lp_browse_list()) {
1436 total = get_server_info(servertype,&servers,domain);
1439 data_len = fixed_len = string_len = 0;
1440 missed = 0;
1442 if (total > 0) {
1443 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1447 char *lastname=NULL;
1449 for (i=0;i<total;i++) {
1450 struct srv_info_struct *s = &servers[i];
1452 if (lastname && strequal(lastname,s->name)) {
1453 continue;
1455 lastname = s->name;
1456 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1457 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1458 s->name, s->type, s->comment, s->domain));
1460 if (data_len <= buf_len) {
1461 counted++;
1462 fixed_len += f_len;
1463 string_len += s_len;
1464 } else {
1465 missed++;
1470 *rdata_len = fixed_len + string_len;
1471 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1472 if (!*rdata) {
1473 return False;
1476 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1477 p = *rdata;
1478 f_len = fixed_len;
1479 s_len = string_len;
1482 char *lastname=NULL;
1483 int count2 = counted;
1485 for (i = 0; i < total && count2;i++) {
1486 struct srv_info_struct *s = &servers[i];
1488 if (lastname && strequal(lastname,s->name)) {
1489 continue;
1491 lastname = s->name;
1492 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1493 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1494 s->name, s->type, s->comment, s->domain));
1495 count2--;
1499 *rparam_len = 8;
1500 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1501 if (!*rparam) {
1502 return False;
1504 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1505 SSVAL(*rparam,2,0);
1506 SSVAL(*rparam,4,counted);
1507 SSVAL(*rparam,6,counted+missed);
1509 SAFE_FREE(servers);
1511 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1512 domain,uLevel,counted,counted+missed));
1514 return True;
1517 /****************************************************************************
1518 command 0x34 - suspected of being a "Lookup Names" stub api
1519 ****************************************************************************/
1521 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1522 char *param, int tpscnt,
1523 char *data, int tdscnt,
1524 int mdrcnt, int mprcnt, char **rdata,
1525 char **rparam, int *rdata_len, int *rparam_len)
1527 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1528 char *str2 = skip_string(param,tpscnt,str1);
1529 char *p = skip_string(param,tpscnt,str2);
1530 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1531 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1532 int counted=0;
1533 int missed=0;
1535 if (!str1 || !str2 || !p) {
1536 return False;
1539 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1540 str1, str2, p, uLevel, buf_len));
1542 if (!prefix_ok(str1,"zWrLeh")) {
1543 return False;
1546 *rdata_len = 0;
1548 *rparam_len = 8;
1549 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1550 if (!*rparam) {
1551 return False;
1554 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1555 SSVAL(*rparam,2,0);
1556 SSVAL(*rparam,4,counted);
1557 SSVAL(*rparam,6,counted+missed);
1559 return True;
1562 /****************************************************************************
1563 get info about a share
1564 ****************************************************************************/
1566 static bool check_share_info(int uLevel, char* id)
1568 switch( uLevel ) {
1569 case 0:
1570 if (strcmp(id,"B13") != 0) {
1571 return False;
1573 break;
1574 case 1:
1575 if (strcmp(id,"B13BWz") != 0) {
1576 return False;
1578 break;
1579 case 2:
1580 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1581 return False;
1583 break;
1584 case 91:
1585 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1586 return False;
1588 break;
1589 default:
1590 return False;
1592 return True;
1595 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1596 char** buf, int* buflen,
1597 char** stringbuf, int* stringspace, char* baseaddr)
1599 int struct_len;
1600 char* p;
1601 char* p2;
1602 int l2;
1603 int len;
1605 switch( uLevel ) {
1606 case 0:
1607 struct_len = 13;
1608 break;
1609 case 1:
1610 struct_len = 20;
1611 break;
1612 case 2:
1613 struct_len = 40;
1614 break;
1615 case 91:
1616 struct_len = 68;
1617 break;
1618 default:
1619 return -1;
1622 if (!buf) {
1623 len = 0;
1625 if (uLevel > 0) {
1626 len += StrlenExpanded(conn,snum,lp_comment(snum));
1628 if (uLevel > 1) {
1629 len += strlen(lp_pathname(snum)) + 1;
1631 if (buflen) {
1632 *buflen = struct_len;
1634 if (stringspace) {
1635 *stringspace = len;
1637 return struct_len + len;
1640 len = struct_len;
1641 p = *buf;
1642 if ((*buflen) < struct_len) {
1643 return -1;
1646 if (stringbuf) {
1647 p2 = *stringbuf;
1648 l2 = *stringspace;
1649 } else {
1650 p2 = p + struct_len;
1651 l2 = (*buflen) - struct_len;
1654 if (!baseaddr) {
1655 baseaddr = p;
1658 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1660 if (uLevel > 0) {
1661 int type;
1663 SCVAL(p,13,0);
1664 type = STYPE_DISKTREE;
1665 if (lp_print_ok(snum)) {
1666 type = STYPE_PRINTQ;
1668 if (strequal("IPC",lp_fstype(snum))) {
1669 type = STYPE_IPC;
1671 SSVAL(p,14,type); /* device type */
1672 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1673 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1676 if (uLevel > 1) {
1677 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1678 SSVALS(p,22,-1); /* max uses */
1679 SSVAL(p,24,1); /* current uses */
1680 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1681 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1682 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1685 if (uLevel > 2) {
1686 memset(p+40,0,SHPWLEN+2);
1687 SSVAL(p,50,0);
1688 SIVAL(p,52,0);
1689 SSVAL(p,56,0);
1690 SSVAL(p,58,0);
1691 SIVAL(p,60,0);
1692 SSVAL(p,64,0);
1693 SSVAL(p,66,0);
1696 if (stringbuf) {
1697 (*buf) = p + struct_len;
1698 (*buflen) -= struct_len;
1699 (*stringbuf) = p2;
1700 (*stringspace) = l2;
1701 } else {
1702 (*buf) = p2;
1703 (*buflen) -= len;
1706 return len;
1709 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1710 char *param, int tpscnt,
1711 char *data, int tdscnt,
1712 int mdrcnt,int mprcnt,
1713 char **rdata,char **rparam,
1714 int *rdata_len,int *rparam_len)
1716 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1717 char *str2 = skip_string(param,tpscnt,str1);
1718 char *netname = skip_string(param,tpscnt,str2);
1719 char *p = skip_string(param,tpscnt,netname);
1720 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1721 int snum;
1723 if (!str1 || !str2 || !netname || !p) {
1724 return False;
1727 snum = find_service(netname);
1728 if (snum < 0) {
1729 return False;
1732 /* check it's a supported varient */
1733 if (!prefix_ok(str1,"zWrLh")) {
1734 return False;
1736 if (!check_share_info(uLevel,str2)) {
1737 return False;
1740 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1741 if (!*rdata) {
1742 return False;
1744 p = *rdata;
1745 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1746 if (*rdata_len < 0) {
1747 return False;
1750 *rparam_len = 6;
1751 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1752 if (!*rparam) {
1753 return False;
1755 SSVAL(*rparam,0,NERR_Success);
1756 SSVAL(*rparam,2,0); /* converter word */
1757 SSVAL(*rparam,4,*rdata_len);
1759 return True;
1762 /****************************************************************************
1763 View the list of available shares.
1765 This function is the server side of the NetShareEnum() RAP call.
1766 It fills the return buffer with share names and share comments.
1767 Note that the return buffer normally (in all known cases) allows only
1768 twelve byte strings for share names (plus one for a nul terminator).
1769 Share names longer than 12 bytes must be skipped.
1770 ****************************************************************************/
1772 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1773 char *param, int tpscnt,
1774 char *data, int tdscnt,
1775 int mdrcnt,
1776 int mprcnt,
1777 char **rdata,
1778 char **rparam,
1779 int *rdata_len,
1780 int *rparam_len )
1782 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1783 char *str2 = skip_string(param,tpscnt,str1);
1784 char *p = skip_string(param,tpscnt,str2);
1785 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1786 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1787 char *p2;
1788 int count = 0;
1789 int total=0,counted=0;
1790 bool missed = False;
1791 int i;
1792 int data_len, fixed_len, string_len;
1793 int f_len = 0, s_len = 0;
1795 if (!str1 || !str2 || !p) {
1796 return False;
1799 if (!prefix_ok(str1,"WrLeh")) {
1800 return False;
1802 if (!check_share_info(uLevel,str2)) {
1803 return False;
1806 /* Ensure all the usershares are loaded. */
1807 become_root();
1808 load_registry_shares();
1809 count = load_usershare_shares();
1810 unbecome_root();
1812 data_len = fixed_len = string_len = 0;
1813 for (i=0;i<count;i++) {
1814 fstring servicename_dos;
1815 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1816 continue;
1818 push_ascii_fstring(servicename_dos, lp_servicename(i));
1819 /* Maximum name length = 13. */
1820 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1821 total++;
1822 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1823 if (data_len <= buf_len) {
1824 counted++;
1825 fixed_len += f_len;
1826 string_len += s_len;
1827 } else {
1828 missed = True;
1833 *rdata_len = fixed_len + string_len;
1834 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1835 if (!*rdata) {
1836 return False;
1839 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1840 p = *rdata;
1841 f_len = fixed_len;
1842 s_len = string_len;
1844 for( i = 0; i < count; i++ ) {
1845 fstring servicename_dos;
1846 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1847 continue;
1850 push_ascii_fstring(servicename_dos, lp_servicename(i));
1851 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1852 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1853 break;
1858 *rparam_len = 8;
1859 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1860 if (!*rparam) {
1861 return False;
1863 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1864 SSVAL(*rparam,2,0);
1865 SSVAL(*rparam,4,counted);
1866 SSVAL(*rparam,6,total);
1868 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1869 counted,total,uLevel,
1870 buf_len,*rdata_len,mdrcnt));
1872 return True;
1875 /****************************************************************************
1876 Add a share
1877 ****************************************************************************/
1879 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1880 char *param, int tpscnt,
1881 char *data, int tdscnt,
1882 int mdrcnt,int mprcnt,
1883 char **rdata,char **rparam,
1884 int *rdata_len,int *rparam_len)
1886 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1887 char *str2 = skip_string(param,tpscnt,str1);
1888 char *p = skip_string(param,tpscnt,str2);
1889 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1890 fstring sharename;
1891 fstring comment;
1892 char *pathname = NULL;
1893 char *command, *cmdname;
1894 unsigned int offset;
1895 int snum;
1896 int res = ERRunsup;
1897 size_t converted_size;
1899 if (!str1 || !str2 || !p) {
1900 return False;
1903 /* check it's a supported varient */
1904 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1905 return False;
1907 if (!check_share_info(uLevel,str2)) {
1908 return False;
1910 if (uLevel != 2) {
1911 return False;
1914 /* Do we have a string ? */
1915 if (skip_string(data,mdrcnt,data) == NULL) {
1916 return False;
1918 pull_ascii_fstring(sharename,data);
1919 snum = find_service(sharename);
1920 if (snum >= 0) { /* already exists */
1921 res = ERRfilexists;
1922 goto error_exit;
1925 if (mdrcnt < 28) {
1926 return False;
1929 /* only support disk share adds */
1930 if (SVAL(data,14)!=STYPE_DISKTREE) {
1931 return False;
1934 offset = IVAL(data, 16);
1935 if (offset >= mdrcnt) {
1936 res = ERRinvalidparam;
1937 goto error_exit;
1940 /* Do we have a string ? */
1941 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1942 return False;
1944 pull_ascii_fstring(comment, offset? (data+offset) : "");
1946 offset = IVAL(data, 26);
1948 if (offset >= mdrcnt) {
1949 res = ERRinvalidparam;
1950 goto error_exit;
1953 /* Do we have a string ? */
1954 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1955 return False;
1958 if (!pull_ascii_talloc(talloc_tos(), &pathname,
1959 offset ? (data+offset) : "", &converted_size))
1961 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
1962 strerror(errno)));
1965 if (!pathname) {
1966 return false;
1969 string_replace(sharename, '"', ' ');
1970 string_replace(pathname, '"', ' ');
1971 string_replace(comment, '"', ' ');
1973 cmdname = lp_add_share_cmd();
1975 if (!cmdname || *cmdname == '\0') {
1976 return False;
1979 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1980 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
1981 pathname, comment) == -1) {
1982 return false;
1985 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1987 if ((res = smbrun(command, NULL)) != 0) {
1988 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
1989 command, res ));
1990 SAFE_FREE(command);
1991 res = ERRnoaccess;
1992 goto error_exit;
1993 } else {
1994 SAFE_FREE(command);
1995 message_send_all(smbd_messaging_context(),
1996 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1999 *rparam_len = 6;
2000 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2001 if (!*rparam) {
2002 return False;
2004 SSVAL(*rparam,0,NERR_Success);
2005 SSVAL(*rparam,2,0); /* converter word */
2006 SSVAL(*rparam,4,*rdata_len);
2007 *rdata_len = 0;
2009 return True;
2011 error_exit:
2013 *rparam_len = 4;
2014 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2015 if (!*rparam) {
2016 return False;
2018 *rdata_len = 0;
2019 SSVAL(*rparam,0,res);
2020 SSVAL(*rparam,2,0);
2021 return True;
2024 /****************************************************************************
2025 view list of groups available
2026 ****************************************************************************/
2028 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2029 char *param, int tpscnt,
2030 char *data, int tdscnt,
2031 int mdrcnt,int mprcnt,
2032 char **rdata,char **rparam,
2033 int *rdata_len,int *rparam_len)
2035 int i;
2036 int errflags=0;
2037 int resume_context, cli_buf_size;
2038 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2039 char *str2 = skip_string(param,tpscnt,str1);
2040 char *p = skip_string(param,tpscnt,str2);
2042 uint32_t num_groups;
2043 uint32_t resume_handle;
2044 struct rpc_pipe_client *samr_pipe;
2045 struct policy_handle samr_handle, domain_handle;
2046 NTSTATUS status;
2048 if (!str1 || !str2 || !p) {
2049 return False;
2052 if (strcmp(str1,"WrLeh") != 0) {
2053 return False;
2056 /* parameters
2057 * W-> resume context (number of users to skip)
2058 * r -> return parameter pointer to receive buffer
2059 * L -> length of receive buffer
2060 * e -> return parameter number of entries
2061 * h -> return parameter total number of users
2064 if (strcmp("B21",str2) != 0) {
2065 return False;
2068 status = rpc_pipe_open_internal(
2069 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2070 conn->server_info, &samr_pipe);
2071 if (!NT_STATUS_IS_OK(status)) {
2072 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2073 nt_errstr(status)));
2074 return false;
2077 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2078 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2079 if (!NT_STATUS_IS_OK(status)) {
2080 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2081 nt_errstr(status)));
2082 return false;
2085 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2086 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2087 get_global_sam_sid(), &domain_handle);
2088 if (!NT_STATUS_IS_OK(status)) {
2089 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2090 nt_errstr(status)));
2091 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2092 return false;
2095 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2096 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2097 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2098 "%d\n", resume_context, cli_buf_size));
2100 *rdata_len = cli_buf_size;
2101 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2102 if (!*rdata) {
2103 return False;
2106 p = *rdata;
2108 errflags = NERR_Success;
2109 num_groups = 0;
2110 resume_handle = 0;
2112 while (true) {
2113 struct samr_SamArray *sam_entries;
2114 uint32_t num_entries;
2116 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2117 &domain_handle,
2118 &resume_handle,
2119 &sam_entries, 1,
2120 &num_entries);
2121 if (!NT_STATUS_IS_OK(status)) {
2122 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2123 "%s\n", nt_errstr(status)));
2124 break;
2127 if (num_entries == 0) {
2128 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2129 "no entries -- done\n"));
2130 break;
2133 for(i=0; i<num_entries; i++) {
2134 const char *name;
2136 name = sam_entries->entries[i].name.string;
2138 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2139 /* set overflow error */
2140 DEBUG(3,("overflow on entry %d group %s\n", i,
2141 name));
2142 errflags=234;
2143 break;
2146 /* truncate the name at 21 chars. */
2147 memset(p, 0, 21);
2148 strlcpy(p, name, 21);
2149 DEBUG(10,("adding entry %d group %s\n", i, p));
2150 p += 21;
2151 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2152 * idea why... */
2153 num_groups += 1;
2156 if (errflags != NERR_Success) {
2157 break;
2160 TALLOC_FREE(sam_entries);
2163 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2164 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2166 *rdata_len = PTR_DIFF(p,*rdata);
2168 *rparam_len = 8;
2169 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2170 if (!*rparam) {
2171 return False;
2173 SSVAL(*rparam, 0, errflags);
2174 SSVAL(*rparam, 2, 0); /* converter word */
2175 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2176 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2178 return(True);
2181 /*******************************************************************
2182 Get groups that a user is a member of.
2183 ******************************************************************/
2185 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2186 char *param, int tpscnt,
2187 char *data, int tdscnt,
2188 int mdrcnt,int mprcnt,
2189 char **rdata,char **rparam,
2190 int *rdata_len,int *rparam_len)
2192 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2193 char *str2 = skip_string(param,tpscnt,str1);
2194 char *UserName = skip_string(param,tpscnt,str2);
2195 char *p = skip_string(param,tpscnt,UserName);
2196 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2197 const char *level_string;
2198 int count=0;
2199 bool ret = False;
2200 uint32_t i;
2201 char *endp = NULL;
2203 struct rpc_pipe_client *samr_pipe;
2204 struct policy_handle samr_handle, domain_handle, user_handle;
2205 struct lsa_String name;
2206 struct lsa_Strings names;
2207 struct samr_Ids type, rid;
2208 struct samr_RidWithAttributeArray *rids;
2209 NTSTATUS status;
2211 if (!str1 || !str2 || !UserName || !p) {
2212 return False;
2215 *rparam_len = 8;
2216 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2217 if (!*rparam) {
2218 return False;
2221 /* check it's a supported varient */
2223 if ( strcmp(str1,"zWrLeh") != 0 )
2224 return False;
2226 switch( uLevel ) {
2227 case 0:
2228 level_string = "B21";
2229 break;
2230 default:
2231 return False;
2234 if (strcmp(level_string,str2) != 0)
2235 return False;
2237 *rdata_len = mdrcnt + 1024;
2238 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2239 if (!*rdata) {
2240 return False;
2243 SSVAL(*rparam,0,NERR_Success);
2244 SSVAL(*rparam,2,0); /* converter word */
2246 p = *rdata;
2247 endp = *rdata + *rdata_len;
2249 status = rpc_pipe_open_internal(
2250 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2251 conn->server_info, &samr_pipe);
2252 if (!NT_STATUS_IS_OK(status)) {
2253 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2254 nt_errstr(status)));
2255 return false;
2258 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2259 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2260 if (!NT_STATUS_IS_OK(status)) {
2261 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2262 nt_errstr(status)));
2263 return false;
2266 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2267 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2268 get_global_sam_sid(), &domain_handle);
2269 if (!NT_STATUS_IS_OK(status)) {
2270 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2271 nt_errstr(status)));
2272 goto close_sam;
2275 name.string = UserName;
2277 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2278 &domain_handle, 1, &name,
2279 &rid, &type);
2280 if (!NT_STATUS_IS_OK(status)) {
2281 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2282 nt_errstr(status)));
2283 goto close_domain;
2286 if (type.ids[0] != SID_NAME_USER) {
2287 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2288 sid_type_lookup(type.ids[0])));
2289 goto close_domain;
2292 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2293 &domain_handle,
2294 SAMR_USER_ACCESS_GET_GROUPS,
2295 rid.ids[0], &user_handle);
2296 if (!NT_STATUS_IS_OK(status)) {
2297 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2298 nt_errstr(status)));
2299 goto close_domain;
2302 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2303 &user_handle, &rids);
2304 if (!NT_STATUS_IS_OK(status)) {
2305 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2306 nt_errstr(status)));
2307 goto close_user;
2310 for (i=0; i<rids->count; i++) {
2312 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2313 &domain_handle,
2314 1, &rids->rids[i].rid,
2315 &names, &type);
2316 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2317 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2318 p += 21;
2319 count++;
2323 *rdata_len = PTR_DIFF(p,*rdata);
2325 SSVAL(*rparam,4,count); /* is this right?? */
2326 SSVAL(*rparam,6,count); /* is this right?? */
2328 ret = True;
2330 close_user:
2331 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2332 close_domain:
2333 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2334 close_sam:
2335 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2337 return ret;
2340 /*******************************************************************
2341 Get all users.
2342 ******************************************************************/
2344 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2345 char *param, int tpscnt,
2346 char *data, int tdscnt,
2347 int mdrcnt,int mprcnt,
2348 char **rdata,char **rparam,
2349 int *rdata_len,int *rparam_len)
2351 int count_sent=0;
2352 int num_users=0;
2353 int errflags=0;
2354 int i, resume_context, cli_buf_size;
2355 uint32_t resume_handle;
2357 struct rpc_pipe_client *samr_pipe;
2358 struct policy_handle samr_handle, domain_handle;
2359 NTSTATUS status;
2361 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2362 char *str2 = skip_string(param,tpscnt,str1);
2363 char *p = skip_string(param,tpscnt,str2);
2364 char *endp = NULL;
2366 if (!str1 || !str2 || !p) {
2367 return False;
2370 if (strcmp(str1,"WrLeh") != 0)
2371 return False;
2372 /* parameters
2373 * W-> resume context (number of users to skip)
2374 * r -> return parameter pointer to receive buffer
2375 * L -> length of receive buffer
2376 * e -> return parameter number of entries
2377 * h -> return parameter total number of users
2380 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2381 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2382 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2383 resume_context, cli_buf_size));
2385 *rparam_len = 8;
2386 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2387 if (!*rparam) {
2388 return False;
2391 /* check it's a supported varient */
2392 if (strcmp("B21",str2) != 0)
2393 return False;
2395 *rdata_len = cli_buf_size;
2396 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2397 if (!*rdata) {
2398 return False;
2401 p = *rdata;
2402 endp = *rdata + *rdata_len;
2404 status = rpc_pipe_open_internal(
2405 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2406 conn->server_info, &samr_pipe);
2407 if (!NT_STATUS_IS_OK(status)) {
2408 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2409 nt_errstr(status)));
2410 return false;
2413 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2414 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2415 if (!NT_STATUS_IS_OK(status)) {
2416 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2417 nt_errstr(status)));
2418 return false;
2421 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2422 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2423 get_global_sam_sid(), &domain_handle);
2424 if (!NT_STATUS_IS_OK(status)) {
2425 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2426 nt_errstr(status)));
2427 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2428 return false;
2431 errflags=NERR_Success;
2433 resume_handle = 0;
2435 while (true) {
2436 struct samr_SamArray *sam_entries;
2437 uint32_t num_entries;
2439 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2440 &domain_handle,
2441 &resume_handle,
2442 0, &sam_entries, 1,
2443 &num_entries);
2445 if (!NT_STATUS_IS_OK(status)) {
2446 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2447 "%s\n", nt_errstr(status)));
2448 break;
2451 if (num_entries == 0) {
2452 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2453 "no entries -- done\n"));
2454 break;
2457 for (i=0; i<num_entries; i++) {
2458 const char *name;
2460 name = sam_entries->entries[i].name.string;
2462 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2463 &&(strlen(name)<=21)) {
2464 strlcpy(p,name,PTR_DIFF(endp,p));
2465 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2466 "username %s\n",count_sent,p));
2467 p += 21;
2468 count_sent++;
2469 } else {
2470 /* set overflow error */
2471 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2472 "username %s\n",count_sent,name));
2473 errflags=234;
2474 break;
2478 if (errflags != NERR_Success) {
2479 break;
2482 TALLOC_FREE(sam_entries);
2485 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2486 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2488 *rdata_len = PTR_DIFF(p,*rdata);
2490 SSVAL(*rparam,0,errflags);
2491 SSVAL(*rparam,2,0); /* converter word */
2492 SSVAL(*rparam,4,count_sent); /* is this right?? */
2493 SSVAL(*rparam,6,num_users); /* is this right?? */
2495 return True;
2498 /****************************************************************************
2499 Get the time of day info.
2500 ****************************************************************************/
2502 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2503 char *param, int tpscnt,
2504 char *data, int tdscnt,
2505 int mdrcnt,int mprcnt,
2506 char **rdata,char **rparam,
2507 int *rdata_len,int *rparam_len)
2509 struct tm *t;
2510 time_t unixdate = time(NULL);
2511 char *p;
2513 *rparam_len = 4;
2514 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2515 if (!*rparam) {
2516 return False;
2519 *rdata_len = 21;
2520 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2521 if (!*rdata) {
2522 return False;
2525 SSVAL(*rparam,0,NERR_Success);
2526 SSVAL(*rparam,2,0); /* converter word */
2528 p = *rdata;
2530 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2531 by NT in a "net time" operation,
2532 it seems to ignore the one below */
2534 /* the client expects to get localtime, not GMT, in this bit
2535 (I think, this needs testing) */
2536 t = localtime(&unixdate);
2537 if (!t) {
2538 return False;
2541 SIVAL(p,4,0); /* msecs ? */
2542 SCVAL(p,8,t->tm_hour);
2543 SCVAL(p,9,t->tm_min);
2544 SCVAL(p,10,t->tm_sec);
2545 SCVAL(p,11,0); /* hundredths of seconds */
2546 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2547 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2548 SCVAL(p,16,t->tm_mday);
2549 SCVAL(p,17,t->tm_mon + 1);
2550 SSVAL(p,18,1900+t->tm_year);
2551 SCVAL(p,20,t->tm_wday);
2553 return True;
2556 /****************************************************************************
2557 Set the user password.
2558 *****************************************************************************/
2560 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2561 char *param, int tpscnt,
2562 char *data, int tdscnt,
2563 int mdrcnt,int mprcnt,
2564 char **rdata,char **rparam,
2565 int *rdata_len,int *rparam_len)
2567 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2568 char *p = NULL;
2569 fstring user;
2570 fstring pass1,pass2;
2572 /* Skip 2 strings. */
2573 p = skip_string(param,tpscnt,np);
2574 p = skip_string(param,tpscnt,p);
2576 if (!np || !p) {
2577 return False;
2580 /* Do we have a string ? */
2581 if (skip_string(param,tpscnt,p) == NULL) {
2582 return False;
2584 pull_ascii_fstring(user,p);
2586 p = skip_string(param,tpscnt,p);
2587 if (!p) {
2588 return False;
2591 memset(pass1,'\0',sizeof(pass1));
2592 memset(pass2,'\0',sizeof(pass2));
2594 * We use 31 here not 32 as we're checking
2595 * the last byte we want to access is safe.
2597 if (!is_offset_safe(param,tpscnt,p,31)) {
2598 return False;
2600 memcpy(pass1,p,16);
2601 memcpy(pass2,p+16,16);
2603 *rparam_len = 4;
2604 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2605 if (!*rparam) {
2606 return False;
2609 *rdata_len = 0;
2611 SSVAL(*rparam,0,NERR_badpass);
2612 SSVAL(*rparam,2,0); /* converter word */
2614 DEBUG(3,("Set password for <%s>\n",user));
2617 * Attempt to verify the old password against smbpasswd entries
2618 * Win98 clients send old and new password in plaintext for this call.
2622 auth_serversupplied_info *server_info = NULL;
2623 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2625 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2627 become_root();
2628 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2629 SSVAL(*rparam,0,NERR_Success);
2631 unbecome_root();
2633 TALLOC_FREE(server_info);
2635 data_blob_clear_free(&password);
2639 * If the plaintext change failed, attempt
2640 * the old encrypted method. NT will generate this
2641 * after trying the samr method. Note that this
2642 * method is done as a last resort as this
2643 * password change method loses the NT password hash
2644 * and cannot change the UNIX password as no plaintext
2645 * is received.
2648 if(SVAL(*rparam,0) != NERR_Success) {
2649 struct samu *hnd = NULL;
2651 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2652 become_root();
2653 if (change_lanman_password(hnd,(uchar *)pass2)) {
2654 SSVAL(*rparam,0,NERR_Success);
2656 unbecome_root();
2657 TALLOC_FREE(hnd);
2661 memset((char *)pass1,'\0',sizeof(fstring));
2662 memset((char *)pass2,'\0',sizeof(fstring));
2664 return(True);
2667 /****************************************************************************
2668 Set the user password (SamOEM version - gets plaintext).
2669 ****************************************************************************/
2671 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2672 char *param, int tpscnt,
2673 char *data, int tdscnt,
2674 int mdrcnt,int mprcnt,
2675 char **rdata,char **rparam,
2676 int *rdata_len,int *rparam_len)
2678 struct smbd_server_connection *sconn = smbd_server_conn;
2679 fstring user;
2680 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2681 *rparam_len = 2;
2682 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2683 if (!*rparam) {
2684 return False;
2687 if (!p) {
2688 return False;
2690 *rdata_len = 0;
2692 SSVAL(*rparam,0,NERR_badpass);
2695 * Check the parameter definition is correct.
2698 /* Do we have a string ? */
2699 if (skip_string(param,tpscnt,p) == 0) {
2700 return False;
2702 if(!strequal(p, "zsT")) {
2703 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2704 return False;
2706 p = skip_string(param, tpscnt, p);
2707 if (!p) {
2708 return False;
2711 /* Do we have a string ? */
2712 if (skip_string(param,tpscnt,p) == 0) {
2713 return False;
2715 if(!strequal(p, "B516B16")) {
2716 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2717 return False;
2719 p = skip_string(param,tpscnt,p);
2720 if (!p) {
2721 return False;
2723 /* Do we have a string ? */
2724 if (skip_string(param,tpscnt,p) == 0) {
2725 return False;
2727 p += pull_ascii_fstring(user,p);
2729 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2732 * Pass the user through the NT -> unix user mapping
2733 * function.
2736 (void)map_username(sconn, user);
2738 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2739 SSVAL(*rparam,0,NERR_Success);
2742 return(True);
2745 /****************************************************************************
2746 delete a print job
2747 Form: <W> <>
2748 ****************************************************************************/
2750 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2751 char *param, int tpscnt,
2752 char *data, int tdscnt,
2753 int mdrcnt,int mprcnt,
2754 char **rdata,char **rparam,
2755 int *rdata_len,int *rparam_len)
2757 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2758 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2759 char *str2 = skip_string(param,tpscnt,str1);
2760 char *p = skip_string(param,tpscnt,str2);
2761 uint32 jobid;
2762 int snum;
2763 fstring sharename;
2764 int errcode;
2765 WERROR werr = WERR_OK;
2767 if (!str1 || !str2 || !p) {
2768 return False;
2771 * We use 1 here not 2 as we're checking
2772 * the last byte we want to access is safe.
2774 if (!is_offset_safe(param,tpscnt,p,1)) {
2775 return False;
2777 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2778 return False;
2780 /* check it's a supported varient */
2781 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2782 return(False);
2784 *rparam_len = 4;
2785 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2786 if (!*rparam) {
2787 return False;
2789 *rdata_len = 0;
2791 if (!print_job_exists(sharename, jobid)) {
2792 errcode = NERR_JobNotFound;
2793 goto out;
2796 snum = lp_servicenumber( sharename);
2797 if (snum == -1) {
2798 errcode = NERR_DestNotFound;
2799 goto out;
2802 errcode = NERR_notsupported;
2804 switch (function) {
2805 case 81: /* delete */
2806 if (print_job_delete(conn->server_info, snum, jobid, &werr))
2807 errcode = NERR_Success;
2808 break;
2809 case 82: /* pause */
2810 if (print_job_pause(conn->server_info, snum, jobid, &werr))
2811 errcode = NERR_Success;
2812 break;
2813 case 83: /* resume */
2814 if (print_job_resume(conn->server_info, snum, jobid, &werr))
2815 errcode = NERR_Success;
2816 break;
2819 if (!W_ERROR_IS_OK(werr))
2820 errcode = W_ERROR_V(werr);
2822 out:
2823 SSVAL(*rparam,0,errcode);
2824 SSVAL(*rparam,2,0); /* converter word */
2826 return(True);
2829 /****************************************************************************
2830 Purge a print queue - or pause or resume it.
2831 ****************************************************************************/
2833 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2834 char *param, int tpscnt,
2835 char *data, int tdscnt,
2836 int mdrcnt,int mprcnt,
2837 char **rdata,char **rparam,
2838 int *rdata_len,int *rparam_len)
2840 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2841 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2842 char *str2 = skip_string(param,tpscnt,str1);
2843 char *QueueName = skip_string(param,tpscnt,str2);
2844 int errcode = NERR_notsupported;
2845 int snum;
2846 WERROR werr = WERR_OK;
2848 if (!str1 || !str2 || !QueueName) {
2849 return False;
2852 /* check it's a supported varient */
2853 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2854 return(False);
2856 *rparam_len = 4;
2857 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2858 if (!*rparam) {
2859 return False;
2861 *rdata_len = 0;
2863 if (skip_string(param,tpscnt,QueueName) == NULL) {
2864 return False;
2866 snum = print_queue_snum(QueueName);
2868 if (snum == -1) {
2869 errcode = NERR_JobNotFound;
2870 goto out;
2873 switch (function) {
2874 case 74: /* Pause queue */
2875 werr = print_queue_pause(conn->server_info, snum);
2876 break;
2877 case 75: /* Resume queue */
2878 werr = print_queue_resume(conn->server_info, snum);
2879 break;
2880 case 103: /* Purge */
2881 werr = print_queue_purge(conn->server_info, snum);
2882 break;
2883 default:
2884 werr = WERR_NOT_SUPPORTED;
2885 break;
2888 errcode = W_ERROR_V(werr);
2890 out:
2891 SSVAL(*rparam,0,errcode);
2892 SSVAL(*rparam,2,0); /* converter word */
2894 return(True);
2897 /****************************************************************************
2898 set the property of a print job (undocumented?)
2899 ? function = 0xb -> set name of print job
2900 ? function = 0x6 -> move print job up/down
2901 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2902 or <WWsTP> <WB21BB16B10zWWzDDz>
2903 ****************************************************************************/
2905 static int check_printjob_info(struct pack_desc* desc,
2906 int uLevel, char* id)
2908 desc->subformat = NULL;
2909 switch( uLevel ) {
2910 case 0: desc->format = "W"; break;
2911 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2912 case 2: desc->format = "WWzWWDDzz"; break;
2913 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2914 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2915 default:
2916 DEBUG(0,("check_printjob_info: invalid level %d\n",
2917 uLevel ));
2918 return False;
2920 if (id == NULL || strcmp(desc->format,id) != 0) {
2921 DEBUG(0,("check_printjob_info: invalid format %s\n",
2922 id ? id : "<NULL>" ));
2923 return False;
2925 return True;
2928 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2929 char *param, int tpscnt,
2930 char *data, int tdscnt,
2931 int mdrcnt,int mprcnt,
2932 char **rdata,char **rparam,
2933 int *rdata_len,int *rparam_len)
2935 struct pack_desc desc;
2936 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2937 char *str2 = skip_string(param,tpscnt,str1);
2938 char *p = skip_string(param,tpscnt,str2);
2939 uint32 jobid;
2940 fstring sharename;
2941 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2942 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2943 int place, errcode;
2945 if (!str1 || !str2 || !p) {
2946 return False;
2949 * We use 1 here not 2 as we're checking
2950 * the last byte we want to access is safe.
2952 if (!is_offset_safe(param,tpscnt,p,1)) {
2953 return False;
2955 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2956 return False;
2957 *rparam_len = 4;
2958 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2959 if (!*rparam) {
2960 return False;
2963 if (!share_defined(sharename)) {
2964 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2965 sharename));
2966 return False;
2969 *rdata_len = 0;
2971 /* check it's a supported varient */
2972 if ((strcmp(str1,"WWsTP")) ||
2973 (!check_printjob_info(&desc,uLevel,str2)))
2974 return(False);
2976 if (!print_job_exists(sharename, jobid)) {
2977 errcode=NERR_JobNotFound;
2978 goto out;
2981 errcode = NERR_notsupported;
2983 switch (function) {
2984 case 0x6:
2985 /* change job place in the queue,
2986 data gives the new place */
2987 place = SVAL(data,0);
2988 if (print_job_set_place(sharename, jobid, place)) {
2989 errcode=NERR_Success;
2991 break;
2993 case 0xb:
2994 /* change print job name, data gives the name */
2995 if (print_job_set_name(sharename, jobid, data)) {
2996 errcode=NERR_Success;
2998 break;
3000 default:
3001 return False;
3004 out:
3005 SSVALS(*rparam,0,errcode);
3006 SSVAL(*rparam,2,0); /* converter word */
3008 return(True);
3012 /****************************************************************************
3013 Get info about the server.
3014 ****************************************************************************/
3016 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3017 char *param, int tpscnt,
3018 char *data, int tdscnt,
3019 int mdrcnt,int mprcnt,
3020 char **rdata,char **rparam,
3021 int *rdata_len,int *rparam_len)
3023 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3024 char *str2 = skip_string(param,tpscnt,str1);
3025 char *p = skip_string(param,tpscnt,str2);
3026 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3027 char *p2;
3028 int struct_len;
3030 if (!str1 || !str2 || !p) {
3031 return False;
3034 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3036 /* check it's a supported varient */
3037 if (!prefix_ok(str1,"WrLh")) {
3038 return False;
3041 switch( uLevel ) {
3042 case 0:
3043 if (strcmp(str2,"B16") != 0) {
3044 return False;
3046 struct_len = 16;
3047 break;
3048 case 1:
3049 if (strcmp(str2,"B16BBDz") != 0) {
3050 return False;
3052 struct_len = 26;
3053 break;
3054 case 2:
3055 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3056 return False;
3058 struct_len = 134;
3059 break;
3060 case 3:
3061 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3062 return False;
3064 struct_len = 144;
3065 break;
3066 case 20:
3067 if (strcmp(str2,"DN") != 0) {
3068 return False;
3070 struct_len = 6;
3071 break;
3072 case 50:
3073 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3074 return False;
3076 struct_len = 42;
3077 break;
3078 default:
3079 return False;
3082 *rdata_len = mdrcnt;
3083 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3084 if (!*rdata) {
3085 return False;
3088 p = *rdata;
3089 p2 = p + struct_len;
3090 if (uLevel != 20) {
3091 srvstr_push(NULL, 0, p,global_myname(),16,
3092 STR_ASCII|STR_UPPER|STR_TERMINATE);
3094 p += 16;
3095 if (uLevel > 0) {
3096 struct srv_info_struct *servers=NULL;
3097 int i,count;
3098 char *comment = NULL;
3099 TALLOC_CTX *ctx = talloc_tos();
3100 uint32 servertype= lp_default_server_announce();
3102 comment = talloc_strdup(ctx,lp_serverstring());
3103 if (!comment) {
3104 return false;
3107 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3108 for (i=0;i<count;i++) {
3109 if (strequal(servers[i].name,global_myname())) {
3110 servertype = servers[i].type;
3111 TALLOC_FREE(comment);
3112 comment = talloc_strdup(ctx,
3113 servers[i].comment);
3114 if (comment) {
3115 return false;
3121 SAFE_FREE(servers);
3123 SCVAL(p,0,lp_major_announce_version());
3124 SCVAL(p,1,lp_minor_announce_version());
3125 SIVAL(p,2,servertype);
3127 if (mdrcnt == struct_len) {
3128 SIVAL(p,6,0);
3129 } else {
3130 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3131 comment = talloc_sub_advanced(
3132 ctx,
3133 lp_servicename(SNUM(conn)),
3134 conn->server_info->unix_name,
3135 conn->connectpath,
3136 conn->server_info->utok.gid,
3137 conn->server_info->sanitized_username,
3138 pdb_get_domain(conn->server_info->sam_account),
3139 comment);
3140 if (comment) {
3141 return false;
3143 if (mdrcnt - struct_len <= 0) {
3144 return false;
3146 push_ascii(p2,
3147 comment,
3148 MIN(mdrcnt - struct_len,
3149 MAX_SERVER_STRING_LENGTH),
3150 STR_TERMINATE);
3151 p2 = skip_string(*rdata,*rdata_len,p2);
3152 if (!p2) {
3153 return False;
3158 if (uLevel > 1) {
3159 return False; /* not yet implemented */
3162 *rdata_len = PTR_DIFF(p2,*rdata);
3164 *rparam_len = 6;
3165 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3166 if (!*rparam) {
3167 return False;
3169 SSVAL(*rparam,0,NERR_Success);
3170 SSVAL(*rparam,2,0); /* converter word */
3171 SSVAL(*rparam,4,*rdata_len);
3173 return True;
3176 /****************************************************************************
3177 Get info about the server.
3178 ****************************************************************************/
3180 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3181 char *param, int tpscnt,
3182 char *data, int tdscnt,
3183 int mdrcnt,int mprcnt,
3184 char **rdata,char **rparam,
3185 int *rdata_len,int *rparam_len)
3187 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3188 char *str2 = skip_string(param,tpscnt,str1);
3189 char *p = skip_string(param,tpscnt,str2);
3190 char *p2;
3191 char *endp;
3192 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3194 if (!str1 || !str2 || !p) {
3195 return False;
3198 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3200 *rparam_len = 6;
3201 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3202 if (!*rparam) {
3203 return False;
3206 /* check it's a supported varient */
3207 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3208 return False;
3211 *rdata_len = mdrcnt + 1024;
3212 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3213 if (!*rdata) {
3214 return False;
3217 SSVAL(*rparam,0,NERR_Success);
3218 SSVAL(*rparam,2,0); /* converter word */
3220 p = *rdata;
3221 endp = *rdata + *rdata_len;
3223 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3224 if (!p2) {
3225 return False;
3228 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3229 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3230 strupper_m(p2);
3231 p2 = skip_string(*rdata,*rdata_len,p2);
3232 if (!p2) {
3233 return False;
3235 p += 4;
3237 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3238 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3239 p2 = skip_string(*rdata,*rdata_len,p2);
3240 if (!p2) {
3241 return False;
3243 p += 4;
3245 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3246 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3247 strupper_m(p2);
3248 p2 = skip_string(*rdata,*rdata_len,p2);
3249 if (!p2) {
3250 return False;
3252 p += 4;
3254 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3255 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3256 p += 2;
3258 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3259 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3260 p2 = skip_string(*rdata,*rdata_len,p2);
3261 if (!p2) {
3262 return False;
3264 p += 4;
3266 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3267 strlcpy(p2,"",PTR_DIFF(endp,p2));
3268 p2 = skip_string(*rdata,*rdata_len,p2);
3269 if (!p2) {
3270 return False;
3272 p += 4;
3274 *rdata_len = PTR_DIFF(p2,*rdata);
3276 SSVAL(*rparam,4,*rdata_len);
3278 return True;
3281 /****************************************************************************
3282 get info about a user
3284 struct user_info_11 {
3285 char usri11_name[21]; 0-20
3286 char usri11_pad; 21
3287 char *usri11_comment; 22-25
3288 char *usri11_usr_comment; 26-29
3289 unsigned short usri11_priv; 30-31
3290 unsigned long usri11_auth_flags; 32-35
3291 long usri11_password_age; 36-39
3292 char *usri11_homedir; 40-43
3293 char *usri11_parms; 44-47
3294 long usri11_last_logon; 48-51
3295 long usri11_last_logoff; 52-55
3296 unsigned short usri11_bad_pw_count; 56-57
3297 unsigned short usri11_num_logons; 58-59
3298 char *usri11_logon_server; 60-63
3299 unsigned short usri11_country_code; 64-65
3300 char *usri11_workstations; 66-69
3301 unsigned long usri11_max_storage; 70-73
3302 unsigned short usri11_units_per_week; 74-75
3303 unsigned char *usri11_logon_hours; 76-79
3304 unsigned short usri11_code_page; 80-81
3307 where:
3309 usri11_name specifies the user name for which information is retrieved
3311 usri11_pad aligns the next data structure element to a word boundary
3313 usri11_comment is a null terminated ASCII comment
3315 usri11_user_comment is a null terminated ASCII comment about the user
3317 usri11_priv specifies the level of the privilege assigned to the user.
3318 The possible values are:
3320 Name Value Description
3321 USER_PRIV_GUEST 0 Guest privilege
3322 USER_PRIV_USER 1 User privilege
3323 USER_PRV_ADMIN 2 Administrator privilege
3325 usri11_auth_flags specifies the account operator privileges. The
3326 possible values are:
3328 Name Value Description
3329 AF_OP_PRINT 0 Print operator
3332 Leach, Naik [Page 28]
3336 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3339 AF_OP_COMM 1 Communications operator
3340 AF_OP_SERVER 2 Server operator
3341 AF_OP_ACCOUNTS 3 Accounts operator
3344 usri11_password_age specifies how many seconds have elapsed since the
3345 password was last changed.
3347 usri11_home_dir points to a null terminated ASCII string that contains
3348 the path name of the user's home directory.
3350 usri11_parms points to a null terminated ASCII string that is set
3351 aside for use by applications.
3353 usri11_last_logon specifies the time when the user last logged on.
3354 This value is stored as the number of seconds elapsed since
3355 00:00:00, January 1, 1970.
3357 usri11_last_logoff specifies the time when the user last logged off.
3358 This value is stored as the number of seconds elapsed since
3359 00:00:00, January 1, 1970. A value of 0 means the last logoff
3360 time is unknown.
3362 usri11_bad_pw_count specifies the number of incorrect passwords
3363 entered since the last successful logon.
3365 usri11_log1_num_logons specifies the number of times this user has
3366 logged on. A value of -1 means the number of logons is unknown.
3368 usri11_logon_server points to a null terminated ASCII string that
3369 contains the name of the server to which logon requests are sent.
3370 A null string indicates logon requests should be sent to the
3371 domain controller.
3373 usri11_country_code specifies the country code for the user's language
3374 of choice.
3376 usri11_workstations points to a null terminated ASCII string that
3377 contains the names of workstations the user may log on from.
3378 There may be up to 8 workstations, with the names separated by
3379 commas. A null strings indicates there are no restrictions.
3381 usri11_max_storage specifies the maximum amount of disk space the user
3382 can occupy. A value of 0xffffffff indicates there are no
3383 restrictions.
3385 usri11_units_per_week specifies the equal number of time units into
3386 which a week is divided. This value must be equal to 168.
3388 usri11_logon_hours points to a 21 byte (168 bits) string that
3389 specifies the time during which the user can log on. Each bit
3390 represents one unique hour in a week. The first bit (bit 0, word
3391 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3395 Leach, Naik [Page 29]
3399 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3402 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3403 are no restrictions.
3405 usri11_code_page specifies the code page for the user's language of
3406 choice
3408 All of the pointers in this data structure need to be treated
3409 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3410 to be ignored. The converter word returned in the parameters section
3411 needs to be subtracted from the lower 16 bits to calculate an offset
3412 into the return buffer where this ASCII string resides.
3414 There is no auxiliary data in the response.
3416 ****************************************************************************/
3418 #define usri11_name 0
3419 #define usri11_pad 21
3420 #define usri11_comment 22
3421 #define usri11_usr_comment 26
3422 #define usri11_full_name 30
3423 #define usri11_priv 34
3424 #define usri11_auth_flags 36
3425 #define usri11_password_age 40
3426 #define usri11_homedir 44
3427 #define usri11_parms 48
3428 #define usri11_last_logon 52
3429 #define usri11_last_logoff 56
3430 #define usri11_bad_pw_count 60
3431 #define usri11_num_logons 62
3432 #define usri11_logon_server 64
3433 #define usri11_country_code 68
3434 #define usri11_workstations 70
3435 #define usri11_max_storage 74
3436 #define usri11_units_per_week 78
3437 #define usri11_logon_hours 80
3438 #define usri11_code_page 84
3439 #define usri11_end 86
3441 #define USER_PRIV_GUEST 0
3442 #define USER_PRIV_USER 1
3443 #define USER_PRIV_ADMIN 2
3445 #define AF_OP_PRINT 0
3446 #define AF_OP_COMM 1
3447 #define AF_OP_SERVER 2
3448 #define AF_OP_ACCOUNTS 3
3451 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3452 char *param, int tpscnt,
3453 char *data, int tdscnt,
3454 int mdrcnt,int mprcnt,
3455 char **rdata,char **rparam,
3456 int *rdata_len,int *rparam_len)
3458 struct smbd_server_connection *sconn = smbd_server_conn;
3459 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3460 char *str2 = skip_string(param,tpscnt,str1);
3461 char *UserName = skip_string(param,tpscnt,str2);
3462 char *p = skip_string(param,tpscnt,UserName);
3463 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3464 char *p2;
3465 char *endp;
3466 const char *level_string;
3468 /* get NIS home of a previously validated user - simeon */
3469 /* With share level security vuid will always be zero.
3470 Don't depend on vuser being non-null !!. JRA */
3471 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3472 if(vuser != NULL) {
3473 DEBUG(3,(" Username of UID %d is %s\n",
3474 (int)vuser->server_info->utok.uid,
3475 vuser->server_info->unix_name));
3478 if (!str1 || !str2 || !UserName || !p) {
3479 return False;
3482 *rparam_len = 6;
3483 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3484 if (!*rparam) {
3485 return False;
3488 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3490 /* check it's a supported variant */
3491 if (strcmp(str1,"zWrLh") != 0) {
3492 return False;
3494 switch( uLevel ) {
3495 case 0: level_string = "B21"; break;
3496 case 1: level_string = "B21BB16DWzzWz"; break;
3497 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3498 case 10: level_string = "B21Bzzz"; break;
3499 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3500 default: return False;
3503 if (strcmp(level_string,str2) != 0) {
3504 return False;
3507 *rdata_len = mdrcnt + 1024;
3508 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3509 if (!*rdata) {
3510 return False;
3513 SSVAL(*rparam,0,NERR_Success);
3514 SSVAL(*rparam,2,0); /* converter word */
3516 p = *rdata;
3517 endp = *rdata + *rdata_len;
3518 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3519 if (!p2) {
3520 return False;
3523 memset(p,0,21);
3524 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3526 if (uLevel > 0) {
3527 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3528 *p2 = 0;
3531 if (uLevel >= 10) {
3532 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3533 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3534 p2 = skip_string(*rdata,*rdata_len,p2);
3535 if (!p2) {
3536 return False;
3539 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3540 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3541 p2 = skip_string(*rdata,*rdata_len,p2);
3542 if (!p2) {
3543 return False;
3546 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3547 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3548 strlcpy(p2,((vuser != NULL)
3549 ? pdb_get_fullname(vuser->server_info->sam_account)
3550 : UserName),PTR_DIFF(endp,p2));
3551 p2 = skip_string(*rdata,*rdata_len,p2);
3552 if (!p2) {
3553 return False;
3557 if (uLevel == 11) {
3558 const char *homedir = "";
3559 if (vuser != NULL) {
3560 homedir = pdb_get_homedir(
3561 vuser->server_info->sam_account);
3563 /* modelled after NTAS 3.51 reply */
3564 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3565 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3566 SIVALS(p,usri11_password_age,-1); /* password age */
3567 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3568 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3569 p2 = skip_string(*rdata,*rdata_len,p2);
3570 if (!p2) {
3571 return False;
3573 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3574 strlcpy(p2,"",PTR_DIFF(endp,p2));
3575 p2 = skip_string(*rdata,*rdata_len,p2);
3576 if (!p2) {
3577 return False;
3579 SIVAL(p,usri11_last_logon,0); /* last logon */
3580 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3581 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3582 SSVALS(p,usri11_num_logons,-1); /* num logons */
3583 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3584 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3585 p2 = skip_string(*rdata,*rdata_len,p2);
3586 if (!p2) {
3587 return False;
3589 SSVAL(p,usri11_country_code,0); /* country code */
3591 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3592 strlcpy(p2,"",PTR_DIFF(endp,p2));
3593 p2 = skip_string(*rdata,*rdata_len,p2);
3594 if (!p2) {
3595 return False;
3598 SIVALS(p,usri11_max_storage,-1); /* max storage */
3599 SSVAL(p,usri11_units_per_week,168); /* units per week */
3600 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3602 /* a simple way to get logon hours at all times. */
3603 memset(p2,0xff,21);
3604 SCVAL(p2,21,0); /* fix zero termination */
3605 p2 = skip_string(*rdata,*rdata_len,p2);
3606 if (!p2) {
3607 return False;
3610 SSVAL(p,usri11_code_page,0); /* code page */
3613 if (uLevel == 1 || uLevel == 2) {
3614 memset(p+22,' ',16); /* password */
3615 SIVALS(p,38,-1); /* password age */
3616 SSVAL(p,42,
3617 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3618 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3619 strlcpy(p2, vuser ? pdb_get_homedir(
3620 vuser->server_info->sam_account) : "",
3621 PTR_DIFF(endp,p2));
3622 p2 = skip_string(*rdata,*rdata_len,p2);
3623 if (!p2) {
3624 return False;
3626 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3627 *p2++ = 0;
3628 SSVAL(p,52,0); /* flags */
3629 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3630 strlcpy(p2, vuser ? pdb_get_logon_script(
3631 vuser->server_info->sam_account) : "",
3632 PTR_DIFF(endp,p2));
3633 p2 = skip_string(*rdata,*rdata_len,p2);
3634 if (!p2) {
3635 return False;
3637 if (uLevel == 2) {
3638 SIVAL(p,60,0); /* auth_flags */
3639 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3640 strlcpy(p2,((vuser != NULL)
3641 ? pdb_get_fullname(vuser->server_info->sam_account)
3642 : UserName),PTR_DIFF(endp,p2));
3643 p2 = skip_string(*rdata,*rdata_len,p2);
3644 if (!p2) {
3645 return False;
3647 SIVAL(p,68,0); /* urs_comment */
3648 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3649 strlcpy(p2,"",PTR_DIFF(endp,p2));
3650 p2 = skip_string(*rdata,*rdata_len,p2);
3651 if (!p2) {
3652 return False;
3654 SIVAL(p,76,0); /* workstations */
3655 SIVAL(p,80,0); /* last_logon */
3656 SIVAL(p,84,0); /* last_logoff */
3657 SIVALS(p,88,-1); /* acct_expires */
3658 SIVALS(p,92,-1); /* max_storage */
3659 SSVAL(p,96,168); /* units_per_week */
3660 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3661 memset(p2,-1,21);
3662 p2 += 21;
3663 SSVALS(p,102,-1); /* bad_pw_count */
3664 SSVALS(p,104,-1); /* num_logons */
3665 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3667 TALLOC_CTX *ctx = talloc_tos();
3668 int space_rem = *rdata_len - (p2 - *rdata);
3669 char *tmp;
3671 if (space_rem <= 0) {
3672 return false;
3674 tmp = talloc_strdup(ctx, "\\\\%L");
3675 if (!tmp) {
3676 return false;
3678 tmp = talloc_sub_basic(ctx,
3681 tmp);
3682 if (!tmp) {
3683 return false;
3686 push_ascii(p2,
3687 tmp,
3688 space_rem,
3689 STR_TERMINATE);
3691 p2 = skip_string(*rdata,*rdata_len,p2);
3692 if (!p2) {
3693 return False;
3695 SSVAL(p,110,49); /* country_code */
3696 SSVAL(p,112,860); /* code page */
3700 *rdata_len = PTR_DIFF(p2,*rdata);
3702 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3704 return(True);
3707 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3708 char *param, int tpscnt,
3709 char *data, int tdscnt,
3710 int mdrcnt,int mprcnt,
3711 char **rdata,char **rparam,
3712 int *rdata_len,int *rparam_len)
3714 struct smbd_server_connection *sconn = smbd_server_conn;
3715 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3716 char *str2 = skip_string(param,tpscnt,str1);
3717 char *p = skip_string(param,tpscnt,str2);
3718 int uLevel;
3719 struct pack_desc desc;
3720 char* name;
3721 /* With share level security vuid will always be zero.
3722 Don't depend on vuser being non-null !!. JRA */
3723 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3725 if (!str1 || !str2 || !p) {
3726 return False;
3729 if(vuser != NULL) {
3730 DEBUG(3,(" Username of UID %d is %s\n",
3731 (int)vuser->server_info->utok.uid,
3732 vuser->server_info->unix_name));
3735 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3736 name = get_safe_str_ptr(param,tpscnt,p,2);
3737 if (!name) {
3738 return False;
3741 memset((char *)&desc,'\0',sizeof(desc));
3743 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3745 /* check it's a supported varient */
3746 if (strcmp(str1,"OOWb54WrLh") != 0) {
3747 return False;
3749 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3750 return False;
3752 if (mdrcnt > 0) {
3753 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3754 if (!*rdata) {
3755 return False;
3759 desc.base = *rdata;
3760 desc.buflen = mdrcnt;
3761 desc.subformat = NULL;
3762 desc.format = str2;
3764 if (init_package(&desc,1,0)) {
3765 PACKI(&desc,"W",0); /* code */
3766 PACKS(&desc,"B21",name); /* eff. name */
3767 PACKS(&desc,"B",""); /* pad */
3768 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3769 PACKI(&desc,"D",0); /* auth flags XXX */
3770 PACKI(&desc,"W",0); /* num logons */
3771 PACKI(&desc,"W",0); /* bad pw count */
3772 PACKI(&desc,"D",0); /* last logon */
3773 PACKI(&desc,"D",-1); /* last logoff */
3774 PACKI(&desc,"D",-1); /* logoff time */
3775 PACKI(&desc,"D",-1); /* kickoff time */
3776 PACKI(&desc,"D",0); /* password age */
3777 PACKI(&desc,"D",0); /* password can change */
3778 PACKI(&desc,"D",-1); /* password must change */
3781 fstring mypath;
3782 fstrcpy(mypath,"\\\\");
3783 fstrcat(mypath,get_local_machine_name());
3784 strupper_m(mypath);
3785 PACKS(&desc,"z",mypath); /* computer */
3788 PACKS(&desc,"z",lp_workgroup());/* domain */
3789 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3790 vuser->server_info->sam_account) : ""); /* script path */
3791 PACKI(&desc,"D",0x00000000); /* reserved */
3794 *rdata_len = desc.usedlen;
3795 *rparam_len = 6;
3796 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3797 if (!*rparam) {
3798 return False;
3800 SSVALS(*rparam,0,desc.errcode);
3801 SSVAL(*rparam,2,0);
3802 SSVAL(*rparam,4,desc.neededlen);
3804 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3806 return True;
3809 /****************************************************************************
3810 api_WAccessGetUserPerms
3811 ****************************************************************************/
3813 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3814 char *param, int tpscnt,
3815 char *data, int tdscnt,
3816 int mdrcnt,int mprcnt,
3817 char **rdata,char **rparam,
3818 int *rdata_len,int *rparam_len)
3820 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3821 char *str2 = skip_string(param,tpscnt,str1);
3822 char *user = skip_string(param,tpscnt,str2);
3823 char *resource = skip_string(param,tpscnt,user);
3825 if (!str1 || !str2 || !user || !resource) {
3826 return False;
3829 if (skip_string(param,tpscnt,resource) == NULL) {
3830 return False;
3832 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3834 /* check it's a supported varient */
3835 if (strcmp(str1,"zzh") != 0) {
3836 return False;
3838 if (strcmp(str2,"") != 0) {
3839 return False;
3842 *rparam_len = 6;
3843 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3844 if (!*rparam) {
3845 return False;
3847 SSVALS(*rparam,0,0); /* errorcode */
3848 SSVAL(*rparam,2,0); /* converter word */
3849 SSVAL(*rparam,4,0x7f); /* permission flags */
3851 return True;
3854 /****************************************************************************
3855 api_WPrintJobEnumerate
3856 ****************************************************************************/
3858 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3859 char *param, int tpscnt,
3860 char *data, int tdscnt,
3861 int mdrcnt,int mprcnt,
3862 char **rdata,char **rparam,
3863 int *rdata_len,int *rparam_len)
3865 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3866 char *str2 = skip_string(param,tpscnt,str1);
3867 char *p = skip_string(param,tpscnt,str2);
3868 int uLevel;
3869 int count;
3870 int i;
3871 int snum;
3872 fstring sharename;
3873 uint32 jobid;
3874 struct pack_desc desc;
3875 print_queue_struct *queue=NULL;
3876 print_status_struct status;
3877 char *tmpdata=NULL;
3879 if (!str1 || !str2 || !p) {
3880 return False;
3883 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3885 memset((char *)&desc,'\0',sizeof(desc));
3886 memset((char *)&status,'\0',sizeof(status));
3888 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3890 /* check it's a supported varient */
3891 if (strcmp(str1,"WWrLh") != 0) {
3892 return False;
3894 if (!check_printjob_info(&desc,uLevel,str2)) {
3895 return False;
3898 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3899 return False;
3902 snum = lp_servicenumber( sharename);
3903 if (snum < 0 || !VALID_SNUM(snum)) {
3904 return(False);
3907 count = print_queue_status(snum,&queue,&status);
3908 for (i = 0; i < count; i++) {
3909 if (queue[i].job == jobid) {
3910 break;
3914 if (mdrcnt > 0) {
3915 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3916 if (!*rdata) {
3917 return False;
3919 desc.base = *rdata;
3920 desc.buflen = mdrcnt;
3921 } else {
3923 * Don't return data but need to get correct length
3924 * init_package will return wrong size if buflen=0
3926 desc.buflen = getlen(desc.format);
3927 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3930 if (init_package(&desc,1,0)) {
3931 if (i < count) {
3932 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3933 *rdata_len = desc.usedlen;
3934 } else {
3935 desc.errcode = NERR_JobNotFound;
3936 *rdata_len = 0;
3940 *rparam_len = 6;
3941 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3942 if (!*rparam) {
3943 return False;
3945 SSVALS(*rparam,0,desc.errcode);
3946 SSVAL(*rparam,2,0);
3947 SSVAL(*rparam,4,desc.neededlen);
3949 SAFE_FREE(queue);
3950 SAFE_FREE(tmpdata);
3952 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3954 return True;
3957 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3958 char *param, int tpscnt,
3959 char *data, int tdscnt,
3960 int mdrcnt,int mprcnt,
3961 char **rdata,char **rparam,
3962 int *rdata_len,int *rparam_len)
3964 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3965 char *str2 = skip_string(param,tpscnt,str1);
3966 char *p = skip_string(param,tpscnt,str2);
3967 char *name = p;
3968 int uLevel;
3969 int count;
3970 int i, succnt=0;
3971 int snum;
3972 struct pack_desc desc;
3973 print_queue_struct *queue=NULL;
3974 print_status_struct status;
3976 if (!str1 || !str2 || !p) {
3977 return False;
3980 memset((char *)&desc,'\0',sizeof(desc));
3981 memset((char *)&status,'\0',sizeof(status));
3983 p = skip_string(param,tpscnt,p);
3984 if (!p) {
3985 return False;
3987 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3989 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3991 /* check it's a supported variant */
3992 if (strcmp(str1,"zWrLeh") != 0) {
3993 return False;
3996 if (uLevel > 2) {
3997 return False; /* defined only for uLevel 0,1,2 */
4000 if (!check_printjob_info(&desc,uLevel,str2)) {
4001 return False;
4004 snum = find_service(name);
4005 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4006 return False;
4009 count = print_queue_status(snum,&queue,&status);
4010 if (mdrcnt > 0) {
4011 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4012 if (!*rdata) {
4013 return False;
4016 desc.base = *rdata;
4017 desc.buflen = mdrcnt;
4019 if (init_package(&desc,count,0)) {
4020 succnt = 0;
4021 for (i = 0; i < count; i++) {
4022 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4023 if (desc.errcode == NERR_Success) {
4024 succnt = i+1;
4029 *rdata_len = desc.usedlen;
4031 *rparam_len = 8;
4032 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4033 if (!*rparam) {
4034 return False;
4036 SSVALS(*rparam,0,desc.errcode);
4037 SSVAL(*rparam,2,0);
4038 SSVAL(*rparam,4,succnt);
4039 SSVAL(*rparam,6,count);
4041 SAFE_FREE(queue);
4043 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4045 return True;
4048 static int check_printdest_info(struct pack_desc* desc,
4049 int uLevel, char* id)
4051 desc->subformat = NULL;
4052 switch( uLevel ) {
4053 case 0:
4054 desc->format = "B9";
4055 break;
4056 case 1:
4057 desc->format = "B9B21WWzW";
4058 break;
4059 case 2:
4060 desc->format = "z";
4061 break;
4062 case 3:
4063 desc->format = "zzzWWzzzWW";
4064 break;
4065 default:
4066 DEBUG(0,("check_printdest_info: invalid level %d\n",
4067 uLevel));
4068 return False;
4070 if (id == NULL || strcmp(desc->format,id) != 0) {
4071 DEBUG(0,("check_printdest_info: invalid string %s\n",
4072 id ? id : "<NULL>" ));
4073 return False;
4075 return True;
4078 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4079 struct pack_desc* desc)
4081 char buf[100];
4083 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4084 buf[sizeof(buf)-1] = 0;
4085 strupper_m(buf);
4087 if (uLevel <= 1) {
4088 PACKS(desc,"B9",buf); /* szName */
4089 if (uLevel == 1) {
4090 PACKS(desc,"B21",""); /* szUserName */
4091 PACKI(desc,"W",0); /* uJobId */
4092 PACKI(desc,"W",0); /* fsStatus */
4093 PACKS(desc,"z",""); /* pszStatus */
4094 PACKI(desc,"W",0); /* time */
4098 if (uLevel == 2 || uLevel == 3) {
4099 PACKS(desc,"z",buf); /* pszPrinterName */
4100 if (uLevel == 3) {
4101 PACKS(desc,"z",""); /* pszUserName */
4102 PACKS(desc,"z",""); /* pszLogAddr */
4103 PACKI(desc,"W",0); /* uJobId */
4104 PACKI(desc,"W",0); /* fsStatus */
4105 PACKS(desc,"z",""); /* pszStatus */
4106 PACKS(desc,"z",""); /* pszComment */
4107 PACKS(desc,"z","NULL"); /* pszDrivers */
4108 PACKI(desc,"W",0); /* time */
4109 PACKI(desc,"W",0); /* pad1 */
4114 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4115 char *param, int tpscnt,
4116 char *data, int tdscnt,
4117 int mdrcnt,int mprcnt,
4118 char **rdata,char **rparam,
4119 int *rdata_len,int *rparam_len)
4121 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4122 char *str2 = skip_string(param,tpscnt,str1);
4123 char *p = skip_string(param,tpscnt,str2);
4124 char* PrinterName = p;
4125 int uLevel;
4126 struct pack_desc desc;
4127 int snum;
4128 char *tmpdata=NULL;
4130 if (!str1 || !str2 || !p) {
4131 return False;
4134 memset((char *)&desc,'\0',sizeof(desc));
4136 p = skip_string(param,tpscnt,p);
4137 if (!p) {
4138 return False;
4140 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4142 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4144 /* check it's a supported varient */
4145 if (strcmp(str1,"zWrLh") != 0) {
4146 return False;
4148 if (!check_printdest_info(&desc,uLevel,str2)) {
4149 return False;
4152 snum = find_service(PrinterName);
4153 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4154 *rdata_len = 0;
4155 desc.errcode = NERR_DestNotFound;
4156 desc.neededlen = 0;
4157 } else {
4158 if (mdrcnt > 0) {
4159 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4160 if (!*rdata) {
4161 return False;
4163 desc.base = *rdata;
4164 desc.buflen = mdrcnt;
4165 } else {
4167 * Don't return data but need to get correct length
4168 * init_package will return wrong size if buflen=0
4170 desc.buflen = getlen(desc.format);
4171 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4173 if (init_package(&desc,1,0)) {
4174 fill_printdest_info(conn,snum,uLevel,&desc);
4176 *rdata_len = desc.usedlen;
4179 *rparam_len = 6;
4180 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4181 if (!*rparam) {
4182 return False;
4184 SSVALS(*rparam,0,desc.errcode);
4185 SSVAL(*rparam,2,0);
4186 SSVAL(*rparam,4,desc.neededlen);
4188 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4189 SAFE_FREE(tmpdata);
4191 return True;
4194 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4195 char *param, int tpscnt,
4196 char *data, int tdscnt,
4197 int mdrcnt,int mprcnt,
4198 char **rdata,char **rparam,
4199 int *rdata_len,int *rparam_len)
4201 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4202 char *str2 = skip_string(param,tpscnt,str1);
4203 char *p = skip_string(param,tpscnt,str2);
4204 int uLevel;
4205 int queuecnt;
4206 int i, n, succnt=0;
4207 struct pack_desc desc;
4208 int services = lp_numservices();
4210 if (!str1 || !str2 || !p) {
4211 return False;
4214 memset((char *)&desc,'\0',sizeof(desc));
4216 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4218 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4220 /* check it's a supported varient */
4221 if (strcmp(str1,"WrLeh") != 0) {
4222 return False;
4224 if (!check_printdest_info(&desc,uLevel,str2)) {
4225 return False;
4228 queuecnt = 0;
4229 for (i = 0; i < services; i++) {
4230 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4231 queuecnt++;
4235 if (mdrcnt > 0) {
4236 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4237 if (!*rdata) {
4238 return False;
4242 desc.base = *rdata;
4243 desc.buflen = mdrcnt;
4244 if (init_package(&desc,queuecnt,0)) {
4245 succnt = 0;
4246 n = 0;
4247 for (i = 0; i < services; i++) {
4248 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4249 fill_printdest_info(conn,i,uLevel,&desc);
4250 n++;
4251 if (desc.errcode == NERR_Success) {
4252 succnt = n;
4258 *rdata_len = desc.usedlen;
4260 *rparam_len = 8;
4261 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4262 if (!*rparam) {
4263 return False;
4265 SSVALS(*rparam,0,desc.errcode);
4266 SSVAL(*rparam,2,0);
4267 SSVAL(*rparam,4,succnt);
4268 SSVAL(*rparam,6,queuecnt);
4270 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4272 return True;
4275 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4276 char *param, int tpscnt,
4277 char *data, int tdscnt,
4278 int mdrcnt,int mprcnt,
4279 char **rdata,char **rparam,
4280 int *rdata_len,int *rparam_len)
4282 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4283 char *str2 = skip_string(param,tpscnt,str1);
4284 char *p = skip_string(param,tpscnt,str2);
4285 int uLevel;
4286 int succnt;
4287 struct pack_desc desc;
4289 if (!str1 || !str2 || !p) {
4290 return False;
4293 memset((char *)&desc,'\0',sizeof(desc));
4295 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4297 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4299 /* check it's a supported varient */
4300 if (strcmp(str1,"WrLeh") != 0) {
4301 return False;
4303 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4304 return False;
4307 if (mdrcnt > 0) {
4308 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4309 if (!*rdata) {
4310 return False;
4313 desc.base = *rdata;
4314 desc.buflen = mdrcnt;
4315 if (init_package(&desc,1,0)) {
4316 PACKS(&desc,"B41","NULL");
4319 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4321 *rdata_len = desc.usedlen;
4323 *rparam_len = 8;
4324 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4325 if (!*rparam) {
4326 return False;
4328 SSVALS(*rparam,0,desc.errcode);
4329 SSVAL(*rparam,2,0);
4330 SSVAL(*rparam,4,succnt);
4331 SSVAL(*rparam,6,1);
4333 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4335 return True;
4338 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4339 char *param, int tpscnt,
4340 char *data, int tdscnt,
4341 int mdrcnt,int mprcnt,
4342 char **rdata,char **rparam,
4343 int *rdata_len,int *rparam_len)
4345 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4346 char *str2 = skip_string(param,tpscnt,str1);
4347 char *p = skip_string(param,tpscnt,str2);
4348 int uLevel;
4349 int succnt;
4350 struct pack_desc desc;
4352 if (!str1 || !str2 || !p) {
4353 return False;
4355 memset((char *)&desc,'\0',sizeof(desc));
4357 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4359 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4361 /* check it's a supported varient */
4362 if (strcmp(str1,"WrLeh") != 0) {
4363 return False;
4365 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4366 return False;
4369 if (mdrcnt > 0) {
4370 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4371 if (!*rdata) {
4372 return False;
4375 desc.base = *rdata;
4376 desc.buflen = mdrcnt;
4377 desc.format = str2;
4378 if (init_package(&desc,1,0)) {
4379 PACKS(&desc,"B13","lpd");
4382 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4384 *rdata_len = desc.usedlen;
4386 *rparam_len = 8;
4387 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4388 if (!*rparam) {
4389 return False;
4391 SSVALS(*rparam,0,desc.errcode);
4392 SSVAL(*rparam,2,0);
4393 SSVAL(*rparam,4,succnt);
4394 SSVAL(*rparam,6,1);
4396 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4398 return True;
4401 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4402 char *param, int tpscnt,
4403 char *data, int tdscnt,
4404 int mdrcnt,int mprcnt,
4405 char **rdata,char **rparam,
4406 int *rdata_len,int *rparam_len)
4408 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4409 char *str2 = skip_string(param,tpscnt,str1);
4410 char *p = skip_string(param,tpscnt,str2);
4411 int uLevel;
4412 int succnt;
4413 struct pack_desc desc;
4415 if (!str1 || !str2 || !p) {
4416 return False;
4419 memset((char *)&desc,'\0',sizeof(desc));
4421 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4423 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4425 /* check it's a supported varient */
4426 if (strcmp(str1,"WrLeh") != 0) {
4427 return False;
4429 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4430 return False;
4433 if (mdrcnt > 0) {
4434 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4435 if (!*rdata) {
4436 return False;
4439 memset((char *)&desc,'\0',sizeof(desc));
4440 desc.base = *rdata;
4441 desc.buflen = mdrcnt;
4442 desc.format = str2;
4443 if (init_package(&desc,1,0)) {
4444 PACKS(&desc,"B13","lp0");
4447 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4449 *rdata_len = desc.usedlen;
4451 *rparam_len = 8;
4452 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4453 if (!*rparam) {
4454 return False;
4456 SSVALS(*rparam,0,desc.errcode);
4457 SSVAL(*rparam,2,0);
4458 SSVAL(*rparam,4,succnt);
4459 SSVAL(*rparam,6,1);
4461 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4463 return True;
4466 /****************************************************************************
4467 List open sessions
4468 ****************************************************************************/
4470 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4471 char *param, int tpscnt,
4472 char *data, int tdscnt,
4473 int mdrcnt,int mprcnt,
4474 char **rdata,char **rparam,
4475 int *rdata_len,int *rparam_len)
4478 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4479 char *str2 = skip_string(param,tpscnt,str1);
4480 char *p = skip_string(param,tpscnt,str2);
4481 int uLevel;
4482 struct pack_desc desc;
4483 struct sessionid *session_list;
4484 int i, num_sessions;
4486 if (!str1 || !str2 || !p) {
4487 return False;
4490 memset((char *)&desc,'\0',sizeof(desc));
4492 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4494 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4495 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4496 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4498 /* check it's a supported varient */
4499 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4500 return False;
4502 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4503 return False;
4506 num_sessions = list_sessions(talloc_tos(), &session_list);
4508 if (mdrcnt > 0) {
4509 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4510 if (!*rdata) {
4511 return False;
4514 memset((char *)&desc,'\0',sizeof(desc));
4515 desc.base = *rdata;
4516 desc.buflen = mdrcnt;
4517 desc.format = str2;
4518 if (!init_package(&desc,num_sessions,0)) {
4519 return False;
4522 for(i=0; i<num_sessions; i++) {
4523 PACKS(&desc, "z", session_list[i].remote_machine);
4524 PACKS(&desc, "z", session_list[i].username);
4525 PACKI(&desc, "W", 1); /* num conns */
4526 PACKI(&desc, "W", 0); /* num opens */
4527 PACKI(&desc, "W", 1); /* num users */
4528 PACKI(&desc, "D", 0); /* session time */
4529 PACKI(&desc, "D", 0); /* idle time */
4530 PACKI(&desc, "D", 0); /* flags */
4531 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4534 *rdata_len = desc.usedlen;
4536 *rparam_len = 8;
4537 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4538 if (!*rparam) {
4539 return False;
4541 SSVALS(*rparam,0,desc.errcode);
4542 SSVAL(*rparam,2,0); /* converter */
4543 SSVAL(*rparam,4,num_sessions); /* count */
4545 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4547 return True;
4551 /****************************************************************************
4552 The buffer was too small.
4553 ****************************************************************************/
4555 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4556 int mdrcnt, int mprcnt,
4557 char **rdata, char **rparam,
4558 int *rdata_len, int *rparam_len)
4560 *rparam_len = MIN(*rparam_len,mprcnt);
4561 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4562 if (!*rparam) {
4563 return False;
4566 *rdata_len = 0;
4568 SSVAL(*rparam,0,NERR_BufTooSmall);
4570 DEBUG(3,("Supplied buffer too small in API command\n"));
4572 return True;
4575 /****************************************************************************
4576 The request is not supported.
4577 ****************************************************************************/
4579 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4580 char *param, int tpscnt,
4581 char *data, int tdscnt,
4582 int mdrcnt, int mprcnt,
4583 char **rdata, char **rparam,
4584 int *rdata_len, int *rparam_len)
4586 *rparam_len = 4;
4587 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4588 if (!*rparam) {
4589 return False;
4592 *rdata_len = 0;
4594 SSVAL(*rparam,0,NERR_notsupported);
4595 SSVAL(*rparam,2,0); /* converter word */
4597 DEBUG(3,("Unsupported API command\n"));
4599 return True;
4602 static const struct {
4603 const char *name;
4604 int id;
4605 bool (*fn)(connection_struct *, uint16,
4606 char *, int,
4607 char *, int,
4608 int,int,char **,char **,int *,int *);
4609 bool auth_user; /* Deny anonymous access? */
4610 } api_commands[] = {
4611 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4612 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4613 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4614 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4615 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4616 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4617 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4618 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4619 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4620 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4621 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4622 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4623 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4624 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4625 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4626 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4627 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4628 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4629 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4630 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4631 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4632 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4633 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4634 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4635 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4636 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4637 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4638 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4639 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4640 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4641 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4642 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4643 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4644 {NULL, -1, api_Unsupported}
4645 /* The following RAP calls are not implemented by Samba:
4647 RAP_WFileEnum2 - anon not OK
4652 /****************************************************************************
4653 Handle remote api calls.
4654 ****************************************************************************/
4656 void api_reply(connection_struct *conn, uint16 vuid,
4657 struct smb_request *req,
4658 char *data, char *params,
4659 int tdscnt, int tpscnt,
4660 int mdrcnt, int mprcnt)
4662 struct smbd_server_connection *sconn = smbd_server_conn;
4663 int api_command;
4664 char *rdata = NULL;
4665 char *rparam = NULL;
4666 const char *name1 = NULL;
4667 const char *name2 = NULL;
4668 int rdata_len = 0;
4669 int rparam_len = 0;
4670 bool reply=False;
4671 int i;
4673 if (!params) {
4674 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4675 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4676 return;
4679 if (tpscnt < 2) {
4680 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4681 return;
4683 api_command = SVAL(params,0);
4684 /* Is there a string at position params+2 ? */
4685 if (skip_string(params,tpscnt,params+2)) {
4686 name1 = params + 2;
4687 } else {
4688 name1 = "";
4690 name2 = skip_string(params,tpscnt,params+2);
4691 if (!name2) {
4692 name2 = "";
4695 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4696 api_command,
4697 name1,
4698 name2,
4699 tdscnt,tpscnt,mdrcnt,mprcnt));
4701 for (i=0;api_commands[i].name;i++) {
4702 if (api_commands[i].id == api_command && api_commands[i].fn) {
4703 DEBUG(3,("Doing %s\n",api_commands[i].name));
4704 break;
4708 /* Check whether this api call can be done anonymously */
4710 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4711 user_struct *user = get_valid_user_struct(sconn, vuid);
4713 if (!user || user->server_info->guest) {
4714 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4715 return;
4719 rdata = (char *)SMB_MALLOC(1024);
4720 if (rdata) {
4721 memset(rdata,'\0',1024);
4724 rparam = (char *)SMB_MALLOC(1024);
4725 if (rparam) {
4726 memset(rparam,'\0',1024);
4729 if(!rdata || !rparam) {
4730 DEBUG(0,("api_reply: malloc fail !\n"));
4731 SAFE_FREE(rdata);
4732 SAFE_FREE(rparam);
4733 reply_nterror(req, NT_STATUS_NO_MEMORY);
4734 return;
4737 reply = api_commands[i].fn(conn,
4738 vuid,
4739 params,tpscnt, /* params + length */
4740 data,tdscnt, /* data + length */
4741 mdrcnt,mprcnt,
4742 &rdata,&rparam,&rdata_len,&rparam_len);
4745 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4746 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4747 &rdata,&rparam,&rdata_len,&rparam_len);
4750 /* if we get False back then it's actually unsupported */
4751 if (!reply) {
4752 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4753 &rdata,&rparam,&rdata_len,&rparam_len);
4756 /* If api_Unsupported returns false we can't return anything. */
4757 if (reply) {
4758 send_trans_reply(conn, req, rparam, rparam_len,
4759 rdata, rdata_len, False);
4762 SAFE_FREE(rdata);
4763 SAFE_FREE(rparam);
4764 return;