s3: Add an async smbsock_connect
[Samba.git] / source3 / smbd / lanman.c
blob40b6acae9f2621589d1af503fc26e83f63962b35
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
29 #include "../lib/util/binsearch.h"
31 #ifdef CHECK_TYPES
32 #undef CHECK_TYPES
33 #endif
34 #define CHECK_TYPES 0
36 #define NERR_Success 0
37 #define NERR_badpass 86
38 #define NERR_notsupported 50
40 #define NERR_BASE (2100)
41 #define NERR_BufTooSmall (NERR_BASE+23)
42 #define NERR_JobNotFound (NERR_BASE+51)
43 #define NERR_DestNotFound (NERR_BASE+52)
45 #define ACCESS_READ 0x01
46 #define ACCESS_WRITE 0x02
47 #define ACCESS_CREATE 0x04
49 #define SHPWLEN 8 /* share password length */
51 /* Limit size of ipc replies */
53 static char *smb_realloc_limit(void *ptr, size_t size)
55 char *val;
57 size = MAX((size),4*1024);
58 val = (char *)SMB_REALLOC(ptr,size);
59 if (val) {
60 memset(val,'\0',size);
62 return val;
65 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
66 char *param, int tpscnt,
67 char *data, int tdscnt,
68 int mdrcnt, int mprcnt,
69 char **rdata, char **rparam,
70 int *rdata_len, int *rparam_len);
72 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
73 int mdrcnt, int mprcnt,
74 char **rdata, char **rparam,
75 int *rdata_len, int *rparam_len);
78 static int CopyExpanded(connection_struct *conn,
79 int snum, char **dst, char *src, int *p_space_remaining)
81 TALLOC_CTX *ctx = talloc_tos();
82 char *buf = NULL;
83 int l;
85 if (!src || !dst || !p_space_remaining || !(*dst) ||
86 *p_space_remaining <= 0) {
87 return 0;
90 buf = talloc_strdup(ctx, src);
91 if (!buf) {
92 *p_space_remaining = 0;
93 return 0;
95 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
96 if (!buf) {
97 *p_space_remaining = 0;
98 return 0;
100 buf = talloc_sub_advanced(ctx,
101 lp_servicename(SNUM(conn)),
102 conn->server_info->unix_name,
103 conn->connectpath,
104 conn->server_info->utok.gid,
105 conn->server_info->sanitized_username,
106 pdb_get_domain(conn->server_info->sam_account),
107 buf);
108 if (!buf) {
109 *p_space_remaining = 0;
110 return 0;
112 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
113 if (l == -1) {
114 return 0;
116 (*dst) += l;
117 (*p_space_remaining) -= l;
118 return l;
121 static int CopyAndAdvance(char **dst, char *src, int *n)
123 int l;
124 if (!src || !dst || !n || !(*dst)) {
125 return 0;
127 l = push_ascii(*dst,src,*n, STR_TERMINATE);
128 if (l == -1) {
129 return 0;
131 (*dst) += l;
132 (*n) -= l;
133 return l;
136 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
138 TALLOC_CTX *ctx = talloc_tos();
139 char *buf = NULL;
140 if (!s) {
141 return 0;
143 buf = talloc_strdup(ctx,s);
144 if (!buf) {
145 return 0;
147 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
148 if (!buf) {
149 return 0;
151 buf = talloc_sub_advanced(ctx,
152 lp_servicename(SNUM(conn)),
153 conn->server_info->unix_name,
154 conn->connectpath,
155 conn->server_info->utok.gid,
156 conn->server_info->sanitized_username,
157 pdb_get_domain(conn->server_info->sam_account),
158 buf);
159 if (!buf) {
160 return 0;
162 return strlen(buf) + 1;
165 static char *Expand(connection_struct *conn, int snum, char *s)
167 TALLOC_CTX *ctx = talloc_tos();
168 char *buf = NULL;
170 if (!s) {
171 return NULL;
173 buf = talloc_strdup(ctx,s);
174 if (!buf) {
175 return 0;
177 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
178 if (!buf) {
179 return 0;
181 return talloc_sub_advanced(ctx,
182 lp_servicename(SNUM(conn)),
183 conn->server_info->unix_name,
184 conn->connectpath,
185 conn->server_info->utok.gid,
186 conn->server_info->sanitized_username,
187 pdb_get_domain(conn->server_info->sam_account),
188 buf);
191 /*******************************************************************
192 Check a API string for validity when we only need to check the prefix.
193 ******************************************************************/
195 static bool prefix_ok(const char *str, const char *prefix)
197 return(strncmp(str,prefix,strlen(prefix)) == 0);
200 struct pack_desc {
201 const char *format; /* formatstring for structure */
202 const char *subformat; /* subformat for structure */
203 char *base; /* baseaddress of buffer */
204 int buflen; /* remaining size for fixed part; on init: length of base */
205 int subcount; /* count of substructures */
206 char *structbuf; /* pointer into buffer for remaining fixed part */
207 int stringlen; /* remaining size for variable part */
208 char *stringbuf; /* pointer into buffer for remaining variable part */
209 int neededlen; /* total needed size */
210 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
211 const char *curpos; /* current position; pointer into format or subformat */
212 int errcode;
215 static int get_counter(const char **p)
217 int i, n;
218 if (!p || !(*p)) {
219 return 1;
221 if (!isdigit((int)**p)) {
222 return 1;
224 for (n = 0;;) {
225 i = **p;
226 if (isdigit(i)) {
227 n = 10 * n + (i - '0');
228 } else {
229 return n;
231 (*p)++;
235 static int getlen(const char *p)
237 int n = 0;
238 if (!p) {
239 return 0;
242 while (*p) {
243 switch( *p++ ) {
244 case 'W': /* word (2 byte) */
245 n += 2;
246 break;
247 case 'K': /* status word? (2 byte) */
248 n += 2;
249 break;
250 case 'N': /* count of substructures (word) at end */
251 n += 2;
252 break;
253 case 'D': /* double word (4 byte) */
254 case 'z': /* offset to zero terminated string (4 byte) */
255 case 'l': /* offset to user data (4 byte) */
256 n += 4;
257 break;
258 case 'b': /* offset to data (with counter) (4 byte) */
259 n += 4;
260 get_counter(&p);
261 break;
262 case 'B': /* byte (with optional counter) */
263 n += get_counter(&p);
264 break;
267 return n;
270 static bool init_package(struct pack_desc *p, int count, int subcount)
272 int n = p->buflen;
273 int i;
275 if (!p->format || !p->base) {
276 return False;
279 i = count * getlen(p->format);
280 if (p->subformat) {
281 i += subcount * getlen(p->subformat);
283 p->structbuf = p->base;
284 p->neededlen = 0;
285 p->usedlen = 0;
286 p->subcount = 0;
287 p->curpos = p->format;
288 if (i > n) {
289 p->neededlen = i;
290 i = n = 0;
291 #if 0
293 * This is the old error code we used. Aparently
294 * WinNT/2k systems return ERRbuftoosmall (2123) and
295 * OS/2 needs this. I'm leaving this here so we can revert
296 * if needed. JRA.
298 p->errcode = ERRmoredata;
299 #else
300 p->errcode = ERRbuftoosmall;
301 #endif
302 } else {
303 p->errcode = NERR_Success;
305 p->buflen = i;
306 n -= i;
307 p->stringbuf = p->base + i;
308 p->stringlen = n;
309 return (p->errcode == NERR_Success);
312 static int package(struct pack_desc *p, ...)
314 va_list args;
315 int needed=0, stringneeded;
316 const char *str=NULL;
317 int is_string=0, stringused;
318 int32 temp;
320 va_start(args,p);
322 if (!*p->curpos) {
323 if (!p->subcount) {
324 p->curpos = p->format;
325 } else {
326 p->curpos = p->subformat;
327 p->subcount--;
330 #if CHECK_TYPES
331 str = va_arg(args,char*);
332 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
333 #endif
334 stringneeded = -1;
336 if (!p->curpos) {
337 va_end(args);
338 return 0;
341 switch( *p->curpos++ ) {
342 case 'W': /* word (2 byte) */
343 needed = 2;
344 temp = va_arg(args,int);
345 if (p->buflen >= needed) {
346 SSVAL(p->structbuf,0,temp);
348 break;
349 case 'K': /* status word? (2 byte) */
350 needed = 2;
351 temp = va_arg(args,int);
352 if (p->buflen >= needed) {
353 SSVAL(p->structbuf,0,temp);
355 break;
356 case 'N': /* count of substructures (word) at end */
357 needed = 2;
358 p->subcount = va_arg(args,int);
359 if (p->buflen >= needed) {
360 SSVAL(p->structbuf,0,p->subcount);
362 break;
363 case 'D': /* double word (4 byte) */
364 needed = 4;
365 temp = va_arg(args,int);
366 if (p->buflen >= needed) {
367 SIVAL(p->structbuf,0,temp);
369 break;
370 case 'B': /* byte (with optional counter) */
371 needed = get_counter(&p->curpos);
373 char *s = va_arg(args,char*);
374 if (p->buflen >= needed) {
375 StrnCpy(p->structbuf,s?s:"",needed-1);
378 break;
379 case 'z': /* offset to zero terminated string (4 byte) */
380 str = va_arg(args,char*);
381 stringneeded = (str ? strlen(str)+1 : 0);
382 is_string = 1;
383 break;
384 case 'l': /* offset to user data (4 byte) */
385 str = va_arg(args,char*);
386 stringneeded = va_arg(args,int);
387 is_string = 0;
388 break;
389 case 'b': /* offset to data (with counter) (4 byte) */
390 str = va_arg(args,char*);
391 stringneeded = get_counter(&p->curpos);
392 is_string = 0;
393 break;
396 va_end(args);
397 if (stringneeded >= 0) {
398 needed = 4;
399 if (p->buflen >= needed) {
400 stringused = stringneeded;
401 if (stringused > p->stringlen) {
402 stringused = (is_string ? p->stringlen : 0);
403 if (p->errcode == NERR_Success) {
404 p->errcode = ERRmoredata;
407 if (!stringused) {
408 SIVAL(p->structbuf,0,0);
409 } else {
410 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
411 memcpy(p->stringbuf,str?str:"",stringused);
412 if (is_string) {
413 p->stringbuf[stringused-1] = '\0';
415 p->stringbuf += stringused;
416 p->stringlen -= stringused;
417 p->usedlen += stringused;
420 p->neededlen += stringneeded;
423 p->neededlen += needed;
424 if (p->buflen >= needed) {
425 p->structbuf += needed;
426 p->buflen -= needed;
427 p->usedlen += needed;
428 } else {
429 if (p->errcode == NERR_Success) {
430 p->errcode = ERRmoredata;
433 return 1;
436 #if CHECK_TYPES
437 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
438 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
439 #else
440 #define PACK(desc,t,v) package(desc,v)
441 #define PACKl(desc,t,v,l) package(desc,v,l)
442 #endif
444 static void PACKI(struct pack_desc* desc, const char *t,int v)
446 PACK(desc,t,v);
449 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
451 PACK(desc,t,v);
454 /****************************************************************************
455 Get a print queue.
456 ****************************************************************************/
458 static void PackDriverData(struct pack_desc* desc)
460 char drivdata[4+4+32];
461 SIVAL(drivdata,0,sizeof drivdata); /* cb */
462 SIVAL(drivdata,4,1000); /* lVersion */
463 memset(drivdata+8,0,32); /* szDeviceName */
464 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
465 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
468 static int check_printq_info(struct pack_desc* desc,
469 unsigned int uLevel, char *id1, char *id2)
471 desc->subformat = NULL;
472 switch( uLevel ) {
473 case 0:
474 desc->format = "B13";
475 break;
476 case 1:
477 desc->format = "B13BWWWzzzzzWW";
478 break;
479 case 2:
480 desc->format = "B13BWWWzzzzzWN";
481 desc->subformat = "WB21BB16B10zWWzDDz";
482 break;
483 case 3:
484 desc->format = "zWWWWzzzzWWzzl";
485 break;
486 case 4:
487 desc->format = "zWWWWzzzzWNzzl";
488 desc->subformat = "WWzWWDDzz";
489 break;
490 case 5:
491 desc->format = "z";
492 break;
493 case 51:
494 desc->format = "K";
495 break;
496 case 52:
497 desc->format = "WzzzzzzzzN";
498 desc->subformat = "z";
499 break;
500 default:
501 DEBUG(0,("check_printq_info: invalid level %d\n",
502 uLevel ));
503 return False;
505 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
506 DEBUG(0,("check_printq_info: invalid format %s\n",
507 id1 ? id1 : "<NULL>" ));
508 return False;
510 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
511 DEBUG(0,("check_printq_info: invalid subformat %s\n",
512 id2 ? id2 : "<NULL>" ));
513 return False;
515 return True;
519 #define RAP_JOB_STATUS_QUEUED 0
520 #define RAP_JOB_STATUS_PAUSED 1
521 #define RAP_JOB_STATUS_SPOOLING 2
522 #define RAP_JOB_STATUS_PRINTING 3
523 #define RAP_JOB_STATUS_PRINTED 4
525 #define RAP_QUEUE_STATUS_PAUSED 1
526 #define RAP_QUEUE_STATUS_ERROR 2
528 /* turn a print job status into a on the wire status
530 static int printj_status(int v)
532 switch (v) {
533 case LPQ_QUEUED:
534 return RAP_JOB_STATUS_QUEUED;
535 case LPQ_PAUSED:
536 return RAP_JOB_STATUS_PAUSED;
537 case LPQ_SPOOLING:
538 return RAP_JOB_STATUS_SPOOLING;
539 case LPQ_PRINTING:
540 return RAP_JOB_STATUS_PRINTING;
542 return 0;
545 /* turn a print queue status into a on the wire status
547 static int printq_status(int v)
549 switch (v) {
550 case LPQ_QUEUED:
551 return 0;
552 case LPQ_PAUSED:
553 return RAP_QUEUE_STATUS_PAUSED;
555 return RAP_QUEUE_STATUS_ERROR;
558 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
559 struct pack_desc *desc,
560 print_queue_struct *queue, int n)
562 time_t t = queue->time;
564 /* the client expects localtime */
565 t -= get_time_zone(t);
567 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
568 if (uLevel == 1) {
569 PACKS(desc,"B21",queue->fs_user); /* szUserName */
570 PACKS(desc,"B",""); /* pad */
571 PACKS(desc,"B16",""); /* szNotifyName */
572 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
573 PACKS(desc,"z",""); /* pszParms */
574 PACKI(desc,"W",n+1); /* uPosition */
575 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
576 PACKS(desc,"z",""); /* pszStatus */
577 PACKI(desc,"D",t); /* ulSubmitted */
578 PACKI(desc,"D",queue->size); /* ulSize */
579 PACKS(desc,"z",queue->fs_file); /* pszComment */
581 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
582 PACKI(desc,"W",queue->priority); /* uPriority */
583 PACKS(desc,"z",queue->fs_user); /* pszUserName */
584 PACKI(desc,"W",n+1); /* uPosition */
585 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
586 PACKI(desc,"D",t); /* ulSubmitted */
587 PACKI(desc,"D",queue->size); /* ulSize */
588 PACKS(desc,"z","Samba"); /* pszComment */
589 PACKS(desc,"z",queue->fs_file); /* pszDocument */
590 if (uLevel == 3) {
591 PACKS(desc,"z",""); /* pszNotifyName */
592 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
593 PACKS(desc,"z",""); /* pszParms */
594 PACKS(desc,"z",""); /* pszStatus */
595 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
596 PACKS(desc,"z","lpd"); /* pszQProcName */
597 PACKS(desc,"z",""); /* pszQProcParms */
598 PACKS(desc,"z","NULL"); /* pszDriverName */
599 PackDriverData(desc); /* pDriverData */
600 PACKS(desc,"z",""); /* pszPrinterName */
601 } else if (uLevel == 4) { /* OS2 */
602 PACKS(desc,"z",""); /* pszSpoolFileName */
603 PACKS(desc,"z",""); /* pszPortName */
604 PACKS(desc,"z",""); /* pszStatus */
605 PACKI(desc,"D",0); /* ulPagesSpooled */
606 PACKI(desc,"D",0); /* ulPagesSent */
607 PACKI(desc,"D",0); /* ulPagesPrinted */
608 PACKI(desc,"D",0); /* ulTimePrinted */
609 PACKI(desc,"D",0); /* ulExtendJobStatus */
610 PACKI(desc,"D",0); /* ulStartPage */
611 PACKI(desc,"D",0); /* ulEndPage */
616 /********************************************************************
617 Return a driver name given an snum.
618 Returns True if from tdb, False otherwise.
619 ********************************************************************/
621 static bool get_driver_name(int snum, char **pp_drivername)
623 NT_PRINTER_INFO_LEVEL *info = NULL;
624 bool in_tdb = false;
626 get_a_printer (NULL, &info, 2, lp_servicename(snum));
627 if (info != NULL) {
628 *pp_drivername = talloc_strdup(talloc_tos(),
629 info->info_2->drivername);
630 in_tdb = true;
631 free_a_printer(&info, 2);
632 if (!*pp_drivername) {
633 return false;
637 return in_tdb;
640 /********************************************************************
641 Respond to the DosPrintQInfo command with a level of 52
642 This is used to get printer driver information for Win9x clients
643 ********************************************************************/
644 static void fill_printq_info_52(connection_struct *conn, int snum,
645 struct pack_desc* desc, int count )
647 int i;
648 fstring location;
649 NT_PRINTER_DRIVER_INFO_LEVEL driver;
650 NT_PRINTER_INFO_LEVEL *printer = NULL;
652 ZERO_STRUCT(driver);
654 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
655 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
656 lp_servicename(snum)));
657 goto err;
660 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
661 "Windows 4.0", 0)) )
663 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
664 printer->info_2->drivername));
665 goto err;
668 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
669 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
670 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
672 PACKI(desc, "W", 0x0400); /* don't know */
673 PACKS(desc, "z", driver.info_3->name); /* long printer name */
674 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
675 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
676 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
678 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
679 standard_sub_basic( "", "", location, sizeof(location)-1 );
680 PACKS(desc,"z", location); /* share to retrieve files */
682 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
683 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
684 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
686 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
687 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
688 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
689 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
690 DEBUG(3,("Driver Location: %s:\n",location));
691 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
692 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
693 PACKI(desc,"N",count); /* number of files to copy */
695 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
697 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
698 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
699 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
702 /* sanity check */
703 if ( i != count )
704 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
705 count, i));
707 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
709 desc->errcode=NERR_Success;
710 goto done;
712 err:
713 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
714 desc->errcode=NERR_notsupported;
716 done:
717 if ( printer )
718 free_a_printer( &printer, 2 );
720 if ( driver.info_3 )
721 free_a_printer_driver( driver, 3 );
725 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
726 struct pack_desc* desc,
727 int count, print_queue_struct* queue,
728 print_status_struct* status)
730 switch (uLevel) {
731 case 1:
732 case 2:
733 PACKS(desc,"B13",SERVICE(snum));
734 break;
735 case 3:
736 case 4:
737 case 5:
738 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
739 break;
740 case 51:
741 PACKI(desc,"K",printq_status(status->status));
742 break;
745 if (uLevel == 1 || uLevel == 2) {
746 PACKS(desc,"B",""); /* alignment */
747 PACKI(desc,"W",5); /* priority */
748 PACKI(desc,"W",0); /* start time */
749 PACKI(desc,"W",0); /* until time */
750 PACKS(desc,"z",""); /* pSepFile */
751 PACKS(desc,"z","lpd"); /* pPrProc */
752 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
753 PACKS(desc,"z",""); /* pParms */
754 if (snum < 0) {
755 PACKS(desc,"z","UNKNOWN PRINTER");
756 PACKI(desc,"W",LPSTAT_ERROR);
758 else if (!status || !status->message[0]) {
759 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
760 PACKI(desc,"W",LPSTAT_OK); /* status */
761 } else {
762 PACKS(desc,"z",status->message);
763 PACKI(desc,"W",printq_status(status->status)); /* status */
765 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
768 if (uLevel == 3 || uLevel == 4) {
769 char *drivername = NULL;
771 PACKI(desc,"W",5); /* uPriority */
772 PACKI(desc,"W",0); /* uStarttime */
773 PACKI(desc,"W",0); /* uUntiltime */
774 PACKI(desc,"W",5); /* pad1 */
775 PACKS(desc,"z",""); /* pszSepFile */
776 PACKS(desc,"z","WinPrint"); /* pszPrProc */
777 PACKS(desc,"z",NULL); /* pszParms */
778 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
779 /* "don't ask" that it's done this way to fix corrupted
780 Win9X/ME printer comments. */
781 if (!status) {
782 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
783 } else {
784 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
786 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
787 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
788 get_driver_name(snum,&drivername);
789 if (!drivername) {
790 return;
792 PACKS(desc,"z",drivername); /* pszDriverName */
793 PackDriverData(desc); /* pDriverData */
796 if (uLevel == 2 || uLevel == 4) {
797 int i;
798 for (i=0;i<count;i++)
799 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
802 if (uLevel==52)
803 fill_printq_info_52( conn, snum, desc, count );
806 /* This function returns the number of files for a given driver */
807 static int get_printerdrivernumber(int snum)
809 int result = 0;
810 NT_PRINTER_DRIVER_INFO_LEVEL driver;
811 NT_PRINTER_INFO_LEVEL *printer = NULL;
813 ZERO_STRUCT(driver);
815 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
816 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
817 lp_servicename(snum)));
818 goto done;
821 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
822 "Windows 4.0", 0)) )
824 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
825 printer->info_2->drivername));
826 goto done;
829 /* count the number of files */
830 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
831 result++;
833 done:
834 if ( printer )
835 free_a_printer( &printer, 2 );
837 if ( driver.info_3 )
838 free_a_printer_driver( driver, 3 );
840 return result;
843 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
844 char *param, int tpscnt,
845 char *data, int tdscnt,
846 int mdrcnt,int mprcnt,
847 char **rdata,char **rparam,
848 int *rdata_len,int *rparam_len)
850 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
851 char *str2 = skip_string(param,tpscnt,str1);
852 char *p = skip_string(param,tpscnt,str2);
853 char *QueueName = p;
854 unsigned int uLevel;
855 int count=0;
856 int snum;
857 char *str3;
858 struct pack_desc desc;
859 print_queue_struct *queue=NULL;
860 print_status_struct status;
861 char* tmpdata=NULL;
863 if (!str1 || !str2 || !p) {
864 return False;
866 memset((char *)&status,'\0',sizeof(status));
867 memset((char *)&desc,'\0',sizeof(desc));
869 p = skip_string(param,tpscnt,p);
870 if (!p) {
871 return False;
873 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
874 str3 = get_safe_str_ptr(param,tpscnt,p,4);
875 /* str3 may be null here and is checked in check_printq_info(). */
877 /* remove any trailing username */
878 if ((p = strchr_m(QueueName,'%')))
879 *p = 0;
881 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
883 /* check it's a supported varient */
884 if (!prefix_ok(str1,"zWrLh"))
885 return False;
886 if (!check_printq_info(&desc,uLevel,str2,str3)) {
888 * Patch from Scott Moomaw <scott@bridgewater.edu>
889 * to return the 'invalid info level' error if an
890 * unknown level was requested.
892 *rdata_len = 0;
893 *rparam_len = 6;
894 *rparam = smb_realloc_limit(*rparam,*rparam_len);
895 if (!*rparam) {
896 return False;
898 SSVALS(*rparam,0,ERRunknownlevel);
899 SSVAL(*rparam,2,0);
900 SSVAL(*rparam,4,0);
901 return(True);
904 snum = find_service(QueueName);
905 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
906 return False;
908 if (uLevel==52) {
909 count = get_printerdrivernumber(snum);
910 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
911 } else {
912 count = print_queue_status(snum, &queue,&status);
915 if (mdrcnt > 0) {
916 *rdata = smb_realloc_limit(*rdata,mdrcnt);
917 if (!*rdata) {
918 SAFE_FREE(queue);
919 return False;
921 desc.base = *rdata;
922 desc.buflen = mdrcnt;
923 } else {
925 * Don't return data but need to get correct length
926 * init_package will return wrong size if buflen=0
928 desc.buflen = getlen(desc.format);
929 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
932 if (init_package(&desc,1,count)) {
933 desc.subcount = count;
934 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
937 *rdata_len = desc.usedlen;
940 * We must set the return code to ERRbuftoosmall
941 * in order to support lanman style printing with Win NT/2k
942 * clients --jerry
944 if (!mdrcnt && lp_disable_spoolss())
945 desc.errcode = ERRbuftoosmall;
947 *rdata_len = desc.usedlen;
948 *rparam_len = 6;
949 *rparam = smb_realloc_limit(*rparam,*rparam_len);
950 if (!*rparam) {
951 SAFE_FREE(queue);
952 SAFE_FREE(tmpdata);
953 return False;
955 SSVALS(*rparam,0,desc.errcode);
956 SSVAL(*rparam,2,0);
957 SSVAL(*rparam,4,desc.neededlen);
959 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
961 SAFE_FREE(queue);
962 SAFE_FREE(tmpdata);
964 return(True);
967 /****************************************************************************
968 View list of all print jobs on all queues.
969 ****************************************************************************/
971 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
972 char *param, int tpscnt,
973 char *data, int tdscnt,
974 int mdrcnt, int mprcnt,
975 char **rdata, char** rparam,
976 int *rdata_len, int *rparam_len)
978 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
979 char *output_format1 = skip_string(param,tpscnt,param_format);
980 char *p = skip_string(param,tpscnt,output_format1);
981 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
982 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
983 int services = lp_numservices();
984 int i, n;
985 struct pack_desc desc;
986 print_queue_struct **queue = NULL;
987 print_status_struct *status = NULL;
988 int *subcntarr = NULL;
989 int queuecnt = 0, subcnt = 0, succnt = 0;
991 if (!param_format || !output_format1 || !p) {
992 return False;
995 memset((char *)&desc,'\0',sizeof(desc));
997 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
999 if (!prefix_ok(param_format,"WrLeh")) {
1000 return False;
1002 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1004 * Patch from Scott Moomaw <scott@bridgewater.edu>
1005 * to return the 'invalid info level' error if an
1006 * unknown level was requested.
1008 *rdata_len = 0;
1009 *rparam_len = 6;
1010 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1011 if (!*rparam) {
1012 return False;
1014 SSVALS(*rparam,0,ERRunknownlevel);
1015 SSVAL(*rparam,2,0);
1016 SSVAL(*rparam,4,0);
1017 return(True);
1020 for (i = 0; i < services; i++) {
1021 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1022 queuecnt++;
1026 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1027 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1028 goto err;
1030 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1031 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1032 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1033 goto err;
1035 memset(status,0,queuecnt*sizeof(print_status_struct));
1036 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1037 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1038 goto err;
1041 subcnt = 0;
1042 n = 0;
1043 for (i = 0; i < services; i++) {
1044 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1045 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1046 subcnt += subcntarr[n];
1047 n++;
1051 if (mdrcnt > 0) {
1052 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1053 if (!*rdata) {
1054 goto err;
1057 desc.base = *rdata;
1058 desc.buflen = mdrcnt;
1060 if (init_package(&desc,queuecnt,subcnt)) {
1061 n = 0;
1062 succnt = 0;
1063 for (i = 0; i < services; i++) {
1064 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1065 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1066 n++;
1067 if (desc.errcode == NERR_Success) {
1068 succnt = n;
1074 SAFE_FREE(subcntarr);
1076 *rdata_len = desc.usedlen;
1077 *rparam_len = 8;
1078 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1079 if (!*rparam) {
1080 goto err;
1082 SSVALS(*rparam,0,desc.errcode);
1083 SSVAL(*rparam,2,0);
1084 SSVAL(*rparam,4,succnt);
1085 SSVAL(*rparam,6,queuecnt);
1087 for (i = 0; i < queuecnt; i++) {
1088 if (queue) {
1089 SAFE_FREE(queue[i]);
1093 SAFE_FREE(queue);
1094 SAFE_FREE(status);
1096 return True;
1098 err:
1100 SAFE_FREE(subcntarr);
1101 for (i = 0; i < queuecnt; i++) {
1102 if (queue) {
1103 SAFE_FREE(queue[i]);
1106 SAFE_FREE(queue);
1107 SAFE_FREE(status);
1109 return False;
1112 /****************************************************************************
1113 Get info level for a server list query.
1114 ****************************************************************************/
1116 static bool check_server_info(int uLevel, char* id)
1118 switch( uLevel ) {
1119 case 0:
1120 if (strcmp(id,"B16") != 0) {
1121 return False;
1123 break;
1124 case 1:
1125 if (strcmp(id,"B16BBDz") != 0) {
1126 return False;
1128 break;
1129 default:
1130 return False;
1132 return True;
1135 struct srv_info_struct {
1136 fstring name;
1137 uint32 type;
1138 fstring comment;
1139 fstring domain;
1140 bool server_added;
1143 /*******************************************************************
1144 Get server info lists from the files saved by nmbd. Return the
1145 number of entries.
1146 ******************************************************************/
1148 static int get_server_info(uint32 servertype,
1149 struct srv_info_struct **servers,
1150 const char *domain)
1152 int count=0;
1153 int alloced=0;
1154 char **lines;
1155 bool local_list_only;
1156 int i;
1158 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1159 if (!lines) {
1160 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1161 return 0;
1164 /* request for everything is code for request all servers */
1165 if (servertype == SV_TYPE_ALL) {
1166 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1169 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1171 DEBUG(4,("Servertype search: %8x\n",servertype));
1173 for (i=0;lines[i];i++) {
1174 fstring stype;
1175 struct srv_info_struct *s;
1176 const char *ptr = lines[i];
1177 bool ok = True;
1178 TALLOC_CTX *frame = NULL;
1179 char *p;
1181 if (!*ptr) {
1182 continue;
1185 if (count == alloced) {
1186 alloced += 10;
1187 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1188 if (!*servers) {
1189 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1190 TALLOC_FREE(lines);
1191 return 0;
1193 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1195 s = &(*servers)[count];
1197 frame = talloc_stackframe();
1198 s->name[0] = '\0';
1199 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1200 TALLOC_FREE(frame);
1201 continue;
1203 fstrcpy(s->name, p);
1205 stype[0] = '\0';
1206 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1207 TALLOC_FREE(frame);
1208 continue;
1210 fstrcpy(stype, p);
1212 s->comment[0] = '\0';
1213 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1214 TALLOC_FREE(frame);
1215 continue;
1217 fstrcpy(s->comment, p);
1218 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1220 s->domain[0] = '\0';
1221 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1222 /* this allows us to cope with an old nmbd */
1223 fstrcpy(s->domain,lp_workgroup());
1224 } else {
1225 fstrcpy(s->domain, p);
1227 TALLOC_FREE(frame);
1229 if (sscanf(stype,"%X",&s->type) != 1) {
1230 DEBUG(4,("r:host file "));
1231 ok = False;
1234 /* Filter the servers/domains we return based on what was asked for. */
1236 /* Check to see if we are being asked for a local list only. */
1237 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1238 DEBUG(4,("r: local list only"));
1239 ok = False;
1242 /* doesn't match up: don't want it */
1243 if (!(servertype & s->type)) {
1244 DEBUG(4,("r:serv type "));
1245 ok = False;
1248 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1249 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1250 DEBUG(4,("s: dom mismatch "));
1251 ok = False;
1254 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1255 ok = False;
1258 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1259 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1261 if (ok) {
1262 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1263 s->name, s->type, s->comment, s->domain));
1264 s->server_added = True;
1265 count++;
1266 } else {
1267 DEBUG(4,("%20s %8x %25s %15s\n",
1268 s->name, s->type, s->comment, s->domain));
1272 TALLOC_FREE(lines);
1273 return count;
1276 /*******************************************************************
1277 Fill in a server info structure.
1278 ******************************************************************/
1280 static int fill_srv_info(struct srv_info_struct *service,
1281 int uLevel, char **buf, int *buflen,
1282 char **stringbuf, int *stringspace, char *baseaddr)
1284 int struct_len;
1285 char* p;
1286 char* p2;
1287 int l2;
1288 int len;
1290 switch (uLevel) {
1291 case 0:
1292 struct_len = 16;
1293 break;
1294 case 1:
1295 struct_len = 26;
1296 break;
1297 default:
1298 return -1;
1301 if (!buf) {
1302 len = 0;
1303 switch (uLevel) {
1304 case 1:
1305 len = strlen(service->comment)+1;
1306 break;
1309 *buflen = struct_len;
1310 *stringspace = len;
1311 return struct_len + len;
1314 len = struct_len;
1315 p = *buf;
1316 if (*buflen < struct_len) {
1317 return -1;
1319 if (stringbuf) {
1320 p2 = *stringbuf;
1321 l2 = *stringspace;
1322 } else {
1323 p2 = p + struct_len;
1324 l2 = *buflen - struct_len;
1326 if (!baseaddr) {
1327 baseaddr = p;
1330 switch (uLevel) {
1331 case 0:
1332 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1333 break;
1335 case 1:
1336 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1337 SIVAL(p,18,service->type);
1338 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1339 len += CopyAndAdvance(&p2,service->comment,&l2);
1340 break;
1343 if (stringbuf) {
1344 *buf = p + struct_len;
1345 *buflen -= struct_len;
1346 *stringbuf = p2;
1347 *stringspace = l2;
1348 } else {
1349 *buf = p2;
1350 *buflen -= len;
1352 return len;
1356 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1358 return StrCaseCmp(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_RNetServerEnum2(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 DEBUG(4, ("domain [%s]\n", domain));
1437 if (lp_browse_list()) {
1438 total = get_server_info(servertype,&servers,domain);
1441 data_len = fixed_len = string_len = 0;
1442 missed = 0;
1444 if (total > 0) {
1445 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1449 char *lastname=NULL;
1451 for (i=0;i<total;i++) {
1452 struct srv_info_struct *s = &servers[i];
1454 if (lastname && strequal(lastname,s->name)) {
1455 continue;
1457 lastname = s->name;
1458 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1459 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1460 i, s->name, s->type, s->comment, s->domain));
1462 if (data_len < buf_len) {
1463 counted++;
1464 fixed_len += f_len;
1465 string_len += s_len;
1466 } else {
1467 missed++;
1472 *rdata_len = fixed_len + string_len;
1473 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1474 if (!*rdata) {
1475 return False;
1478 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1479 p = *rdata;
1480 f_len = fixed_len;
1481 s_len = string_len;
1484 char *lastname=NULL;
1485 int count2 = counted;
1487 for (i = 0; i < total && count2;i++) {
1488 struct srv_info_struct *s = &servers[i];
1490 if (lastname && strequal(lastname,s->name)) {
1491 continue;
1493 lastname = s->name;
1494 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1495 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1496 i, s->name, s->type, s->comment, s->domain));
1497 count2--;
1501 *rparam_len = 8;
1502 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1503 if (!*rparam) {
1504 return False;
1506 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1507 SSVAL(*rparam,2,0);
1508 SSVAL(*rparam,4,counted);
1509 SSVAL(*rparam,6,counted+missed);
1511 SAFE_FREE(servers);
1513 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1514 domain,uLevel,counted,counted+missed));
1516 return True;
1519 static int srv_name_match(const char *n1, const char *n2)
1522 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1524 * In Windows, FirstNameToReturn need not be an exact match:
1525 * the server will return a list of servers that exist on
1526 * the network greater than or equal to the FirstNameToReturn.
1528 int ret = StrCaseCmp(n1, n2);
1530 if (ret <= 0) {
1531 return 0;
1534 return ret;
1537 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1538 char *param, int tpscnt,
1539 char *data, int tdscnt,
1540 int mdrcnt, int mprcnt, char **rdata,
1541 char **rparam, int *rdata_len, int *rparam_len)
1543 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1544 char *str2 = skip_string(param,tpscnt,str1);
1545 char *p = skip_string(param,tpscnt,str2);
1546 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1547 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1548 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1549 char *p2;
1550 int data_len, fixed_len, string_len;
1551 int f_len = 0, s_len = 0;
1552 struct srv_info_struct *servers=NULL;
1553 int counted=0,first=0,total=0;
1554 int i,missed;
1555 fstring domain;
1556 fstring first_name;
1557 bool domain_request;
1558 bool local_request;
1560 if (!str1 || !str2 || !p) {
1561 return False;
1564 /* If someone sets all the bits they don't really mean to set
1565 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1566 known servers. */
1568 if (servertype == SV_TYPE_ALL) {
1569 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1572 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1573 any other bit (they may just set this bit on its own) they
1574 want all the locally seen servers. However this bit can be
1575 set on its own so set the requested servers to be
1576 ALL - DOMAIN_ENUM. */
1578 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1579 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1582 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1583 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1585 p += 8;
1587 if (strcmp(str1, "WrLehDzz") != 0) {
1588 return false;
1590 if (!check_server_info(uLevel,str2)) {
1591 return False;
1594 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1595 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1596 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1598 if (skip_string(param,tpscnt,p) == NULL) {
1599 return False;
1601 pull_ascii_fstring(domain, p);
1602 if (domain[0] == '\0') {
1603 fstrcpy(domain, lp_workgroup());
1605 p = skip_string(param,tpscnt,p);
1606 if (skip_string(param,tpscnt,p) == NULL) {
1607 return False;
1609 pull_ascii_fstring(first_name, p);
1611 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1612 domain, first_name));
1614 if (lp_browse_list()) {
1615 total = get_server_info(servertype,&servers,domain);
1618 data_len = fixed_len = string_len = 0;
1619 missed = 0;
1621 if (total > 0) {
1622 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1625 if (first_name[0] != '\0') {
1626 struct srv_info_struct *first_server = NULL;
1628 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1629 srv_name_match, first_server);
1630 if (first_server) {
1631 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1633 * The binary search may not find the exact match
1634 * so we need to search backward to find the first match
1636 * This implements the strange matching windows
1637 * implements. (see the comment in srv_name_match().
1639 for (;first > 0;) {
1640 int ret;
1641 ret = StrCaseCmp(first_name,
1642 servers[first-1].name);
1643 if (ret > 0) {
1644 break;
1646 first--;
1648 } else {
1649 /* we should return no entries */
1650 first = total;
1655 char *lastname=NULL;
1657 for (i=first;i<total;i++) {
1658 struct srv_info_struct *s = &servers[i];
1660 if (lastname && strequal(lastname,s->name)) {
1661 continue;
1663 lastname = s->name;
1664 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1665 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1666 i, s->name, s->type, s->comment, s->domain));
1668 if (data_len < buf_len) {
1669 counted++;
1670 fixed_len += f_len;
1671 string_len += s_len;
1672 } else {
1673 missed++;
1678 *rdata_len = fixed_len + string_len;
1679 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1680 if (!*rdata) {
1681 return False;
1684 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1685 p = *rdata;
1686 f_len = fixed_len;
1687 s_len = string_len;
1690 char *lastname=NULL;
1691 int count2 = counted;
1693 for (i = first; i < total && count2;i++) {
1694 struct srv_info_struct *s = &servers[i];
1696 if (lastname && strequal(lastname,s->name)) {
1697 continue;
1699 lastname = s->name;
1700 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1701 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1702 i, s->name, s->type, s->comment, s->domain));
1703 count2--;
1707 *rparam_len = 8;
1708 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1709 if (!*rparam) {
1710 return False;
1712 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1713 SSVAL(*rparam,2,0);
1714 SSVAL(*rparam,4,counted);
1715 SSVAL(*rparam,6,counted+missed);
1717 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1718 domain,uLevel,first,first_name,
1719 first < total ? servers[first].name : "",
1720 counted,counted+missed));
1722 SAFE_FREE(servers);
1724 return True;
1727 /****************************************************************************
1728 command 0x34 - suspected of being a "Lookup Names" stub api
1729 ****************************************************************************/
1731 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1732 char *param, int tpscnt,
1733 char *data, int tdscnt,
1734 int mdrcnt, int mprcnt, char **rdata,
1735 char **rparam, int *rdata_len, int *rparam_len)
1737 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1738 char *str2 = skip_string(param,tpscnt,str1);
1739 char *p = skip_string(param,tpscnt,str2);
1740 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1741 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1742 int counted=0;
1743 int missed=0;
1745 if (!str1 || !str2 || !p) {
1746 return False;
1749 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1750 str1, str2, p, uLevel, buf_len));
1752 if (!prefix_ok(str1,"zWrLeh")) {
1753 return False;
1756 *rdata_len = 0;
1758 *rparam_len = 8;
1759 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1760 if (!*rparam) {
1761 return False;
1764 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1765 SSVAL(*rparam,2,0);
1766 SSVAL(*rparam,4,counted);
1767 SSVAL(*rparam,6,counted+missed);
1769 return True;
1772 /****************************************************************************
1773 get info about a share
1774 ****************************************************************************/
1776 static bool check_share_info(int uLevel, char* id)
1778 switch( uLevel ) {
1779 case 0:
1780 if (strcmp(id,"B13") != 0) {
1781 return False;
1783 break;
1784 case 1:
1785 if (strcmp(id,"B13BWz") != 0) {
1786 return False;
1788 break;
1789 case 2:
1790 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1791 return False;
1793 break;
1794 case 91:
1795 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1796 return False;
1798 break;
1799 default:
1800 return False;
1802 return True;
1805 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1806 char** buf, int* buflen,
1807 char** stringbuf, int* stringspace, char* baseaddr)
1809 int struct_len;
1810 char* p;
1811 char* p2;
1812 int l2;
1813 int len;
1815 switch( uLevel ) {
1816 case 0:
1817 struct_len = 13;
1818 break;
1819 case 1:
1820 struct_len = 20;
1821 break;
1822 case 2:
1823 struct_len = 40;
1824 break;
1825 case 91:
1826 struct_len = 68;
1827 break;
1828 default:
1829 return -1;
1832 if (!buf) {
1833 len = 0;
1835 if (uLevel > 0) {
1836 len += StrlenExpanded(conn,snum,lp_comment(snum));
1838 if (uLevel > 1) {
1839 len += strlen(lp_pathname(snum)) + 1;
1841 if (buflen) {
1842 *buflen = struct_len;
1844 if (stringspace) {
1845 *stringspace = len;
1847 return struct_len + len;
1850 len = struct_len;
1851 p = *buf;
1852 if ((*buflen) < struct_len) {
1853 return -1;
1856 if (stringbuf) {
1857 p2 = *stringbuf;
1858 l2 = *stringspace;
1859 } else {
1860 p2 = p + struct_len;
1861 l2 = (*buflen) - struct_len;
1864 if (!baseaddr) {
1865 baseaddr = p;
1868 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1870 if (uLevel > 0) {
1871 int type;
1873 SCVAL(p,13,0);
1874 type = STYPE_DISKTREE;
1875 if (lp_print_ok(snum)) {
1876 type = STYPE_PRINTQ;
1878 if (strequal("IPC",lp_fstype(snum))) {
1879 type = STYPE_IPC;
1881 SSVAL(p,14,type); /* device type */
1882 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1883 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1886 if (uLevel > 1) {
1887 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1888 SSVALS(p,22,-1); /* max uses */
1889 SSVAL(p,24,1); /* current uses */
1890 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1891 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1892 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1895 if (uLevel > 2) {
1896 memset(p+40,0,SHPWLEN+2);
1897 SSVAL(p,50,0);
1898 SIVAL(p,52,0);
1899 SSVAL(p,56,0);
1900 SSVAL(p,58,0);
1901 SIVAL(p,60,0);
1902 SSVAL(p,64,0);
1903 SSVAL(p,66,0);
1906 if (stringbuf) {
1907 (*buf) = p + struct_len;
1908 (*buflen) -= struct_len;
1909 (*stringbuf) = p2;
1910 (*stringspace) = l2;
1911 } else {
1912 (*buf) = p2;
1913 (*buflen) -= len;
1916 return len;
1919 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1920 char *param, int tpscnt,
1921 char *data, int tdscnt,
1922 int mdrcnt,int mprcnt,
1923 char **rdata,char **rparam,
1924 int *rdata_len,int *rparam_len)
1926 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1927 char *str2 = skip_string(param,tpscnt,str1);
1928 char *netname = skip_string(param,tpscnt,str2);
1929 char *p = skip_string(param,tpscnt,netname);
1930 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1931 int snum;
1933 if (!str1 || !str2 || !netname || !p) {
1934 return False;
1937 snum = find_service(netname);
1938 if (snum < 0) {
1939 return False;
1942 /* check it's a supported varient */
1943 if (!prefix_ok(str1,"zWrLh")) {
1944 return False;
1946 if (!check_share_info(uLevel,str2)) {
1947 return False;
1950 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1951 if (!*rdata) {
1952 return False;
1954 p = *rdata;
1955 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1956 if (*rdata_len < 0) {
1957 return False;
1960 *rparam_len = 6;
1961 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1962 if (!*rparam) {
1963 return False;
1965 SSVAL(*rparam,0,NERR_Success);
1966 SSVAL(*rparam,2,0); /* converter word */
1967 SSVAL(*rparam,4,*rdata_len);
1969 return True;
1972 /****************************************************************************
1973 View the list of available shares.
1975 This function is the server side of the NetShareEnum() RAP call.
1976 It fills the return buffer with share names and share comments.
1977 Note that the return buffer normally (in all known cases) allows only
1978 twelve byte strings for share names (plus one for a nul terminator).
1979 Share names longer than 12 bytes must be skipped.
1980 ****************************************************************************/
1982 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1983 char *param, int tpscnt,
1984 char *data, int tdscnt,
1985 int mdrcnt,
1986 int mprcnt,
1987 char **rdata,
1988 char **rparam,
1989 int *rdata_len,
1990 int *rparam_len )
1992 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1993 char *str2 = skip_string(param,tpscnt,str1);
1994 char *p = skip_string(param,tpscnt,str2);
1995 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1996 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1997 char *p2;
1998 int count = 0;
1999 int total=0,counted=0;
2000 bool missed = False;
2001 int i;
2002 int data_len, fixed_len, string_len;
2003 int f_len = 0, s_len = 0;
2005 if (!str1 || !str2 || !p) {
2006 return False;
2009 if (!prefix_ok(str1,"WrLeh")) {
2010 return False;
2012 if (!check_share_info(uLevel,str2)) {
2013 return False;
2016 /* Ensure all the usershares are loaded. */
2017 become_root();
2018 load_registry_shares();
2019 count = load_usershare_shares();
2020 unbecome_root();
2022 data_len = fixed_len = string_len = 0;
2023 for (i=0;i<count;i++) {
2024 fstring servicename_dos;
2025 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2026 continue;
2028 push_ascii_fstring(servicename_dos, lp_servicename(i));
2029 /* Maximum name length = 13. */
2030 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2031 total++;
2032 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2033 if (data_len < buf_len) {
2034 counted++;
2035 fixed_len += f_len;
2036 string_len += s_len;
2037 } else {
2038 missed = True;
2043 *rdata_len = fixed_len + string_len;
2044 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2045 if (!*rdata) {
2046 return False;
2049 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2050 p = *rdata;
2051 f_len = fixed_len;
2052 s_len = string_len;
2054 for( i = 0; i < count; i++ ) {
2055 fstring servicename_dos;
2056 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2057 continue;
2060 push_ascii_fstring(servicename_dos, lp_servicename(i));
2061 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2062 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2063 break;
2068 *rparam_len = 8;
2069 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2070 if (!*rparam) {
2071 return False;
2073 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2074 SSVAL(*rparam,2,0);
2075 SSVAL(*rparam,4,counted);
2076 SSVAL(*rparam,6,total);
2078 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2079 counted,total,uLevel,
2080 buf_len,*rdata_len,mdrcnt));
2082 return True;
2085 /****************************************************************************
2086 Add a share
2087 ****************************************************************************/
2089 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2090 char *param, int tpscnt,
2091 char *data, int tdscnt,
2092 int mdrcnt,int mprcnt,
2093 char **rdata,char **rparam,
2094 int *rdata_len,int *rparam_len)
2096 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2097 char *str2 = skip_string(param,tpscnt,str1);
2098 char *p = skip_string(param,tpscnt,str2);
2099 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2100 fstring sharename;
2101 fstring comment;
2102 char *pathname = NULL;
2103 char *command, *cmdname;
2104 unsigned int offset;
2105 int snum;
2106 int res = ERRunsup;
2107 size_t converted_size;
2109 if (!str1 || !str2 || !p) {
2110 return False;
2113 /* check it's a supported varient */
2114 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2115 return False;
2117 if (!check_share_info(uLevel,str2)) {
2118 return False;
2120 if (uLevel != 2) {
2121 return False;
2124 /* Do we have a string ? */
2125 if (skip_string(data,mdrcnt,data) == NULL) {
2126 return False;
2128 pull_ascii_fstring(sharename,data);
2129 snum = find_service(sharename);
2130 if (snum >= 0) { /* already exists */
2131 res = ERRfilexists;
2132 goto error_exit;
2135 if (mdrcnt < 28) {
2136 return False;
2139 /* only support disk share adds */
2140 if (SVAL(data,14)!=STYPE_DISKTREE) {
2141 return False;
2144 offset = IVAL(data, 16);
2145 if (offset >= mdrcnt) {
2146 res = ERRinvalidparam;
2147 goto error_exit;
2150 /* Do we have a string ? */
2151 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2152 return False;
2154 pull_ascii_fstring(comment, offset? (data+offset) : "");
2156 offset = IVAL(data, 26);
2158 if (offset >= mdrcnt) {
2159 res = ERRinvalidparam;
2160 goto error_exit;
2163 /* Do we have a string ? */
2164 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2165 return False;
2168 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2169 offset ? (data+offset) : "", &converted_size))
2171 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2172 strerror(errno)));
2175 if (!pathname) {
2176 return false;
2179 string_replace(sharename, '"', ' ');
2180 string_replace(pathname, '"', ' ');
2181 string_replace(comment, '"', ' ');
2183 cmdname = lp_add_share_cmd();
2185 if (!cmdname || *cmdname == '\0') {
2186 return False;
2189 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
2190 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
2191 pathname, comment) == -1) {
2192 return false;
2195 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
2197 if ((res = smbrun(command, NULL)) != 0) {
2198 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
2199 command, res ));
2200 SAFE_FREE(command);
2201 res = ERRnoaccess;
2202 goto error_exit;
2203 } else {
2204 SAFE_FREE(command);
2205 message_send_all(smbd_messaging_context(),
2206 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2209 *rparam_len = 6;
2210 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2211 if (!*rparam) {
2212 return False;
2214 SSVAL(*rparam,0,NERR_Success);
2215 SSVAL(*rparam,2,0); /* converter word */
2216 SSVAL(*rparam,4,*rdata_len);
2217 *rdata_len = 0;
2219 return True;
2221 error_exit:
2223 *rparam_len = 4;
2224 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2225 if (!*rparam) {
2226 return False;
2228 *rdata_len = 0;
2229 SSVAL(*rparam,0,res);
2230 SSVAL(*rparam,2,0);
2231 return True;
2234 /****************************************************************************
2235 view list of groups available
2236 ****************************************************************************/
2238 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2239 char *param, int tpscnt,
2240 char *data, int tdscnt,
2241 int mdrcnt,int mprcnt,
2242 char **rdata,char **rparam,
2243 int *rdata_len,int *rparam_len)
2245 int i;
2246 int errflags=0;
2247 int resume_context, cli_buf_size;
2248 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2249 char *str2 = skip_string(param,tpscnt,str1);
2250 char *p = skip_string(param,tpscnt,str2);
2252 uint32_t num_groups;
2253 uint32_t resume_handle;
2254 struct rpc_pipe_client *samr_pipe;
2255 struct policy_handle samr_handle, domain_handle;
2256 NTSTATUS status;
2258 if (!str1 || !str2 || !p) {
2259 return False;
2262 if (strcmp(str1,"WrLeh") != 0) {
2263 return False;
2266 /* parameters
2267 * W-> resume context (number of users to skip)
2268 * r -> return parameter pointer to receive buffer
2269 * L -> length of receive buffer
2270 * e -> return parameter number of entries
2271 * h -> return parameter total number of users
2274 if (strcmp("B21",str2) != 0) {
2275 return False;
2278 status = rpc_pipe_open_internal(
2279 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2280 conn->server_info, &samr_pipe);
2281 if (!NT_STATUS_IS_OK(status)) {
2282 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2283 nt_errstr(status)));
2284 return false;
2287 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2288 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2289 if (!NT_STATUS_IS_OK(status)) {
2290 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2291 nt_errstr(status)));
2292 return false;
2295 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2296 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2297 get_global_sam_sid(), &domain_handle);
2298 if (!NT_STATUS_IS_OK(status)) {
2299 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2300 nt_errstr(status)));
2301 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2302 return false;
2305 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2306 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2307 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2308 "%d\n", resume_context, cli_buf_size));
2310 *rdata_len = cli_buf_size;
2311 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2312 if (!*rdata) {
2313 return False;
2316 p = *rdata;
2318 errflags = NERR_Success;
2319 num_groups = 0;
2320 resume_handle = 0;
2322 while (true) {
2323 struct samr_SamArray *sam_entries;
2324 uint32_t num_entries;
2326 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2327 &domain_handle,
2328 &resume_handle,
2329 &sam_entries, 1,
2330 &num_entries);
2331 if (!NT_STATUS_IS_OK(status)) {
2332 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2333 "%s\n", nt_errstr(status)));
2334 break;
2337 if (num_entries == 0) {
2338 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2339 "no entries -- done\n"));
2340 break;
2343 for(i=0; i<num_entries; i++) {
2344 const char *name;
2346 name = sam_entries->entries[i].name.string;
2348 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2349 /* set overflow error */
2350 DEBUG(3,("overflow on entry %d group %s\n", i,
2351 name));
2352 errflags=234;
2353 break;
2356 /* truncate the name at 21 chars. */
2357 memset(p, 0, 21);
2358 strlcpy(p, name, 21);
2359 DEBUG(10,("adding entry %d group %s\n", i, p));
2360 p += 21;
2361 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2362 * idea why... */
2363 num_groups += 1;
2366 if (errflags != NERR_Success) {
2367 break;
2370 TALLOC_FREE(sam_entries);
2373 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2374 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2376 *rdata_len = PTR_DIFF(p,*rdata);
2378 *rparam_len = 8;
2379 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2380 if (!*rparam) {
2381 return False;
2383 SSVAL(*rparam, 0, errflags);
2384 SSVAL(*rparam, 2, 0); /* converter word */
2385 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2386 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2388 return(True);
2391 /*******************************************************************
2392 Get groups that a user is a member of.
2393 ******************************************************************/
2395 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2396 char *param, int tpscnt,
2397 char *data, int tdscnt,
2398 int mdrcnt,int mprcnt,
2399 char **rdata,char **rparam,
2400 int *rdata_len,int *rparam_len)
2402 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2403 char *str2 = skip_string(param,tpscnt,str1);
2404 char *UserName = skip_string(param,tpscnt,str2);
2405 char *p = skip_string(param,tpscnt,UserName);
2406 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2407 const char *level_string;
2408 int count=0;
2409 bool ret = False;
2410 uint32_t i;
2411 char *endp = NULL;
2413 struct rpc_pipe_client *samr_pipe;
2414 struct policy_handle samr_handle, domain_handle, user_handle;
2415 struct lsa_String name;
2416 struct lsa_Strings names;
2417 struct samr_Ids type, rid;
2418 struct samr_RidWithAttributeArray *rids;
2419 NTSTATUS status;
2421 if (!str1 || !str2 || !UserName || !p) {
2422 return False;
2425 *rparam_len = 8;
2426 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2427 if (!*rparam) {
2428 return False;
2431 /* check it's a supported varient */
2433 if ( strcmp(str1,"zWrLeh") != 0 )
2434 return False;
2436 switch( uLevel ) {
2437 case 0:
2438 level_string = "B21";
2439 break;
2440 default:
2441 return False;
2444 if (strcmp(level_string,str2) != 0)
2445 return False;
2447 *rdata_len = mdrcnt + 1024;
2448 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2449 if (!*rdata) {
2450 return False;
2453 SSVAL(*rparam,0,NERR_Success);
2454 SSVAL(*rparam,2,0); /* converter word */
2456 p = *rdata;
2457 endp = *rdata + *rdata_len;
2459 status = rpc_pipe_open_internal(
2460 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2461 conn->server_info, &samr_pipe);
2462 if (!NT_STATUS_IS_OK(status)) {
2463 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2464 nt_errstr(status)));
2465 return false;
2468 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2469 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2470 if (!NT_STATUS_IS_OK(status)) {
2471 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2472 nt_errstr(status)));
2473 return false;
2476 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2477 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2478 get_global_sam_sid(), &domain_handle);
2479 if (!NT_STATUS_IS_OK(status)) {
2480 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2481 nt_errstr(status)));
2482 goto close_sam;
2485 name.string = UserName;
2487 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2488 &domain_handle, 1, &name,
2489 &rid, &type);
2490 if (!NT_STATUS_IS_OK(status)) {
2491 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2492 nt_errstr(status)));
2493 goto close_domain;
2496 if (type.ids[0] != SID_NAME_USER) {
2497 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2498 sid_type_lookup(type.ids[0])));
2499 goto close_domain;
2502 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2503 &domain_handle,
2504 SAMR_USER_ACCESS_GET_GROUPS,
2505 rid.ids[0], &user_handle);
2506 if (!NT_STATUS_IS_OK(status)) {
2507 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2508 nt_errstr(status)));
2509 goto close_domain;
2512 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2513 &user_handle, &rids);
2514 if (!NT_STATUS_IS_OK(status)) {
2515 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2516 nt_errstr(status)));
2517 goto close_user;
2520 for (i=0; i<rids->count; i++) {
2522 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2523 &domain_handle,
2524 1, &rids->rids[i].rid,
2525 &names, &type);
2526 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2527 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2528 p += 21;
2529 count++;
2533 *rdata_len = PTR_DIFF(p,*rdata);
2535 SSVAL(*rparam,4,count); /* is this right?? */
2536 SSVAL(*rparam,6,count); /* is this right?? */
2538 ret = True;
2540 close_user:
2541 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2542 close_domain:
2543 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2544 close_sam:
2545 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2547 return ret;
2550 /*******************************************************************
2551 Get all users.
2552 ******************************************************************/
2554 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2555 char *param, int tpscnt,
2556 char *data, int tdscnt,
2557 int mdrcnt,int mprcnt,
2558 char **rdata,char **rparam,
2559 int *rdata_len,int *rparam_len)
2561 int count_sent=0;
2562 int num_users=0;
2563 int errflags=0;
2564 int i, resume_context, cli_buf_size;
2565 uint32_t resume_handle;
2567 struct rpc_pipe_client *samr_pipe;
2568 struct policy_handle samr_handle, domain_handle;
2569 NTSTATUS status;
2571 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2572 char *str2 = skip_string(param,tpscnt,str1);
2573 char *p = skip_string(param,tpscnt,str2);
2574 char *endp = NULL;
2576 if (!str1 || !str2 || !p) {
2577 return False;
2580 if (strcmp(str1,"WrLeh") != 0)
2581 return False;
2582 /* parameters
2583 * W-> resume context (number of users to skip)
2584 * r -> return parameter pointer to receive buffer
2585 * L -> length of receive buffer
2586 * e -> return parameter number of entries
2587 * h -> return parameter total number of users
2590 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2591 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2592 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2593 resume_context, cli_buf_size));
2595 *rparam_len = 8;
2596 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2597 if (!*rparam) {
2598 return False;
2601 /* check it's a supported varient */
2602 if (strcmp("B21",str2) != 0)
2603 return False;
2605 *rdata_len = cli_buf_size;
2606 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2607 if (!*rdata) {
2608 return False;
2611 p = *rdata;
2612 endp = *rdata + *rdata_len;
2614 status = rpc_pipe_open_internal(
2615 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2616 conn->server_info, &samr_pipe);
2617 if (!NT_STATUS_IS_OK(status)) {
2618 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2619 nt_errstr(status)));
2620 return false;
2623 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2624 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2625 if (!NT_STATUS_IS_OK(status)) {
2626 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2627 nt_errstr(status)));
2628 return false;
2631 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2632 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2633 get_global_sam_sid(), &domain_handle);
2634 if (!NT_STATUS_IS_OK(status)) {
2635 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2636 nt_errstr(status)));
2637 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2638 return false;
2641 errflags=NERR_Success;
2643 resume_handle = 0;
2645 while (true) {
2646 struct samr_SamArray *sam_entries;
2647 uint32_t num_entries;
2649 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2650 &domain_handle,
2651 &resume_handle,
2652 0, &sam_entries, 1,
2653 &num_entries);
2655 if (!NT_STATUS_IS_OK(status)) {
2656 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2657 "%s\n", nt_errstr(status)));
2658 break;
2661 if (num_entries == 0) {
2662 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2663 "no entries -- done\n"));
2664 break;
2667 for (i=0; i<num_entries; i++) {
2668 const char *name;
2670 name = sam_entries->entries[i].name.string;
2672 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2673 &&(strlen(name)<=21)) {
2674 strlcpy(p,name,PTR_DIFF(endp,p));
2675 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2676 "username %s\n",count_sent,p));
2677 p += 21;
2678 count_sent++;
2679 } else {
2680 /* set overflow error */
2681 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2682 "username %s\n",count_sent,name));
2683 errflags=234;
2684 break;
2688 if (errflags != NERR_Success) {
2689 break;
2692 TALLOC_FREE(sam_entries);
2695 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2696 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2698 *rdata_len = PTR_DIFF(p,*rdata);
2700 SSVAL(*rparam,0,errflags);
2701 SSVAL(*rparam,2,0); /* converter word */
2702 SSVAL(*rparam,4,count_sent); /* is this right?? */
2703 SSVAL(*rparam,6,num_users); /* is this right?? */
2705 return True;
2708 /****************************************************************************
2709 Get the time of day info.
2710 ****************************************************************************/
2712 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2713 char *param, int tpscnt,
2714 char *data, int tdscnt,
2715 int mdrcnt,int mprcnt,
2716 char **rdata,char **rparam,
2717 int *rdata_len,int *rparam_len)
2719 struct tm *t;
2720 time_t unixdate = time(NULL);
2721 char *p;
2723 *rparam_len = 4;
2724 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2725 if (!*rparam) {
2726 return False;
2729 *rdata_len = 21;
2730 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2731 if (!*rdata) {
2732 return False;
2735 SSVAL(*rparam,0,NERR_Success);
2736 SSVAL(*rparam,2,0); /* converter word */
2738 p = *rdata;
2740 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2741 by NT in a "net time" operation,
2742 it seems to ignore the one below */
2744 /* the client expects to get localtime, not GMT, in this bit
2745 (I think, this needs testing) */
2746 t = localtime(&unixdate);
2747 if (!t) {
2748 return False;
2751 SIVAL(p,4,0); /* msecs ? */
2752 SCVAL(p,8,t->tm_hour);
2753 SCVAL(p,9,t->tm_min);
2754 SCVAL(p,10,t->tm_sec);
2755 SCVAL(p,11,0); /* hundredths of seconds */
2756 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2757 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2758 SCVAL(p,16,t->tm_mday);
2759 SCVAL(p,17,t->tm_mon + 1);
2760 SSVAL(p,18,1900+t->tm_year);
2761 SCVAL(p,20,t->tm_wday);
2763 return True;
2766 /****************************************************************************
2767 Set the user password.
2768 *****************************************************************************/
2770 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2771 char *param, int tpscnt,
2772 char *data, int tdscnt,
2773 int mdrcnt,int mprcnt,
2774 char **rdata,char **rparam,
2775 int *rdata_len,int *rparam_len)
2777 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2778 char *p = NULL;
2779 fstring user;
2780 fstring pass1,pass2;
2782 /* Skip 2 strings. */
2783 p = skip_string(param,tpscnt,np);
2784 p = skip_string(param,tpscnt,p);
2786 if (!np || !p) {
2787 return False;
2790 /* Do we have a string ? */
2791 if (skip_string(param,tpscnt,p) == NULL) {
2792 return False;
2794 pull_ascii_fstring(user,p);
2796 p = skip_string(param,tpscnt,p);
2797 if (!p) {
2798 return False;
2801 memset(pass1,'\0',sizeof(pass1));
2802 memset(pass2,'\0',sizeof(pass2));
2804 * We use 31 here not 32 as we're checking
2805 * the last byte we want to access is safe.
2807 if (!is_offset_safe(param,tpscnt,p,31)) {
2808 return False;
2810 memcpy(pass1,p,16);
2811 memcpy(pass2,p+16,16);
2813 *rparam_len = 4;
2814 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2815 if (!*rparam) {
2816 return False;
2819 *rdata_len = 0;
2821 SSVAL(*rparam,0,NERR_badpass);
2822 SSVAL(*rparam,2,0); /* converter word */
2824 DEBUG(3,("Set password for <%s>\n",user));
2827 * Attempt to verify the old password against smbpasswd entries
2828 * Win98 clients send old and new password in plaintext for this call.
2832 auth_serversupplied_info *server_info = NULL;
2833 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2835 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2837 become_root();
2838 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2839 SSVAL(*rparam,0,NERR_Success);
2841 unbecome_root();
2843 TALLOC_FREE(server_info);
2845 data_blob_clear_free(&password);
2849 * If the plaintext change failed, attempt
2850 * the old encrypted method. NT will generate this
2851 * after trying the samr method. Note that this
2852 * method is done as a last resort as this
2853 * password change method loses the NT password hash
2854 * and cannot change the UNIX password as no plaintext
2855 * is received.
2858 if(SVAL(*rparam,0) != NERR_Success) {
2859 struct samu *hnd = NULL;
2861 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2862 become_root();
2863 if (change_lanman_password(hnd,(uchar *)pass2)) {
2864 SSVAL(*rparam,0,NERR_Success);
2866 unbecome_root();
2867 TALLOC_FREE(hnd);
2871 memset((char *)pass1,'\0',sizeof(fstring));
2872 memset((char *)pass2,'\0',sizeof(fstring));
2874 return(True);
2877 /****************************************************************************
2878 Set the user password (SamOEM version - gets plaintext).
2879 ****************************************************************************/
2881 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2882 char *param, int tpscnt,
2883 char *data, int tdscnt,
2884 int mdrcnt,int mprcnt,
2885 char **rdata,char **rparam,
2886 int *rdata_len,int *rparam_len)
2888 fstring user;
2889 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2890 *rparam_len = 2;
2891 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2892 if (!*rparam) {
2893 return False;
2896 if (!p) {
2897 return False;
2899 *rdata_len = 0;
2901 SSVAL(*rparam,0,NERR_badpass);
2904 * Check the parameter definition is correct.
2907 /* Do we have a string ? */
2908 if (skip_string(param,tpscnt,p) == 0) {
2909 return False;
2911 if(!strequal(p, "zsT")) {
2912 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2913 return False;
2915 p = skip_string(param, tpscnt, p);
2916 if (!p) {
2917 return False;
2920 /* Do we have a string ? */
2921 if (skip_string(param,tpscnt,p) == 0) {
2922 return False;
2924 if(!strequal(p, "B516B16")) {
2925 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2926 return False;
2928 p = skip_string(param,tpscnt,p);
2929 if (!p) {
2930 return False;
2932 /* Do we have a string ? */
2933 if (skip_string(param,tpscnt,p) == 0) {
2934 return False;
2936 p += pull_ascii_fstring(user,p);
2938 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2941 * Pass the user through the NT -> unix user mapping
2942 * function.
2945 (void)map_username(user);
2947 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2948 SSVAL(*rparam,0,NERR_Success);
2951 return(True);
2954 /****************************************************************************
2955 delete a print job
2956 Form: <W> <>
2957 ****************************************************************************/
2959 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2960 char *param, int tpscnt,
2961 char *data, int tdscnt,
2962 int mdrcnt,int mprcnt,
2963 char **rdata,char **rparam,
2964 int *rdata_len,int *rparam_len)
2966 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2967 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2968 char *str2 = skip_string(param,tpscnt,str1);
2969 char *p = skip_string(param,tpscnt,str2);
2970 uint32 jobid;
2971 int snum;
2972 fstring sharename;
2973 int errcode;
2974 WERROR werr = WERR_OK;
2976 if (!str1 || !str2 || !p) {
2977 return False;
2980 * We use 1 here not 2 as we're checking
2981 * the last byte we want to access is safe.
2983 if (!is_offset_safe(param,tpscnt,p,1)) {
2984 return False;
2986 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2987 return False;
2989 /* check it's a supported varient */
2990 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2991 return(False);
2993 *rparam_len = 4;
2994 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2995 if (!*rparam) {
2996 return False;
2998 *rdata_len = 0;
3000 if (!print_job_exists(sharename, jobid)) {
3001 errcode = NERR_JobNotFound;
3002 goto out;
3005 snum = lp_servicenumber( sharename);
3006 if (snum == -1) {
3007 errcode = NERR_DestNotFound;
3008 goto out;
3011 errcode = NERR_notsupported;
3013 switch (function) {
3014 case 81: /* delete */
3015 if (print_job_delete(conn->server_info, snum, jobid, &werr))
3016 errcode = NERR_Success;
3017 break;
3018 case 82: /* pause */
3019 if (print_job_pause(conn->server_info, snum, jobid, &werr))
3020 errcode = NERR_Success;
3021 break;
3022 case 83: /* resume */
3023 if (print_job_resume(conn->server_info, snum, jobid, &werr))
3024 errcode = NERR_Success;
3025 break;
3028 if (!W_ERROR_IS_OK(werr))
3029 errcode = W_ERROR_V(werr);
3031 out:
3032 SSVAL(*rparam,0,errcode);
3033 SSVAL(*rparam,2,0); /* converter word */
3035 return(True);
3038 /****************************************************************************
3039 Purge a print queue - or pause or resume it.
3040 ****************************************************************************/
3042 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3043 char *param, int tpscnt,
3044 char *data, int tdscnt,
3045 int mdrcnt,int mprcnt,
3046 char **rdata,char **rparam,
3047 int *rdata_len,int *rparam_len)
3049 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3050 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3051 char *str2 = skip_string(param,tpscnt,str1);
3052 char *QueueName = skip_string(param,tpscnt,str2);
3053 int errcode = NERR_notsupported;
3054 int snum;
3055 WERROR werr = WERR_OK;
3057 if (!str1 || !str2 || !QueueName) {
3058 return False;
3061 /* check it's a supported varient */
3062 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3063 return(False);
3065 *rparam_len = 4;
3066 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3067 if (!*rparam) {
3068 return False;
3070 *rdata_len = 0;
3072 if (skip_string(param,tpscnt,QueueName) == NULL) {
3073 return False;
3075 snum = print_queue_snum(QueueName);
3077 if (snum == -1) {
3078 errcode = NERR_JobNotFound;
3079 goto out;
3082 switch (function) {
3083 case 74: /* Pause queue */
3084 werr = print_queue_pause(conn->server_info, snum);
3085 break;
3086 case 75: /* Resume queue */
3087 werr = print_queue_resume(conn->server_info, snum);
3088 break;
3089 case 103: /* Purge */
3090 werr = print_queue_purge(conn->server_info, snum);
3091 break;
3092 default:
3093 werr = WERR_NOT_SUPPORTED;
3094 break;
3097 errcode = W_ERROR_V(werr);
3099 out:
3100 SSVAL(*rparam,0,errcode);
3101 SSVAL(*rparam,2,0); /* converter word */
3103 return(True);
3106 /****************************************************************************
3107 set the property of a print job (undocumented?)
3108 ? function = 0xb -> set name of print job
3109 ? function = 0x6 -> move print job up/down
3110 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3111 or <WWsTP> <WB21BB16B10zWWzDDz>
3112 ****************************************************************************/
3114 static int check_printjob_info(struct pack_desc* desc,
3115 int uLevel, char* id)
3117 desc->subformat = NULL;
3118 switch( uLevel ) {
3119 case 0: desc->format = "W"; break;
3120 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3121 case 2: desc->format = "WWzWWDDzz"; break;
3122 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3123 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3124 default:
3125 DEBUG(0,("check_printjob_info: invalid level %d\n",
3126 uLevel ));
3127 return False;
3129 if (id == NULL || strcmp(desc->format,id) != 0) {
3130 DEBUG(0,("check_printjob_info: invalid format %s\n",
3131 id ? id : "<NULL>" ));
3132 return False;
3134 return True;
3137 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3138 char *param, int tpscnt,
3139 char *data, int tdscnt,
3140 int mdrcnt,int mprcnt,
3141 char **rdata,char **rparam,
3142 int *rdata_len,int *rparam_len)
3144 struct pack_desc desc;
3145 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3146 char *str2 = skip_string(param,tpscnt,str1);
3147 char *p = skip_string(param,tpscnt,str2);
3148 uint32 jobid;
3149 fstring sharename;
3150 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3151 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3152 int place, errcode;
3154 if (!str1 || !str2 || !p) {
3155 return False;
3158 * We use 1 here not 2 as we're checking
3159 * the last byte we want to access is safe.
3161 if (!is_offset_safe(param,tpscnt,p,1)) {
3162 return False;
3164 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3165 return False;
3166 *rparam_len = 4;
3167 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3168 if (!*rparam) {
3169 return False;
3172 if (!share_defined(sharename)) {
3173 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
3174 sharename));
3175 return False;
3178 *rdata_len = 0;
3180 /* check it's a supported varient */
3181 if ((strcmp(str1,"WWsTP")) ||
3182 (!check_printjob_info(&desc,uLevel,str2)))
3183 return(False);
3185 if (!print_job_exists(sharename, jobid)) {
3186 errcode=NERR_JobNotFound;
3187 goto out;
3190 errcode = NERR_notsupported;
3192 switch (function) {
3193 case 0x6:
3194 /* change job place in the queue,
3195 data gives the new place */
3196 place = SVAL(data,0);
3197 if (print_job_set_place(sharename, jobid, place)) {
3198 errcode=NERR_Success;
3200 break;
3202 case 0xb:
3203 /* change print job name, data gives the name */
3204 if (print_job_set_name(sharename, jobid, data)) {
3205 errcode=NERR_Success;
3207 break;
3209 default:
3210 return False;
3213 out:
3214 SSVALS(*rparam,0,errcode);
3215 SSVAL(*rparam,2,0); /* converter word */
3217 return(True);
3221 /****************************************************************************
3222 Get info about the server.
3223 ****************************************************************************/
3225 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3226 char *param, int tpscnt,
3227 char *data, int tdscnt,
3228 int mdrcnt,int mprcnt,
3229 char **rdata,char **rparam,
3230 int *rdata_len,int *rparam_len)
3232 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3233 char *str2 = skip_string(param,tpscnt,str1);
3234 char *p = skip_string(param,tpscnt,str2);
3235 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3236 char *p2;
3237 int struct_len;
3239 if (!str1 || !str2 || !p) {
3240 return False;
3243 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3245 /* check it's a supported varient */
3246 if (!prefix_ok(str1,"WrLh")) {
3247 return False;
3250 switch( uLevel ) {
3251 case 0:
3252 if (strcmp(str2,"B16") != 0) {
3253 return False;
3255 struct_len = 16;
3256 break;
3257 case 1:
3258 if (strcmp(str2,"B16BBDz") != 0) {
3259 return False;
3261 struct_len = 26;
3262 break;
3263 case 2:
3264 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3265 return False;
3267 struct_len = 134;
3268 break;
3269 case 3:
3270 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3271 return False;
3273 struct_len = 144;
3274 break;
3275 case 20:
3276 if (strcmp(str2,"DN") != 0) {
3277 return False;
3279 struct_len = 6;
3280 break;
3281 case 50:
3282 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3283 return False;
3285 struct_len = 42;
3286 break;
3287 default:
3288 return False;
3291 *rdata_len = mdrcnt;
3292 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3293 if (!*rdata) {
3294 return False;
3297 p = *rdata;
3298 p2 = p + struct_len;
3299 if (uLevel != 20) {
3300 srvstr_push(NULL, 0, p,global_myname(),16,
3301 STR_ASCII|STR_UPPER|STR_TERMINATE);
3303 p += 16;
3304 if (uLevel > 0) {
3305 struct srv_info_struct *servers=NULL;
3306 int i,count;
3307 char *comment = NULL;
3308 TALLOC_CTX *ctx = talloc_tos();
3309 uint32 servertype= lp_default_server_announce();
3311 comment = talloc_strdup(ctx,lp_serverstring());
3312 if (!comment) {
3313 return false;
3316 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3317 for (i=0;i<count;i++) {
3318 if (strequal(servers[i].name,global_myname())) {
3319 servertype = servers[i].type;
3320 TALLOC_FREE(comment);
3321 comment = talloc_strdup(ctx,
3322 servers[i].comment);
3323 if (comment) {
3324 return false;
3330 SAFE_FREE(servers);
3332 SCVAL(p,0,lp_major_announce_version());
3333 SCVAL(p,1,lp_minor_announce_version());
3334 SIVAL(p,2,servertype);
3336 if (mdrcnt == struct_len) {
3337 SIVAL(p,6,0);
3338 } else {
3339 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3340 comment = talloc_sub_advanced(
3341 ctx,
3342 lp_servicename(SNUM(conn)),
3343 conn->server_info->unix_name,
3344 conn->connectpath,
3345 conn->server_info->utok.gid,
3346 conn->server_info->sanitized_username,
3347 pdb_get_domain(conn->server_info->sam_account),
3348 comment);
3349 if (comment) {
3350 return false;
3352 if (mdrcnt - struct_len <= 0) {
3353 return false;
3355 push_ascii(p2,
3356 comment,
3357 MIN(mdrcnt - struct_len,
3358 MAX_SERVER_STRING_LENGTH),
3359 STR_TERMINATE);
3360 p2 = skip_string(*rdata,*rdata_len,p2);
3361 if (!p2) {
3362 return False;
3367 if (uLevel > 1) {
3368 return False; /* not yet implemented */
3371 *rdata_len = PTR_DIFF(p2,*rdata);
3373 *rparam_len = 6;
3374 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3375 if (!*rparam) {
3376 return False;
3378 SSVAL(*rparam,0,NERR_Success);
3379 SSVAL(*rparam,2,0); /* converter word */
3380 SSVAL(*rparam,4,*rdata_len);
3382 return True;
3385 /****************************************************************************
3386 Get info about the server.
3387 ****************************************************************************/
3389 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3390 char *param, int tpscnt,
3391 char *data, int tdscnt,
3392 int mdrcnt,int mprcnt,
3393 char **rdata,char **rparam,
3394 int *rdata_len,int *rparam_len)
3396 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3397 char *str2 = skip_string(param,tpscnt,str1);
3398 char *p = skip_string(param,tpscnt,str2);
3399 char *p2;
3400 char *endp;
3401 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3403 if (!str1 || !str2 || !p) {
3404 return False;
3407 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3409 *rparam_len = 6;
3410 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3411 if (!*rparam) {
3412 return False;
3415 /* check it's a supported varient */
3416 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3417 return False;
3420 *rdata_len = mdrcnt + 1024;
3421 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3422 if (!*rdata) {
3423 return False;
3426 SSVAL(*rparam,0,NERR_Success);
3427 SSVAL(*rparam,2,0); /* converter word */
3429 p = *rdata;
3430 endp = *rdata + *rdata_len;
3432 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3433 if (!p2) {
3434 return False;
3437 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3438 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3439 strupper_m(p2);
3440 p2 = skip_string(*rdata,*rdata_len,p2);
3441 if (!p2) {
3442 return False;
3444 p += 4;
3446 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3447 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3448 p2 = skip_string(*rdata,*rdata_len,p2);
3449 if (!p2) {
3450 return False;
3452 p += 4;
3454 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3455 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3456 strupper_m(p2);
3457 p2 = skip_string(*rdata,*rdata_len,p2);
3458 if (!p2) {
3459 return False;
3461 p += 4;
3463 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3464 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3465 p += 2;
3467 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3468 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3469 p2 = skip_string(*rdata,*rdata_len,p2);
3470 if (!p2) {
3471 return False;
3473 p += 4;
3475 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3476 strlcpy(p2,"",PTR_DIFF(endp,p2));
3477 p2 = skip_string(*rdata,*rdata_len,p2);
3478 if (!p2) {
3479 return False;
3481 p += 4;
3483 *rdata_len = PTR_DIFF(p2,*rdata);
3485 SSVAL(*rparam,4,*rdata_len);
3487 return True;
3490 /****************************************************************************
3491 get info about a user
3493 struct user_info_11 {
3494 char usri11_name[21]; 0-20
3495 char usri11_pad; 21
3496 char *usri11_comment; 22-25
3497 char *usri11_usr_comment; 26-29
3498 unsigned short usri11_priv; 30-31
3499 unsigned long usri11_auth_flags; 32-35
3500 long usri11_password_age; 36-39
3501 char *usri11_homedir; 40-43
3502 char *usri11_parms; 44-47
3503 long usri11_last_logon; 48-51
3504 long usri11_last_logoff; 52-55
3505 unsigned short usri11_bad_pw_count; 56-57
3506 unsigned short usri11_num_logons; 58-59
3507 char *usri11_logon_server; 60-63
3508 unsigned short usri11_country_code; 64-65
3509 char *usri11_workstations; 66-69
3510 unsigned long usri11_max_storage; 70-73
3511 unsigned short usri11_units_per_week; 74-75
3512 unsigned char *usri11_logon_hours; 76-79
3513 unsigned short usri11_code_page; 80-81
3516 where:
3518 usri11_name specifies the user name for which information is retrieved
3520 usri11_pad aligns the next data structure element to a word boundary
3522 usri11_comment is a null terminated ASCII comment
3524 usri11_user_comment is a null terminated ASCII comment about the user
3526 usri11_priv specifies the level of the privilege assigned to the user.
3527 The possible values are:
3529 Name Value Description
3530 USER_PRIV_GUEST 0 Guest privilege
3531 USER_PRIV_USER 1 User privilege
3532 USER_PRV_ADMIN 2 Administrator privilege
3534 usri11_auth_flags specifies the account operator privileges. The
3535 possible values are:
3537 Name Value Description
3538 AF_OP_PRINT 0 Print operator
3541 Leach, Naik [Page 28]
3545 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3548 AF_OP_COMM 1 Communications operator
3549 AF_OP_SERVER 2 Server operator
3550 AF_OP_ACCOUNTS 3 Accounts operator
3553 usri11_password_age specifies how many seconds have elapsed since the
3554 password was last changed.
3556 usri11_home_dir points to a null terminated ASCII string that contains
3557 the path name of the user's home directory.
3559 usri11_parms points to a null terminated ASCII string that is set
3560 aside for use by applications.
3562 usri11_last_logon specifies the time when the user last logged on.
3563 This value is stored as the number of seconds elapsed since
3564 00:00:00, January 1, 1970.
3566 usri11_last_logoff specifies the time when the user last logged off.
3567 This value is stored as the number of seconds elapsed since
3568 00:00:00, January 1, 1970. A value of 0 means the last logoff
3569 time is unknown.
3571 usri11_bad_pw_count specifies the number of incorrect passwords
3572 entered since the last successful logon.
3574 usri11_log1_num_logons specifies the number of times this user has
3575 logged on. A value of -1 means the number of logons is unknown.
3577 usri11_logon_server points to a null terminated ASCII string that
3578 contains the name of the server to which logon requests are sent.
3579 A null string indicates logon requests should be sent to the
3580 domain controller.
3582 usri11_country_code specifies the country code for the user's language
3583 of choice.
3585 usri11_workstations points to a null terminated ASCII string that
3586 contains the names of workstations the user may log on from.
3587 There may be up to 8 workstations, with the names separated by
3588 commas. A null strings indicates there are no restrictions.
3590 usri11_max_storage specifies the maximum amount of disk space the user
3591 can occupy. A value of 0xffffffff indicates there are no
3592 restrictions.
3594 usri11_units_per_week specifies the equal number of time units into
3595 which a week is divided. This value must be equal to 168.
3597 usri11_logon_hours points to a 21 byte (168 bits) string that
3598 specifies the time during which the user can log on. Each bit
3599 represents one unique hour in a week. The first bit (bit 0, word
3600 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3604 Leach, Naik [Page 29]
3608 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3611 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3612 are no restrictions.
3614 usri11_code_page specifies the code page for the user's language of
3615 choice
3617 All of the pointers in this data structure need to be treated
3618 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3619 to be ignored. The converter word returned in the parameters section
3620 needs to be subtracted from the lower 16 bits to calculate an offset
3621 into the return buffer where this ASCII string resides.
3623 There is no auxiliary data in the response.
3625 ****************************************************************************/
3627 #define usri11_name 0
3628 #define usri11_pad 21
3629 #define usri11_comment 22
3630 #define usri11_usr_comment 26
3631 #define usri11_full_name 30
3632 #define usri11_priv 34
3633 #define usri11_auth_flags 36
3634 #define usri11_password_age 40
3635 #define usri11_homedir 44
3636 #define usri11_parms 48
3637 #define usri11_last_logon 52
3638 #define usri11_last_logoff 56
3639 #define usri11_bad_pw_count 60
3640 #define usri11_num_logons 62
3641 #define usri11_logon_server 64
3642 #define usri11_country_code 68
3643 #define usri11_workstations 70
3644 #define usri11_max_storage 74
3645 #define usri11_units_per_week 78
3646 #define usri11_logon_hours 80
3647 #define usri11_code_page 84
3648 #define usri11_end 86
3650 #define USER_PRIV_GUEST 0
3651 #define USER_PRIV_USER 1
3652 #define USER_PRIV_ADMIN 2
3654 #define AF_OP_PRINT 0
3655 #define AF_OP_COMM 1
3656 #define AF_OP_SERVER 2
3657 #define AF_OP_ACCOUNTS 3
3660 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3661 char *param, int tpscnt,
3662 char *data, int tdscnt,
3663 int mdrcnt,int mprcnt,
3664 char **rdata,char **rparam,
3665 int *rdata_len,int *rparam_len)
3667 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3668 char *str2 = skip_string(param,tpscnt,str1);
3669 char *UserName = skip_string(param,tpscnt,str2);
3670 char *p = skip_string(param,tpscnt,UserName);
3671 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3672 char *p2;
3673 char *endp;
3674 const char *level_string;
3676 /* get NIS home of a previously validated user - simeon */
3677 /* With share level security vuid will always be zero.
3678 Don't depend on vuser being non-null !!. JRA */
3679 user_struct *vuser = get_valid_user_struct(vuid);
3680 if(vuser != NULL) {
3681 DEBUG(3,(" Username of UID %d is %s\n",
3682 (int)vuser->server_info->utok.uid,
3683 vuser->server_info->unix_name));
3686 if (!str1 || !str2 || !UserName || !p) {
3687 return False;
3690 *rparam_len = 6;
3691 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3692 if (!*rparam) {
3693 return False;
3696 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3698 /* check it's a supported variant */
3699 if (strcmp(str1,"zWrLh") != 0) {
3700 return False;
3702 switch( uLevel ) {
3703 case 0: level_string = "B21"; break;
3704 case 1: level_string = "B21BB16DWzzWz"; break;
3705 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3706 case 10: level_string = "B21Bzzz"; break;
3707 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3708 default: return False;
3711 if (strcmp(level_string,str2) != 0) {
3712 return False;
3715 *rdata_len = mdrcnt + 1024;
3716 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3717 if (!*rdata) {
3718 return False;
3721 SSVAL(*rparam,0,NERR_Success);
3722 SSVAL(*rparam,2,0); /* converter word */
3724 p = *rdata;
3725 endp = *rdata + *rdata_len;
3726 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3727 if (!p2) {
3728 return False;
3731 memset(p,0,21);
3732 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3734 if (uLevel > 0) {
3735 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3736 *p2 = 0;
3739 if (uLevel >= 10) {
3740 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3741 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3742 p2 = skip_string(*rdata,*rdata_len,p2);
3743 if (!p2) {
3744 return False;
3747 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3748 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3749 p2 = skip_string(*rdata,*rdata_len,p2);
3750 if (!p2) {
3751 return False;
3754 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3755 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3756 strlcpy(p2,((vuser != NULL)
3757 ? pdb_get_fullname(vuser->server_info->sam_account)
3758 : UserName),PTR_DIFF(endp,p2));
3759 p2 = skip_string(*rdata,*rdata_len,p2);
3760 if (!p2) {
3761 return False;
3765 if (uLevel == 11) {
3766 const char *homedir = "";
3767 if (vuser != NULL) {
3768 homedir = pdb_get_homedir(
3769 vuser->server_info->sam_account);
3771 /* modelled after NTAS 3.51 reply */
3772 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3773 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3774 SIVALS(p,usri11_password_age,-1); /* password age */
3775 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3776 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3777 p2 = skip_string(*rdata,*rdata_len,p2);
3778 if (!p2) {
3779 return False;
3781 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3782 strlcpy(p2,"",PTR_DIFF(endp,p2));
3783 p2 = skip_string(*rdata,*rdata_len,p2);
3784 if (!p2) {
3785 return False;
3787 SIVAL(p,usri11_last_logon,0); /* last logon */
3788 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3789 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3790 SSVALS(p,usri11_num_logons,-1); /* num logons */
3791 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3792 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3793 p2 = skip_string(*rdata,*rdata_len,p2);
3794 if (!p2) {
3795 return False;
3797 SSVAL(p,usri11_country_code,0); /* country code */
3799 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3800 strlcpy(p2,"",PTR_DIFF(endp,p2));
3801 p2 = skip_string(*rdata,*rdata_len,p2);
3802 if (!p2) {
3803 return False;
3806 SIVALS(p,usri11_max_storage,-1); /* max storage */
3807 SSVAL(p,usri11_units_per_week,168); /* units per week */
3808 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3810 /* a simple way to get logon hours at all times. */
3811 memset(p2,0xff,21);
3812 SCVAL(p2,21,0); /* fix zero termination */
3813 p2 = skip_string(*rdata,*rdata_len,p2);
3814 if (!p2) {
3815 return False;
3818 SSVAL(p,usri11_code_page,0); /* code page */
3821 if (uLevel == 1 || uLevel == 2) {
3822 memset(p+22,' ',16); /* password */
3823 SIVALS(p,38,-1); /* password age */
3824 SSVAL(p,42,
3825 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3826 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3827 strlcpy(p2, vuser ? pdb_get_homedir(
3828 vuser->server_info->sam_account) : "",
3829 PTR_DIFF(endp,p2));
3830 p2 = skip_string(*rdata,*rdata_len,p2);
3831 if (!p2) {
3832 return False;
3834 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3835 *p2++ = 0;
3836 SSVAL(p,52,0); /* flags */
3837 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3838 strlcpy(p2, vuser ? pdb_get_logon_script(
3839 vuser->server_info->sam_account) : "",
3840 PTR_DIFF(endp,p2));
3841 p2 = skip_string(*rdata,*rdata_len,p2);
3842 if (!p2) {
3843 return False;
3845 if (uLevel == 2) {
3846 SIVAL(p,60,0); /* auth_flags */
3847 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3848 strlcpy(p2,((vuser != NULL)
3849 ? pdb_get_fullname(vuser->server_info->sam_account)
3850 : UserName),PTR_DIFF(endp,p2));
3851 p2 = skip_string(*rdata,*rdata_len,p2);
3852 if (!p2) {
3853 return False;
3855 SIVAL(p,68,0); /* urs_comment */
3856 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3857 strlcpy(p2,"",PTR_DIFF(endp,p2));
3858 p2 = skip_string(*rdata,*rdata_len,p2);
3859 if (!p2) {
3860 return False;
3862 SIVAL(p,76,0); /* workstations */
3863 SIVAL(p,80,0); /* last_logon */
3864 SIVAL(p,84,0); /* last_logoff */
3865 SIVALS(p,88,-1); /* acct_expires */
3866 SIVALS(p,92,-1); /* max_storage */
3867 SSVAL(p,96,168); /* units_per_week */
3868 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3869 memset(p2,-1,21);
3870 p2 += 21;
3871 SSVALS(p,102,-1); /* bad_pw_count */
3872 SSVALS(p,104,-1); /* num_logons */
3873 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3875 TALLOC_CTX *ctx = talloc_tos();
3876 int space_rem = *rdata_len - (p2 - *rdata);
3877 char *tmp;
3879 if (space_rem <= 0) {
3880 return false;
3882 tmp = talloc_strdup(ctx, "\\\\%L");
3883 if (!tmp) {
3884 return false;
3886 tmp = talloc_sub_basic(ctx,
3889 tmp);
3890 if (!tmp) {
3891 return false;
3894 push_ascii(p2,
3895 tmp,
3896 space_rem,
3897 STR_TERMINATE);
3899 p2 = skip_string(*rdata,*rdata_len,p2);
3900 if (!p2) {
3901 return False;
3903 SSVAL(p,110,49); /* country_code */
3904 SSVAL(p,112,860); /* code page */
3908 *rdata_len = PTR_DIFF(p2,*rdata);
3910 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3912 return(True);
3915 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3916 char *param, int tpscnt,
3917 char *data, int tdscnt,
3918 int mdrcnt,int mprcnt,
3919 char **rdata,char **rparam,
3920 int *rdata_len,int *rparam_len)
3922 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3923 char *str2 = skip_string(param,tpscnt,str1);
3924 char *p = skip_string(param,tpscnt,str2);
3925 int uLevel;
3926 struct pack_desc desc;
3927 char* name;
3928 /* With share level security vuid will always be zero.
3929 Don't depend on vuser being non-null !!. JRA */
3930 user_struct *vuser = get_valid_user_struct(vuid);
3932 if (!str1 || !str2 || !p) {
3933 return False;
3936 if(vuser != NULL) {
3937 DEBUG(3,(" Username of UID %d is %s\n",
3938 (int)vuser->server_info->utok.uid,
3939 vuser->server_info->unix_name));
3942 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3943 name = get_safe_str_ptr(param,tpscnt,p,2);
3944 if (!name) {
3945 return False;
3948 memset((char *)&desc,'\0',sizeof(desc));
3950 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3952 /* check it's a supported varient */
3953 if (strcmp(str1,"OOWb54WrLh") != 0) {
3954 return False;
3956 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3957 return False;
3959 if (mdrcnt > 0) {
3960 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3961 if (!*rdata) {
3962 return False;
3966 desc.base = *rdata;
3967 desc.buflen = mdrcnt;
3968 desc.subformat = NULL;
3969 desc.format = str2;
3971 if (init_package(&desc,1,0)) {
3972 PACKI(&desc,"W",0); /* code */
3973 PACKS(&desc,"B21",name); /* eff. name */
3974 PACKS(&desc,"B",""); /* pad */
3975 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3976 PACKI(&desc,"D",0); /* auth flags XXX */
3977 PACKI(&desc,"W",0); /* num logons */
3978 PACKI(&desc,"W",0); /* bad pw count */
3979 PACKI(&desc,"D",0); /* last logon */
3980 PACKI(&desc,"D",-1); /* last logoff */
3981 PACKI(&desc,"D",-1); /* logoff time */
3982 PACKI(&desc,"D",-1); /* kickoff time */
3983 PACKI(&desc,"D",0); /* password age */
3984 PACKI(&desc,"D",0); /* password can change */
3985 PACKI(&desc,"D",-1); /* password must change */
3988 fstring mypath;
3989 fstrcpy(mypath,"\\\\");
3990 fstrcat(mypath,get_local_machine_name());
3991 strupper_m(mypath);
3992 PACKS(&desc,"z",mypath); /* computer */
3995 PACKS(&desc,"z",lp_workgroup());/* domain */
3996 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3997 vuser->server_info->sam_account) : ""); /* script path */
3998 PACKI(&desc,"D",0x00000000); /* reserved */
4001 *rdata_len = desc.usedlen;
4002 *rparam_len = 6;
4003 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4004 if (!*rparam) {
4005 return False;
4007 SSVALS(*rparam,0,desc.errcode);
4008 SSVAL(*rparam,2,0);
4009 SSVAL(*rparam,4,desc.neededlen);
4011 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4013 return True;
4016 /****************************************************************************
4017 api_WAccessGetUserPerms
4018 ****************************************************************************/
4020 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4021 char *param, int tpscnt,
4022 char *data, int tdscnt,
4023 int mdrcnt,int mprcnt,
4024 char **rdata,char **rparam,
4025 int *rdata_len,int *rparam_len)
4027 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4028 char *str2 = skip_string(param,tpscnt,str1);
4029 char *user = skip_string(param,tpscnt,str2);
4030 char *resource = skip_string(param,tpscnt,user);
4032 if (!str1 || !str2 || !user || !resource) {
4033 return False;
4036 if (skip_string(param,tpscnt,resource) == NULL) {
4037 return False;
4039 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4041 /* check it's a supported varient */
4042 if (strcmp(str1,"zzh") != 0) {
4043 return False;
4045 if (strcmp(str2,"") != 0) {
4046 return False;
4049 *rparam_len = 6;
4050 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4051 if (!*rparam) {
4052 return False;
4054 SSVALS(*rparam,0,0); /* errorcode */
4055 SSVAL(*rparam,2,0); /* converter word */
4056 SSVAL(*rparam,4,0x7f); /* permission flags */
4058 return True;
4061 /****************************************************************************
4062 api_WPrintJobEnumerate
4063 ****************************************************************************/
4065 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4066 char *param, int tpscnt,
4067 char *data, int tdscnt,
4068 int mdrcnt,int mprcnt,
4069 char **rdata,char **rparam,
4070 int *rdata_len,int *rparam_len)
4072 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4073 char *str2 = skip_string(param,tpscnt,str1);
4074 char *p = skip_string(param,tpscnt,str2);
4075 int uLevel;
4076 int count;
4077 int i;
4078 int snum;
4079 fstring sharename;
4080 uint32 jobid;
4081 struct pack_desc desc;
4082 print_queue_struct *queue=NULL;
4083 print_status_struct status;
4084 char *tmpdata=NULL;
4086 if (!str1 || !str2 || !p) {
4087 return False;
4090 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4092 memset((char *)&desc,'\0',sizeof(desc));
4093 memset((char *)&status,'\0',sizeof(status));
4095 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4097 /* check it's a supported varient */
4098 if (strcmp(str1,"WWrLh") != 0) {
4099 return False;
4101 if (!check_printjob_info(&desc,uLevel,str2)) {
4102 return False;
4105 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4106 return False;
4109 snum = lp_servicenumber( sharename);
4110 if (snum < 0 || !VALID_SNUM(snum)) {
4111 return(False);
4114 count = print_queue_status(snum,&queue,&status);
4115 for (i = 0; i < count; i++) {
4116 if (queue[i].job == jobid) {
4117 break;
4121 if (mdrcnt > 0) {
4122 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4123 if (!*rdata) {
4124 return False;
4126 desc.base = *rdata;
4127 desc.buflen = mdrcnt;
4128 } else {
4130 * Don't return data but need to get correct length
4131 * init_package will return wrong size if buflen=0
4133 desc.buflen = getlen(desc.format);
4134 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4137 if (init_package(&desc,1,0)) {
4138 if (i < count) {
4139 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4140 *rdata_len = desc.usedlen;
4141 } else {
4142 desc.errcode = NERR_JobNotFound;
4143 *rdata_len = 0;
4147 *rparam_len = 6;
4148 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4149 if (!*rparam) {
4150 return False;
4152 SSVALS(*rparam,0,desc.errcode);
4153 SSVAL(*rparam,2,0);
4154 SSVAL(*rparam,4,desc.neededlen);
4156 SAFE_FREE(queue);
4157 SAFE_FREE(tmpdata);
4159 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4161 return True;
4164 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4165 char *param, int tpscnt,
4166 char *data, int tdscnt,
4167 int mdrcnt,int mprcnt,
4168 char **rdata,char **rparam,
4169 int *rdata_len,int *rparam_len)
4171 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4172 char *str2 = skip_string(param,tpscnt,str1);
4173 char *p = skip_string(param,tpscnt,str2);
4174 char *name = p;
4175 int uLevel;
4176 int count;
4177 int i, succnt=0;
4178 int snum;
4179 struct pack_desc desc;
4180 print_queue_struct *queue=NULL;
4181 print_status_struct status;
4183 if (!str1 || !str2 || !p) {
4184 return False;
4187 memset((char *)&desc,'\0',sizeof(desc));
4188 memset((char *)&status,'\0',sizeof(status));
4190 p = skip_string(param,tpscnt,p);
4191 if (!p) {
4192 return False;
4194 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4196 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4198 /* check it's a supported variant */
4199 if (strcmp(str1,"zWrLeh") != 0) {
4200 return False;
4203 if (uLevel > 2) {
4204 return False; /* defined only for uLevel 0,1,2 */
4207 if (!check_printjob_info(&desc,uLevel,str2)) {
4208 return False;
4211 snum = find_service(name);
4212 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4213 return False;
4216 count = print_queue_status(snum,&queue,&status);
4217 if (mdrcnt > 0) {
4218 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4219 if (!*rdata) {
4220 return False;
4223 desc.base = *rdata;
4224 desc.buflen = mdrcnt;
4226 if (init_package(&desc,count,0)) {
4227 succnt = 0;
4228 for (i = 0; i < count; i++) {
4229 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4230 if (desc.errcode == NERR_Success) {
4231 succnt = i+1;
4236 *rdata_len = desc.usedlen;
4238 *rparam_len = 8;
4239 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4240 if (!*rparam) {
4241 return False;
4243 SSVALS(*rparam,0,desc.errcode);
4244 SSVAL(*rparam,2,0);
4245 SSVAL(*rparam,4,succnt);
4246 SSVAL(*rparam,6,count);
4248 SAFE_FREE(queue);
4250 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4252 return True;
4255 static int check_printdest_info(struct pack_desc* desc,
4256 int uLevel, char* id)
4258 desc->subformat = NULL;
4259 switch( uLevel ) {
4260 case 0:
4261 desc->format = "B9";
4262 break;
4263 case 1:
4264 desc->format = "B9B21WWzW";
4265 break;
4266 case 2:
4267 desc->format = "z";
4268 break;
4269 case 3:
4270 desc->format = "zzzWWzzzWW";
4271 break;
4272 default:
4273 DEBUG(0,("check_printdest_info: invalid level %d\n",
4274 uLevel));
4275 return False;
4277 if (id == NULL || strcmp(desc->format,id) != 0) {
4278 DEBUG(0,("check_printdest_info: invalid string %s\n",
4279 id ? id : "<NULL>" ));
4280 return False;
4282 return True;
4285 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4286 struct pack_desc* desc)
4288 char buf[100];
4290 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4291 buf[sizeof(buf)-1] = 0;
4292 strupper_m(buf);
4294 if (uLevel <= 1) {
4295 PACKS(desc,"B9",buf); /* szName */
4296 if (uLevel == 1) {
4297 PACKS(desc,"B21",""); /* szUserName */
4298 PACKI(desc,"W",0); /* uJobId */
4299 PACKI(desc,"W",0); /* fsStatus */
4300 PACKS(desc,"z",""); /* pszStatus */
4301 PACKI(desc,"W",0); /* time */
4305 if (uLevel == 2 || uLevel == 3) {
4306 PACKS(desc,"z",buf); /* pszPrinterName */
4307 if (uLevel == 3) {
4308 PACKS(desc,"z",""); /* pszUserName */
4309 PACKS(desc,"z",""); /* pszLogAddr */
4310 PACKI(desc,"W",0); /* uJobId */
4311 PACKI(desc,"W",0); /* fsStatus */
4312 PACKS(desc,"z",""); /* pszStatus */
4313 PACKS(desc,"z",""); /* pszComment */
4314 PACKS(desc,"z","NULL"); /* pszDrivers */
4315 PACKI(desc,"W",0); /* time */
4316 PACKI(desc,"W",0); /* pad1 */
4321 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4322 char *param, int tpscnt,
4323 char *data, int tdscnt,
4324 int mdrcnt,int mprcnt,
4325 char **rdata,char **rparam,
4326 int *rdata_len,int *rparam_len)
4328 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4329 char *str2 = skip_string(param,tpscnt,str1);
4330 char *p = skip_string(param,tpscnt,str2);
4331 char* PrinterName = p;
4332 int uLevel;
4333 struct pack_desc desc;
4334 int snum;
4335 char *tmpdata=NULL;
4337 if (!str1 || !str2 || !p) {
4338 return False;
4341 memset((char *)&desc,'\0',sizeof(desc));
4343 p = skip_string(param,tpscnt,p);
4344 if (!p) {
4345 return False;
4347 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4349 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4351 /* check it's a supported varient */
4352 if (strcmp(str1,"zWrLh") != 0) {
4353 return False;
4355 if (!check_printdest_info(&desc,uLevel,str2)) {
4356 return False;
4359 snum = find_service(PrinterName);
4360 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4361 *rdata_len = 0;
4362 desc.errcode = NERR_DestNotFound;
4363 desc.neededlen = 0;
4364 } else {
4365 if (mdrcnt > 0) {
4366 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4367 if (!*rdata) {
4368 return False;
4370 desc.base = *rdata;
4371 desc.buflen = mdrcnt;
4372 } else {
4374 * Don't return data but need to get correct length
4375 * init_package will return wrong size if buflen=0
4377 desc.buflen = getlen(desc.format);
4378 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4380 if (init_package(&desc,1,0)) {
4381 fill_printdest_info(conn,snum,uLevel,&desc);
4383 *rdata_len = desc.usedlen;
4386 *rparam_len = 6;
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,desc.neededlen);
4395 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4396 SAFE_FREE(tmpdata);
4398 return True;
4401 static bool api_WPrintDestEnum(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 queuecnt;
4413 int i, n, succnt=0;
4414 struct pack_desc desc;
4415 int services = lp_numservices();
4417 if (!str1 || !str2 || !p) {
4418 return False;
4421 memset((char *)&desc,'\0',sizeof(desc));
4423 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4425 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4427 /* check it's a supported varient */
4428 if (strcmp(str1,"WrLeh") != 0) {
4429 return False;
4431 if (!check_printdest_info(&desc,uLevel,str2)) {
4432 return False;
4435 queuecnt = 0;
4436 for (i = 0; i < services; i++) {
4437 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4438 queuecnt++;
4442 if (mdrcnt > 0) {
4443 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4444 if (!*rdata) {
4445 return False;
4449 desc.base = *rdata;
4450 desc.buflen = mdrcnt;
4451 if (init_package(&desc,queuecnt,0)) {
4452 succnt = 0;
4453 n = 0;
4454 for (i = 0; i < services; i++) {
4455 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4456 fill_printdest_info(conn,i,uLevel,&desc);
4457 n++;
4458 if (desc.errcode == NERR_Success) {
4459 succnt = n;
4465 *rdata_len = desc.usedlen;
4467 *rparam_len = 8;
4468 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4469 if (!*rparam) {
4470 return False;
4472 SSVALS(*rparam,0,desc.errcode);
4473 SSVAL(*rparam,2,0);
4474 SSVAL(*rparam,4,succnt);
4475 SSVAL(*rparam,6,queuecnt);
4477 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4479 return True;
4482 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4483 char *param, int tpscnt,
4484 char *data, int tdscnt,
4485 int mdrcnt,int mprcnt,
4486 char **rdata,char **rparam,
4487 int *rdata_len,int *rparam_len)
4489 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4490 char *str2 = skip_string(param,tpscnt,str1);
4491 char *p = skip_string(param,tpscnt,str2);
4492 int uLevel;
4493 int succnt;
4494 struct pack_desc desc;
4496 if (!str1 || !str2 || !p) {
4497 return False;
4500 memset((char *)&desc,'\0',sizeof(desc));
4502 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4504 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4506 /* check it's a supported varient */
4507 if (strcmp(str1,"WrLeh") != 0) {
4508 return False;
4510 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4511 return False;
4514 if (mdrcnt > 0) {
4515 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4516 if (!*rdata) {
4517 return False;
4520 desc.base = *rdata;
4521 desc.buflen = mdrcnt;
4522 if (init_package(&desc,1,0)) {
4523 PACKS(&desc,"B41","NULL");
4526 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4528 *rdata_len = desc.usedlen;
4530 *rparam_len = 8;
4531 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4532 if (!*rparam) {
4533 return False;
4535 SSVALS(*rparam,0,desc.errcode);
4536 SSVAL(*rparam,2,0);
4537 SSVAL(*rparam,4,succnt);
4538 SSVAL(*rparam,6,1);
4540 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4542 return True;
4545 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4546 char *param, int tpscnt,
4547 char *data, int tdscnt,
4548 int mdrcnt,int mprcnt,
4549 char **rdata,char **rparam,
4550 int *rdata_len,int *rparam_len)
4552 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4553 char *str2 = skip_string(param,tpscnt,str1);
4554 char *p = skip_string(param,tpscnt,str2);
4555 int uLevel;
4556 int succnt;
4557 struct pack_desc desc;
4559 if (!str1 || !str2 || !p) {
4560 return False;
4562 memset((char *)&desc,'\0',sizeof(desc));
4564 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4566 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4568 /* check it's a supported varient */
4569 if (strcmp(str1,"WrLeh") != 0) {
4570 return False;
4572 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4573 return False;
4576 if (mdrcnt > 0) {
4577 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4578 if (!*rdata) {
4579 return False;
4582 desc.base = *rdata;
4583 desc.buflen = mdrcnt;
4584 desc.format = str2;
4585 if (init_package(&desc,1,0)) {
4586 PACKS(&desc,"B13","lpd");
4589 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4591 *rdata_len = desc.usedlen;
4593 *rparam_len = 8;
4594 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4595 if (!*rparam) {
4596 return False;
4598 SSVALS(*rparam,0,desc.errcode);
4599 SSVAL(*rparam,2,0);
4600 SSVAL(*rparam,4,succnt);
4601 SSVAL(*rparam,6,1);
4603 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4605 return True;
4608 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4609 char *param, int tpscnt,
4610 char *data, int tdscnt,
4611 int mdrcnt,int mprcnt,
4612 char **rdata,char **rparam,
4613 int *rdata_len,int *rparam_len)
4615 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4616 char *str2 = skip_string(param,tpscnt,str1);
4617 char *p = skip_string(param,tpscnt,str2);
4618 int uLevel;
4619 int succnt;
4620 struct pack_desc desc;
4622 if (!str1 || !str2 || !p) {
4623 return False;
4626 memset((char *)&desc,'\0',sizeof(desc));
4628 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4630 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4632 /* check it's a supported varient */
4633 if (strcmp(str1,"WrLeh") != 0) {
4634 return False;
4636 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4637 return False;
4640 if (mdrcnt > 0) {
4641 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4642 if (!*rdata) {
4643 return False;
4646 memset((char *)&desc,'\0',sizeof(desc));
4647 desc.base = *rdata;
4648 desc.buflen = mdrcnt;
4649 desc.format = str2;
4650 if (init_package(&desc,1,0)) {
4651 PACKS(&desc,"B13","lp0");
4654 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4656 *rdata_len = desc.usedlen;
4658 *rparam_len = 8;
4659 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4660 if (!*rparam) {
4661 return False;
4663 SSVALS(*rparam,0,desc.errcode);
4664 SSVAL(*rparam,2,0);
4665 SSVAL(*rparam,4,succnt);
4666 SSVAL(*rparam,6,1);
4668 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4670 return True;
4673 /****************************************************************************
4674 List open sessions
4675 ****************************************************************************/
4677 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4678 char *param, int tpscnt,
4679 char *data, int tdscnt,
4680 int mdrcnt,int mprcnt,
4681 char **rdata,char **rparam,
4682 int *rdata_len,int *rparam_len)
4685 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4686 char *str2 = skip_string(param,tpscnt,str1);
4687 char *p = skip_string(param,tpscnt,str2);
4688 int uLevel;
4689 struct pack_desc desc;
4690 struct sessionid *session_list;
4691 int i, num_sessions;
4693 if (!str1 || !str2 || !p) {
4694 return False;
4697 memset((char *)&desc,'\0',sizeof(desc));
4699 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4701 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4702 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4703 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4705 /* check it's a supported varient */
4706 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4707 return False;
4709 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4710 return False;
4713 num_sessions = list_sessions(talloc_tos(), &session_list);
4715 if (mdrcnt > 0) {
4716 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4717 if (!*rdata) {
4718 return False;
4721 memset((char *)&desc,'\0',sizeof(desc));
4722 desc.base = *rdata;
4723 desc.buflen = mdrcnt;
4724 desc.format = str2;
4725 if (!init_package(&desc,num_sessions,0)) {
4726 return False;
4729 for(i=0; i<num_sessions; i++) {
4730 PACKS(&desc, "z", session_list[i].remote_machine);
4731 PACKS(&desc, "z", session_list[i].username);
4732 PACKI(&desc, "W", 1); /* num conns */
4733 PACKI(&desc, "W", 0); /* num opens */
4734 PACKI(&desc, "W", 1); /* num users */
4735 PACKI(&desc, "D", 0); /* session time */
4736 PACKI(&desc, "D", 0); /* idle time */
4737 PACKI(&desc, "D", 0); /* flags */
4738 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4741 *rdata_len = desc.usedlen;
4743 *rparam_len = 8;
4744 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4745 if (!*rparam) {
4746 return False;
4748 SSVALS(*rparam,0,desc.errcode);
4749 SSVAL(*rparam,2,0); /* converter */
4750 SSVAL(*rparam,4,num_sessions); /* count */
4752 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4754 return True;
4758 /****************************************************************************
4759 The buffer was too small.
4760 ****************************************************************************/
4762 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4763 int mdrcnt, int mprcnt,
4764 char **rdata, char **rparam,
4765 int *rdata_len, int *rparam_len)
4767 *rparam_len = MIN(*rparam_len,mprcnt);
4768 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4769 if (!*rparam) {
4770 return False;
4773 *rdata_len = 0;
4775 SSVAL(*rparam,0,NERR_BufTooSmall);
4777 DEBUG(3,("Supplied buffer too small in API command\n"));
4779 return True;
4782 /****************************************************************************
4783 The request is not supported.
4784 ****************************************************************************/
4786 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4787 char *param, int tpscnt,
4788 char *data, int tdscnt,
4789 int mdrcnt, int mprcnt,
4790 char **rdata, char **rparam,
4791 int *rdata_len, int *rparam_len)
4793 *rparam_len = 4;
4794 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4795 if (!*rparam) {
4796 return False;
4799 *rdata_len = 0;
4801 SSVAL(*rparam,0,NERR_notsupported);
4802 SSVAL(*rparam,2,0); /* converter word */
4804 DEBUG(3,("Unsupported API command\n"));
4806 return True;
4809 static const struct {
4810 const char *name;
4811 int id;
4812 bool (*fn)(connection_struct *, uint16,
4813 char *, int,
4814 char *, int,
4815 int,int,char **,char **,int *,int *);
4816 bool auth_user; /* Deny anonymous access? */
4817 } api_commands[] = {
4818 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4819 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4820 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4821 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4822 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4823 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4824 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4825 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4826 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4827 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4828 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4829 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4830 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4831 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4832 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4833 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4834 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4835 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4836 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4837 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4838 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4839 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4840 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4841 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4842 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
4843 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
4844 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4845 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4846 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4847 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4848 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4849 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4850 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4851 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4852 {NULL, -1, api_Unsupported}
4853 /* The following RAP calls are not implemented by Samba:
4855 RAP_WFileEnum2 - anon not OK
4860 /****************************************************************************
4861 Handle remote api calls.
4862 ****************************************************************************/
4864 void api_reply(connection_struct *conn, uint16 vuid,
4865 struct smb_request *req,
4866 char *data, char *params,
4867 int tdscnt, int tpscnt,
4868 int mdrcnt, int mprcnt)
4870 int api_command;
4871 char *rdata = NULL;
4872 char *rparam = NULL;
4873 const char *name1 = NULL;
4874 const char *name2 = NULL;
4875 int rdata_len = 0;
4876 int rparam_len = 0;
4877 bool reply=False;
4878 int i;
4880 if (!params) {
4881 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4882 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4883 return;
4886 if (tpscnt < 2) {
4887 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4888 return;
4890 api_command = SVAL(params,0);
4891 /* Is there a string at position params+2 ? */
4892 if (skip_string(params,tpscnt,params+2)) {
4893 name1 = params + 2;
4894 } else {
4895 name1 = "";
4897 name2 = skip_string(params,tpscnt,params+2);
4898 if (!name2) {
4899 name2 = "";
4902 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4903 api_command,
4904 name1,
4905 name2,
4906 tdscnt,tpscnt,mdrcnt,mprcnt));
4908 for (i=0;api_commands[i].name;i++) {
4909 if (api_commands[i].id == api_command && api_commands[i].fn) {
4910 DEBUG(3,("Doing %s\n",api_commands[i].name));
4911 break;
4915 /* Check whether this api call can be done anonymously */
4917 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4918 user_struct *user = get_valid_user_struct(vuid);
4920 if (!user || user->server_info->guest) {
4921 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4922 return;
4926 rdata = (char *)SMB_MALLOC(1024);
4927 if (rdata) {
4928 memset(rdata,'\0',1024);
4931 rparam = (char *)SMB_MALLOC(1024);
4932 if (rparam) {
4933 memset(rparam,'\0',1024);
4936 if(!rdata || !rparam) {
4937 DEBUG(0,("api_reply: malloc fail !\n"));
4938 SAFE_FREE(rdata);
4939 SAFE_FREE(rparam);
4940 reply_nterror(req, NT_STATUS_NO_MEMORY);
4941 return;
4944 reply = api_commands[i].fn(conn,
4945 vuid,
4946 params,tpscnt, /* params + length */
4947 data,tdscnt, /* data + length */
4948 mdrcnt,mprcnt,
4949 &rdata,&rparam,&rdata_len,&rparam_len);
4952 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4953 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4954 &rdata,&rparam,&rdata_len,&rparam_len);
4957 /* if we get False back then it's actually unsupported */
4958 if (!reply) {
4959 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4960 &rdata,&rparam,&rdata_len,&rparam_len);
4963 /* If api_Unsupported returns false we can't return anything. */
4964 if (reply) {
4965 send_trans_reply(conn, req, rparam, rparam_len,
4966 rdata, rdata_len, False);
4969 SAFE_FREE(rdata);
4970 SAFE_FREE(rparam);
4971 return;