s3-rpc_client: move protos to cli_lsarpc.h
[Samba/ekacnet.git] / source3 / smbd / lanman.c
blobfce23e8da23ff10f6c26a680377cca68b39b58ae
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
29 #include "smbd/globals.h"
30 #include "../librpc/gen_ndr/cli_samr.h"
31 #include "../librpc/gen_ndr/cli_spoolss.h"
32 #include "../librpc/gen_ndr/cli_srvsvc.h"
33 #include "../librpc/gen_ndr/srv_samr.h"
34 #include "../librpc/gen_ndr/srv_spoolss.h"
35 #include "../librpc/gen_ndr/srv_srvsvc.h"
36 #include "../librpc/gen_ndr/rap.h"
37 #include "../lib/util/binsearch.h"
39 #ifdef CHECK_TYPES
40 #undef CHECK_TYPES
41 #endif
42 #define CHECK_TYPES 0
44 #define NERR_Success 0
45 #define NERR_badpass 86
46 #define NERR_notsupported 50
48 #define NERR_BASE (2100)
49 #define NERR_BufTooSmall (NERR_BASE+23)
50 #define NERR_JobNotFound (NERR_BASE+51)
51 #define NERR_DestNotFound (NERR_BASE+52)
53 #define ACCESS_READ 0x01
54 #define ACCESS_WRITE 0x02
55 #define ACCESS_CREATE 0x04
57 #define SHPWLEN 8 /* share password length */
59 /* Limit size of ipc replies */
61 static char *smb_realloc_limit(void *ptr, size_t size)
63 char *val;
65 size = MAX((size),4*1024);
66 val = (char *)SMB_REALLOC(ptr,size);
67 if (val) {
68 memset(val,'\0',size);
70 return val;
73 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
74 char *param, int tpscnt,
75 char *data, int tdscnt,
76 int mdrcnt, int mprcnt,
77 char **rdata, char **rparam,
78 int *rdata_len, int *rparam_len);
80 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
81 int mdrcnt, int mprcnt,
82 char **rdata, char **rparam,
83 int *rdata_len, int *rparam_len);
86 static int CopyExpanded(connection_struct *conn,
87 int snum, char **dst, char *src, int *p_space_remaining)
89 TALLOC_CTX *ctx = talloc_tos();
90 char *buf = NULL;
91 int l;
93 if (!src || !dst || !p_space_remaining || !(*dst) ||
94 *p_space_remaining <= 0) {
95 return 0;
98 buf = talloc_strdup(ctx, src);
99 if (!buf) {
100 *p_space_remaining = 0;
101 return 0;
103 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
104 if (!buf) {
105 *p_space_remaining = 0;
106 return 0;
108 buf = talloc_sub_advanced(ctx,
109 lp_servicename(SNUM(conn)),
110 conn->server_info->unix_name,
111 conn->connectpath,
112 conn->server_info->utok.gid,
113 conn->server_info->sanitized_username,
114 pdb_get_domain(conn->server_info->sam_account),
115 buf);
116 if (!buf) {
117 *p_space_remaining = 0;
118 return 0;
120 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
121 if (l == -1) {
122 return 0;
124 (*dst) += l;
125 (*p_space_remaining) -= l;
126 return l;
129 static int CopyAndAdvance(char **dst, char *src, int *n)
131 int l;
132 if (!src || !dst || !n || !(*dst)) {
133 return 0;
135 l = push_ascii(*dst,src,*n, STR_TERMINATE);
136 if (l == -1) {
137 return 0;
139 (*dst) += l;
140 (*n) -= l;
141 return l;
144 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
146 TALLOC_CTX *ctx = talloc_tos();
147 char *buf = NULL;
148 if (!s) {
149 return 0;
151 buf = talloc_strdup(ctx,s);
152 if (!buf) {
153 return 0;
155 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
156 if (!buf) {
157 return 0;
159 buf = talloc_sub_advanced(ctx,
160 lp_servicename(SNUM(conn)),
161 conn->server_info->unix_name,
162 conn->connectpath,
163 conn->server_info->utok.gid,
164 conn->server_info->sanitized_username,
165 pdb_get_domain(conn->server_info->sam_account),
166 buf);
167 if (!buf) {
168 return 0;
170 return strlen(buf) + 1;
173 /*******************************************************************
174 Check a API string for validity when we only need to check the prefix.
175 ******************************************************************/
177 static bool prefix_ok(const char *str, const char *prefix)
179 return(strncmp(str,prefix,strlen(prefix)) == 0);
182 struct pack_desc {
183 const char *format; /* formatstring for structure */
184 const char *subformat; /* subformat for structure */
185 char *base; /* baseaddress of buffer */
186 int buflen; /* remaining size for fixed part; on init: length of base */
187 int subcount; /* count of substructures */
188 char *structbuf; /* pointer into buffer for remaining fixed part */
189 int stringlen; /* remaining size for variable part */
190 char *stringbuf; /* pointer into buffer for remaining variable part */
191 int neededlen; /* total needed size */
192 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
193 const char *curpos; /* current position; pointer into format or subformat */
194 int errcode;
197 static int get_counter(const char **p)
199 int i, n;
200 if (!p || !(*p)) {
201 return 1;
203 if (!isdigit((int)**p)) {
204 return 1;
206 for (n = 0;;) {
207 i = **p;
208 if (isdigit(i)) {
209 n = 10 * n + (i - '0');
210 } else {
211 return n;
213 (*p)++;
217 static int getlen(const char *p)
219 int n = 0;
220 if (!p) {
221 return 0;
224 while (*p) {
225 switch( *p++ ) {
226 case 'W': /* word (2 byte) */
227 n += 2;
228 break;
229 case 'K': /* status word? (2 byte) */
230 n += 2;
231 break;
232 case 'N': /* count of substructures (word) at end */
233 n += 2;
234 break;
235 case 'D': /* double word (4 byte) */
236 case 'z': /* offset to zero terminated string (4 byte) */
237 case 'l': /* offset to user data (4 byte) */
238 n += 4;
239 break;
240 case 'b': /* offset to data (with counter) (4 byte) */
241 n += 4;
242 get_counter(&p);
243 break;
244 case 'B': /* byte (with optional counter) */
245 n += get_counter(&p);
246 break;
249 return n;
252 static bool init_package(struct pack_desc *p, int count, int subcount)
254 int n = p->buflen;
255 int i;
257 if (!p->format || !p->base) {
258 return False;
261 i = count * getlen(p->format);
262 if (p->subformat) {
263 i += subcount * getlen(p->subformat);
265 p->structbuf = p->base;
266 p->neededlen = 0;
267 p->usedlen = 0;
268 p->subcount = 0;
269 p->curpos = p->format;
270 if (i > n) {
271 p->neededlen = i;
272 i = n = 0;
273 #if 0
275 * This is the old error code we used. Aparently
276 * WinNT/2k systems return ERRbuftoosmall (2123) and
277 * OS/2 needs this. I'm leaving this here so we can revert
278 * if needed. JRA.
280 p->errcode = ERRmoredata;
281 #else
282 p->errcode = ERRbuftoosmall;
283 #endif
284 } else {
285 p->errcode = NERR_Success;
287 p->buflen = i;
288 n -= i;
289 p->stringbuf = p->base + i;
290 p->stringlen = n;
291 return (p->errcode == NERR_Success);
294 static int package(struct pack_desc *p, ...)
296 va_list args;
297 int needed=0, stringneeded;
298 const char *str=NULL;
299 int is_string=0, stringused;
300 int32 temp;
302 va_start(args,p);
304 if (!*p->curpos) {
305 if (!p->subcount) {
306 p->curpos = p->format;
307 } else {
308 p->curpos = p->subformat;
309 p->subcount--;
312 #if CHECK_TYPES
313 str = va_arg(args,char*);
314 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
315 #endif
316 stringneeded = -1;
318 if (!p->curpos) {
319 va_end(args);
320 return 0;
323 switch( *p->curpos++ ) {
324 case 'W': /* word (2 byte) */
325 needed = 2;
326 temp = va_arg(args,int);
327 if (p->buflen >= needed) {
328 SSVAL(p->structbuf,0,temp);
330 break;
331 case 'K': /* status word? (2 byte) */
332 needed = 2;
333 temp = va_arg(args,int);
334 if (p->buflen >= needed) {
335 SSVAL(p->structbuf,0,temp);
337 break;
338 case 'N': /* count of substructures (word) at end */
339 needed = 2;
340 p->subcount = va_arg(args,int);
341 if (p->buflen >= needed) {
342 SSVAL(p->structbuf,0,p->subcount);
344 break;
345 case 'D': /* double word (4 byte) */
346 needed = 4;
347 temp = va_arg(args,int);
348 if (p->buflen >= needed) {
349 SIVAL(p->structbuf,0,temp);
351 break;
352 case 'B': /* byte (with optional counter) */
353 needed = get_counter(&p->curpos);
355 char *s = va_arg(args,char*);
356 if (p->buflen >= needed) {
357 StrnCpy(p->structbuf,s?s:"",needed-1);
360 break;
361 case 'z': /* offset to zero terminated string (4 byte) */
362 str = va_arg(args,char*);
363 stringneeded = (str ? strlen(str)+1 : 0);
364 is_string = 1;
365 break;
366 case 'l': /* offset to user data (4 byte) */
367 str = va_arg(args,char*);
368 stringneeded = va_arg(args,int);
369 is_string = 0;
370 break;
371 case 'b': /* offset to data (with counter) (4 byte) */
372 str = va_arg(args,char*);
373 stringneeded = get_counter(&p->curpos);
374 is_string = 0;
375 break;
378 va_end(args);
379 if (stringneeded >= 0) {
380 needed = 4;
381 if (p->buflen >= needed) {
382 stringused = stringneeded;
383 if (stringused > p->stringlen) {
384 stringused = (is_string ? p->stringlen : 0);
385 if (p->errcode == NERR_Success) {
386 p->errcode = ERRmoredata;
389 if (!stringused) {
390 SIVAL(p->structbuf,0,0);
391 } else {
392 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
393 memcpy(p->stringbuf,str?str:"",stringused);
394 if (is_string) {
395 p->stringbuf[stringused-1] = '\0';
397 p->stringbuf += stringused;
398 p->stringlen -= stringused;
399 p->usedlen += stringused;
402 p->neededlen += stringneeded;
405 p->neededlen += needed;
406 if (p->buflen >= needed) {
407 p->structbuf += needed;
408 p->buflen -= needed;
409 p->usedlen += needed;
410 } else {
411 if (p->errcode == NERR_Success) {
412 p->errcode = ERRmoredata;
415 return 1;
418 #if CHECK_TYPES
419 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
420 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
421 #else
422 #define PACK(desc,t,v) package(desc,v)
423 #define PACKl(desc,t,v,l) package(desc,v,l)
424 #endif
426 static void PACKI(struct pack_desc* desc, const char *t,int v)
428 PACK(desc,t,v);
431 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
433 PACK(desc,t,v);
436 /****************************************************************************
437 Get a print queue.
438 ****************************************************************************/
440 static void PackDriverData(struct pack_desc* desc)
442 char drivdata[4+4+32];
443 SIVAL(drivdata,0,sizeof drivdata); /* cb */
444 SIVAL(drivdata,4,1000); /* lVersion */
445 memset(drivdata+8,0,32); /* szDeviceName */
446 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
447 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
450 static int check_printq_info(struct pack_desc* desc,
451 unsigned int uLevel, char *id1, char *id2)
453 desc->subformat = NULL;
454 switch( uLevel ) {
455 case 0:
456 desc->format = "B13";
457 break;
458 case 1:
459 desc->format = "B13BWWWzzzzzWW";
460 break;
461 case 2:
462 desc->format = "B13BWWWzzzzzWN";
463 desc->subformat = "WB21BB16B10zWWzDDz";
464 break;
465 case 3:
466 desc->format = "zWWWWzzzzWWzzl";
467 break;
468 case 4:
469 desc->format = "zWWWWzzzzWNzzl";
470 desc->subformat = "WWzWWDDzz";
471 break;
472 case 5:
473 desc->format = "z";
474 break;
475 case 51:
476 desc->format = "K";
477 break;
478 case 52:
479 desc->format = "WzzzzzzzzN";
480 desc->subformat = "z";
481 break;
482 default:
483 DEBUG(0,("check_printq_info: invalid level %d\n",
484 uLevel ));
485 return False;
487 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
488 DEBUG(0,("check_printq_info: invalid format %s\n",
489 id1 ? id1 : "<NULL>" ));
490 return False;
492 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
493 DEBUG(0,("check_printq_info: invalid subformat %s\n",
494 id2 ? id2 : "<NULL>" ));
495 return False;
497 return True;
501 #define RAP_JOB_STATUS_QUEUED 0
502 #define RAP_JOB_STATUS_PAUSED 1
503 #define RAP_JOB_STATUS_SPOOLING 2
504 #define RAP_JOB_STATUS_PRINTING 3
505 #define RAP_JOB_STATUS_PRINTED 4
507 #define RAP_QUEUE_STATUS_PAUSED 1
508 #define RAP_QUEUE_STATUS_ERROR 2
510 /* turn a print job status into a on the wire status
512 static int printj_spoolss_status(int v)
514 if (v == JOB_STATUS_QUEUED)
515 return RAP_JOB_STATUS_QUEUED;
516 if (v & JOB_STATUS_PAUSED)
517 return RAP_JOB_STATUS_PAUSED;
518 if (v & JOB_STATUS_SPOOLING)
519 return RAP_JOB_STATUS_SPOOLING;
520 if (v & JOB_STATUS_PRINTING)
521 return RAP_JOB_STATUS_PRINTING;
522 return 0;
525 /* turn a print queue status into a on the wire status
527 static int printq_spoolss_status(int v)
529 if (v == PRINTER_STATUS_OK)
530 return 0;
531 if (v & PRINTER_STATUS_PAUSED)
532 return RAP_QUEUE_STATUS_PAUSED;
533 return RAP_QUEUE_STATUS_ERROR;
536 static void fill_spoolss_printjob_info(int uLevel,
537 struct pack_desc *desc,
538 struct spoolss_JobInfo2 *info2,
539 int n)
541 time_t t = spoolss_Time_to_time_t(&info2->submitted);
543 /* the client expects localtime */
544 t -= get_time_zone(t);
546 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
547 if (uLevel == 1) {
548 PACKS(desc,"B21", info2->user_name); /* szUserName */
549 PACKS(desc,"B",""); /* pad */
550 PACKS(desc,"B16",""); /* szNotifyName */
551 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
552 PACKS(desc,"z",""); /* pszParms */
553 PACKI(desc,"W",n+1); /* uPosition */
554 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
555 PACKS(desc,"z",""); /* pszStatus */
556 PACKI(desc,"D", t); /* ulSubmitted */
557 PACKI(desc,"D", info2->size); /* ulSize */
558 PACKS(desc,"z", info2->document_name); /* pszComment */
560 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
561 PACKI(desc,"W", info2->priority); /* uPriority */
562 PACKS(desc,"z", info2->user_name); /* pszUserName */
563 PACKI(desc,"W",n+1); /* uPosition */
564 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
565 PACKI(desc,"D",t); /* ulSubmitted */
566 PACKI(desc,"D", info2->size); /* ulSize */
567 PACKS(desc,"z","Samba"); /* pszComment */
568 PACKS(desc,"z", info2->document_name); /* pszDocument */
569 if (uLevel == 3) {
570 PACKS(desc,"z",""); /* pszNotifyName */
571 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
572 PACKS(desc,"z",""); /* pszParms */
573 PACKS(desc,"z",""); /* pszStatus */
574 PACKS(desc,"z", info2->printer_name); /* pszQueue */
575 PACKS(desc,"z","lpd"); /* pszQProcName */
576 PACKS(desc,"z",""); /* pszQProcParms */
577 PACKS(desc,"z","NULL"); /* pszDriverName */
578 PackDriverData(desc); /* pDriverData */
579 PACKS(desc,"z",""); /* pszPrinterName */
580 } else if (uLevel == 4) { /* OS2 */
581 PACKS(desc,"z",""); /* pszSpoolFileName */
582 PACKS(desc,"z",""); /* pszPortName */
583 PACKS(desc,"z",""); /* pszStatus */
584 PACKI(desc,"D",0); /* ulPagesSpooled */
585 PACKI(desc,"D",0); /* ulPagesSent */
586 PACKI(desc,"D",0); /* ulPagesPrinted */
587 PACKI(desc,"D",0); /* ulTimePrinted */
588 PACKI(desc,"D",0); /* ulExtendJobStatus */
589 PACKI(desc,"D",0); /* ulStartPage */
590 PACKI(desc,"D",0); /* ulEndPage */
595 /********************************************************************
596 Respond to the DosPrintQInfo command with a level of 52
597 This is used to get printer driver information for Win9x clients
598 ********************************************************************/
599 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
600 struct pack_desc* desc, int count,
601 const char *printer_name)
603 int i;
604 fstring location;
605 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
606 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
607 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
609 PACKI(desc, "W", 0x0400); /* don't know */
610 PACKS(desc, "z", driver->driver_name); /* long printer name */
611 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
612 PACKS(desc, "z", driver->data_file); /* Datafile name */
613 PACKS(desc, "z", driver->monitor_name); /* language monitor */
615 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
616 standard_sub_basic( "", "", location, sizeof(location)-1 );
617 PACKS(desc,"z", location); /* share to retrieve files */
619 PACKS(desc,"z", driver->default_datatype); /* default data type */
620 PACKS(desc,"z", driver->help_file); /* helpfile name */
621 PACKS(desc,"z", driver->driver_path); /* driver name */
623 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
624 DEBUG(3,("Driver: %s:\n",driver->driver_path));
625 DEBUG(3,("Data File: %s:\n",driver->data_file));
626 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
627 DEBUG(3,("Driver Location: %s:\n",location));
628 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
629 DEBUG(3,("Help File: %s:\n",driver->help_file));
630 PACKI(desc,"N",count); /* number of files to copy */
632 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
634 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
635 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
636 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
639 /* sanity check */
640 if ( i != count )
641 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
642 count, i));
644 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
646 desc->errcode=NERR_Success;
650 static const char *strip_unc(const char *unc)
652 char *p;
654 if (unc == NULL) {
655 return NULL;
658 if ((p = strrchr(unc, '\\')) != NULL) {
659 return p+1;
662 return unc;
665 static void fill_printq_info(int uLevel,
666 struct pack_desc* desc,
667 int count,
668 union spoolss_JobInfo *job_info,
669 struct spoolss_DriverInfo3 *driver_info,
670 struct spoolss_PrinterInfo2 *printer_info)
672 switch (uLevel) {
673 case 0:
674 case 1:
675 case 2:
676 PACKS(desc,"B13", strip_unc(printer_info->printername));
677 break;
678 case 3:
679 case 4:
680 case 5:
681 PACKS(desc,"z", strip_unc(printer_info->printername));
682 break;
683 case 51:
684 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
685 break;
688 if (uLevel == 1 || uLevel == 2) {
689 PACKS(desc,"B",""); /* alignment */
690 PACKI(desc,"W",5); /* priority */
691 PACKI(desc,"W",0); /* start time */
692 PACKI(desc,"W",0); /* until time */
693 PACKS(desc,"z",""); /* pSepFile */
694 PACKS(desc,"z","lpd"); /* pPrProc */
695 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
696 PACKS(desc,"z",""); /* pParms */
697 if (printer_info->printername == NULL) {
698 PACKS(desc,"z","UNKNOWN PRINTER");
699 PACKI(desc,"W",LPSTAT_ERROR);
700 } else {
701 PACKS(desc,"z", printer_info->comment);
702 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
704 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
707 if (uLevel == 3 || uLevel == 4) {
708 PACKI(desc,"W",5); /* uPriority */
709 PACKI(desc,"W",0); /* uStarttime */
710 PACKI(desc,"W",0); /* uUntiltime */
711 PACKI(desc,"W",5); /* pad1 */
712 PACKS(desc,"z",""); /* pszSepFile */
713 PACKS(desc,"z","WinPrint"); /* pszPrProc */
714 PACKS(desc,"z",NULL); /* pszParms */
715 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
716 /* "don't ask" that it's done this way to fix corrupted
717 Win9X/ME printer comments. */
718 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
719 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
720 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
721 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
722 PackDriverData(desc); /* pDriverData */
725 if (uLevel == 2 || uLevel == 4) {
726 int i;
727 for (i = 0; i < count; i++) {
728 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
732 if (uLevel==52)
733 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
736 /* This function returns the number of files for a given driver */
737 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
739 int result = 0;
741 /* count the number of files */
742 while (driver->dependent_files && *driver->dependent_files[result])
743 result++;
745 return result;
748 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
749 char *param, int tpscnt,
750 char *data, int tdscnt,
751 int mdrcnt,int mprcnt,
752 char **rdata,char **rparam,
753 int *rdata_len,int *rparam_len)
755 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
756 char *str2 = skip_string(param,tpscnt,str1);
757 char *p = skip_string(param,tpscnt,str2);
758 char *QueueName = p;
759 unsigned int uLevel;
760 uint32_t count = 0;
761 char *str3;
762 struct pack_desc desc;
763 char* tmpdata=NULL;
765 WERROR werr = WERR_OK;
766 TALLOC_CTX *mem_ctx = talloc_tos();
767 NTSTATUS status;
768 struct rpc_pipe_client *cli = NULL;
769 struct policy_handle handle;
770 struct spoolss_DevmodeContainer devmode_ctr;
771 union spoolss_DriverInfo driver_info;
772 union spoolss_JobInfo *job_info;
773 union spoolss_PrinterInfo printer_info;
775 if (!str1 || !str2 || !p) {
776 return False;
778 memset((char *)&desc,'\0',sizeof(desc));
780 p = skip_string(param,tpscnt,p);
781 if (!p) {
782 return False;
784 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
785 str3 = get_safe_str_ptr(param,tpscnt,p,4);
786 /* str3 may be null here and is checked in check_printq_info(). */
788 /* remove any trailing username */
789 if ((p = strchr_m(QueueName,'%')))
790 *p = 0;
792 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
794 /* check it's a supported varient */
795 if (!prefix_ok(str1,"zWrLh"))
796 return False;
797 if (!check_printq_info(&desc,uLevel,str2,str3)) {
799 * Patch from Scott Moomaw <scott@bridgewater.edu>
800 * to return the 'invalid info level' error if an
801 * unknown level was requested.
803 *rdata_len = 0;
804 *rparam_len = 6;
805 *rparam = smb_realloc_limit(*rparam,*rparam_len);
806 if (!*rparam) {
807 return False;
809 SSVALS(*rparam,0,ERRunknownlevel);
810 SSVAL(*rparam,2,0);
811 SSVAL(*rparam,4,0);
812 return(True);
815 ZERO_STRUCT(handle);
817 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
818 rpc_spoolss_dispatch, conn->server_info,
819 &cli);
820 if (!NT_STATUS_IS_OK(status)) {
821 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
822 nt_errstr(status)));
823 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
824 goto out;
827 ZERO_STRUCT(devmode_ctr);
829 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
830 QueueName,
831 NULL,
832 devmode_ctr,
833 SEC_FLAG_MAXIMUM_ALLOWED,
834 &handle,
835 &werr);
836 if (!NT_STATUS_IS_OK(status)) {
837 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
838 goto out;
840 if (!W_ERROR_IS_OK(werr)) {
841 desc.errcode = W_ERROR_V(werr);
842 goto out;
845 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
846 &handle,
849 &printer_info);
850 if (!W_ERROR_IS_OK(werr)) {
851 desc.errcode = W_ERROR_V(werr);
852 goto out;
855 if (uLevel==52) {
856 uint32_t server_major_version;
857 uint32_t server_minor_version;
859 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
860 &handle,
861 "Windows 4.0",
862 3, /* level */
864 0, /* version */
866 &driver_info,
867 &server_major_version,
868 &server_minor_version);
869 if (!W_ERROR_IS_OK(werr)) {
870 desc.errcode = W_ERROR_V(werr);
871 goto out;
874 count = get_printerdrivernumber(&driver_info.info3);
875 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
876 } else {
877 uint32_t num_jobs;
878 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
879 &handle,
880 0, /* firstjob */
881 0xff, /* numjobs */
882 2, /* level */
883 0, /* offered */
884 &num_jobs,
885 &job_info);
886 if (!W_ERROR_IS_OK(werr)) {
887 desc.errcode = W_ERROR_V(werr);
888 goto out;
891 count = num_jobs;
894 if (mdrcnt > 0) {
895 *rdata = smb_realloc_limit(*rdata,mdrcnt);
896 if (!*rdata) {
897 return False;
899 desc.base = *rdata;
900 desc.buflen = mdrcnt;
901 } else {
903 * Don't return data but need to get correct length
904 * init_package will return wrong size if buflen=0
906 desc.buflen = getlen(desc.format);
907 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
910 if (init_package(&desc,1,count)) {
911 desc.subcount = count;
912 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
915 *rdata_len = desc.usedlen;
918 * We must set the return code to ERRbuftoosmall
919 * in order to support lanman style printing with Win NT/2k
920 * clients --jerry
922 if (!mdrcnt && lp_disable_spoolss())
923 desc.errcode = ERRbuftoosmall;
925 out:
926 if (cli && is_valid_policy_hnd(&handle)) {
927 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
930 *rdata_len = desc.usedlen;
931 *rparam_len = 6;
932 *rparam = smb_realloc_limit(*rparam,*rparam_len);
933 if (!*rparam) {
934 SAFE_FREE(tmpdata);
935 return False;
937 SSVALS(*rparam,0,desc.errcode);
938 SSVAL(*rparam,2,0);
939 SSVAL(*rparam,4,desc.neededlen);
941 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
943 SAFE_FREE(tmpdata);
945 return(True);
948 /****************************************************************************
949 View list of all print jobs on all queues.
950 ****************************************************************************/
952 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
953 char *param, int tpscnt,
954 char *data, int tdscnt,
955 int mdrcnt, int mprcnt,
956 char **rdata, char** rparam,
957 int *rdata_len, int *rparam_len)
959 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
960 char *output_format1 = skip_string(param,tpscnt,param_format);
961 char *p = skip_string(param,tpscnt,output_format1);
962 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
963 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
964 int i;
965 struct pack_desc desc;
966 int *subcntarr = NULL;
967 int queuecnt = 0, subcnt = 0, succnt = 0;
969 WERROR werr = WERR_OK;
970 TALLOC_CTX *mem_ctx = talloc_tos();
971 NTSTATUS status;
972 struct rpc_pipe_client *cli = NULL;
973 struct spoolss_DevmodeContainer devmode_ctr;
974 uint32_t num_printers;
975 union spoolss_PrinterInfo *printer_info;
976 union spoolss_DriverInfo *driver_info;
977 union spoolss_JobInfo **job_info;
979 if (!param_format || !output_format1 || !p) {
980 return False;
983 memset((char *)&desc,'\0',sizeof(desc));
985 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
987 if (!prefix_ok(param_format,"WrLeh")) {
988 return False;
990 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
992 * Patch from Scott Moomaw <scott@bridgewater.edu>
993 * to return the 'invalid info level' error if an
994 * unknown level was requested.
996 *rdata_len = 0;
997 *rparam_len = 6;
998 *rparam = smb_realloc_limit(*rparam,*rparam_len);
999 if (!*rparam) {
1000 return False;
1002 SSVALS(*rparam,0,ERRunknownlevel);
1003 SSVAL(*rparam,2,0);
1004 SSVAL(*rparam,4,0);
1005 return(True);
1008 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
1009 rpc_spoolss_dispatch, conn->server_info,
1010 &cli);
1011 if (!NT_STATUS_IS_OK(status)) {
1012 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1013 nt_errstr(status)));
1014 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1015 goto out;
1018 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1019 PRINTER_ENUM_LOCAL,
1020 cli->srv_name_slash,
1023 &num_printers,
1024 &printer_info);
1025 if (!W_ERROR_IS_OK(werr)) {
1026 desc.errcode = W_ERROR_V(werr);
1027 goto out;
1030 queuecnt = num_printers;
1032 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1033 if (job_info == NULL) {
1034 goto err;
1037 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1038 if (driver_info == NULL) {
1039 goto err;
1042 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1043 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1044 goto err;
1047 if (mdrcnt > 0) {
1048 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1049 if (!*rdata) {
1050 goto err;
1053 desc.base = *rdata;
1054 desc.buflen = mdrcnt;
1056 subcnt = 0;
1057 for (i = 0; i < num_printers; i++) {
1059 uint32_t num_jobs;
1060 struct policy_handle handle;
1061 const char *printername;
1063 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1064 if (printername == NULL) {
1065 goto err;
1068 ZERO_STRUCT(handle);
1069 ZERO_STRUCT(devmode_ctr);
1071 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1072 printername,
1073 NULL,
1074 devmode_ctr,
1075 SEC_FLAG_MAXIMUM_ALLOWED,
1076 &handle,
1077 &werr);
1078 if (!NT_STATUS_IS_OK(status)) {
1079 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1080 goto out;
1082 if (!W_ERROR_IS_OK(werr)) {
1083 desc.errcode = W_ERROR_V(werr);
1084 goto out;
1087 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1088 &handle,
1089 0, /* firstjob */
1090 0xff, /* numjobs */
1091 2, /* level */
1092 0, /* offered */
1093 &num_jobs,
1094 &job_info[i]);
1095 if (!W_ERROR_IS_OK(werr)) {
1096 desc.errcode = W_ERROR_V(werr);
1097 goto out;
1100 if (uLevel==52) {
1101 uint32_t server_major_version;
1102 uint32_t server_minor_version;
1104 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1105 &handle,
1106 "Windows 4.0",
1107 3, /* level */
1109 0, /* version */
1111 &driver_info[i],
1112 &server_major_version,
1113 &server_minor_version);
1114 if (!W_ERROR_IS_OK(werr)) {
1115 desc.errcode = W_ERROR_V(werr);
1116 goto out;
1120 subcntarr[i] = num_jobs;
1121 subcnt += subcntarr[i];
1123 if (cli && is_valid_policy_hnd(&handle)) {
1124 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1128 if (init_package(&desc,queuecnt,subcnt)) {
1129 for (i = 0; i < num_printers; i++) {
1130 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1131 if (desc.errcode == NERR_Success) {
1132 succnt = i;
1137 SAFE_FREE(subcntarr);
1138 out:
1139 *rdata_len = desc.usedlen;
1140 *rparam_len = 8;
1141 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1142 if (!*rparam) {
1143 goto err;
1145 SSVALS(*rparam,0,desc.errcode);
1146 SSVAL(*rparam,2,0);
1147 SSVAL(*rparam,4,succnt);
1148 SSVAL(*rparam,6,queuecnt);
1150 return True;
1152 err:
1154 SAFE_FREE(subcntarr);
1156 return False;
1159 /****************************************************************************
1160 Get info level for a server list query.
1161 ****************************************************************************/
1163 static bool check_server_info(int uLevel, char* id)
1165 switch( uLevel ) {
1166 case 0:
1167 if (strcmp(id,"B16") != 0) {
1168 return False;
1170 break;
1171 case 1:
1172 if (strcmp(id,"B16BBDz") != 0) {
1173 return False;
1175 break;
1176 default:
1177 return False;
1179 return True;
1182 struct srv_info_struct {
1183 fstring name;
1184 uint32 type;
1185 fstring comment;
1186 fstring domain;
1187 bool server_added;
1190 /*******************************************************************
1191 Get server info lists from the files saved by nmbd. Return the
1192 number of entries.
1193 ******************************************************************/
1195 static int get_server_info(uint32 servertype,
1196 struct srv_info_struct **servers,
1197 const char *domain)
1199 int count=0;
1200 int alloced=0;
1201 char **lines;
1202 bool local_list_only;
1203 int i;
1205 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1206 if (!lines) {
1207 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1208 return 0;
1211 /* request for everything is code for request all servers */
1212 if (servertype == SV_TYPE_ALL) {
1213 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1216 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1218 DEBUG(4,("Servertype search: %8x\n",servertype));
1220 for (i=0;lines[i];i++) {
1221 fstring stype;
1222 struct srv_info_struct *s;
1223 const char *ptr = lines[i];
1224 bool ok = True;
1225 TALLOC_CTX *frame = NULL;
1226 char *p;
1228 if (!*ptr) {
1229 continue;
1232 if (count == alloced) {
1233 alloced += 10;
1234 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1235 if (!*servers) {
1236 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1237 TALLOC_FREE(lines);
1238 return 0;
1240 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1242 s = &(*servers)[count];
1244 frame = talloc_stackframe();
1245 s->name[0] = '\0';
1246 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1247 TALLOC_FREE(frame);
1248 continue;
1250 fstrcpy(s->name, p);
1252 stype[0] = '\0';
1253 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1254 TALLOC_FREE(frame);
1255 continue;
1257 fstrcpy(stype, p);
1259 s->comment[0] = '\0';
1260 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1261 TALLOC_FREE(frame);
1262 continue;
1264 fstrcpy(s->comment, p);
1265 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1267 s->domain[0] = '\0';
1268 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1269 /* this allows us to cope with an old nmbd */
1270 fstrcpy(s->domain,lp_workgroup());
1271 } else {
1272 fstrcpy(s->domain, p);
1274 TALLOC_FREE(frame);
1276 if (sscanf(stype,"%X",&s->type) != 1) {
1277 DEBUG(4,("r:host file "));
1278 ok = False;
1281 /* Filter the servers/domains we return based on what was asked for. */
1283 /* Check to see if we are being asked for a local list only. */
1284 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1285 DEBUG(4,("r: local list only"));
1286 ok = False;
1289 /* doesn't match up: don't want it */
1290 if (!(servertype & s->type)) {
1291 DEBUG(4,("r:serv type "));
1292 ok = False;
1295 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1296 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1297 DEBUG(4,("s: dom mismatch "));
1298 ok = False;
1301 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1302 ok = False;
1305 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1306 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1308 if (ok) {
1309 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1310 s->name, s->type, s->comment, s->domain));
1311 s->server_added = True;
1312 count++;
1313 } else {
1314 DEBUG(4,("%20s %8x %25s %15s\n",
1315 s->name, s->type, s->comment, s->domain));
1319 TALLOC_FREE(lines);
1320 return count;
1323 /*******************************************************************
1324 Fill in a server info structure.
1325 ******************************************************************/
1327 static int fill_srv_info(struct srv_info_struct *service,
1328 int uLevel, char **buf, int *buflen,
1329 char **stringbuf, int *stringspace, char *baseaddr)
1331 int struct_len;
1332 char* p;
1333 char* p2;
1334 int l2;
1335 int len;
1337 switch (uLevel) {
1338 case 0:
1339 struct_len = 16;
1340 break;
1341 case 1:
1342 struct_len = 26;
1343 break;
1344 default:
1345 return -1;
1348 if (!buf) {
1349 len = 0;
1350 switch (uLevel) {
1351 case 1:
1352 len = strlen(service->comment)+1;
1353 break;
1356 *buflen = struct_len;
1357 *stringspace = len;
1358 return struct_len + len;
1361 len = struct_len;
1362 p = *buf;
1363 if (*buflen < struct_len) {
1364 return -1;
1366 if (stringbuf) {
1367 p2 = *stringbuf;
1368 l2 = *stringspace;
1369 } else {
1370 p2 = p + struct_len;
1371 l2 = *buflen - struct_len;
1373 if (!baseaddr) {
1374 baseaddr = p;
1377 switch (uLevel) {
1378 case 0:
1379 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1380 break;
1382 case 1:
1383 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1384 SIVAL(p,18,service->type);
1385 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1386 len += CopyAndAdvance(&p2,service->comment,&l2);
1387 break;
1390 if (stringbuf) {
1391 *buf = p + struct_len;
1392 *buflen -= struct_len;
1393 *stringbuf = p2;
1394 *stringspace = l2;
1395 } else {
1396 *buf = p2;
1397 *buflen -= len;
1399 return len;
1403 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1405 return StrCaseCmp(s1->name,s2->name);
1408 /****************************************************************************
1409 View list of servers available (or possibly domains). The info is
1410 extracted from lists saved by nmbd on the local host.
1411 ****************************************************************************/
1413 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1414 char *param, int tpscnt,
1415 char *data, int tdscnt,
1416 int mdrcnt, int mprcnt, char **rdata,
1417 char **rparam, int *rdata_len, int *rparam_len)
1419 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1420 char *str2 = skip_string(param,tpscnt,str1);
1421 char *p = skip_string(param,tpscnt,str2);
1422 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1423 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1424 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1425 char *p2;
1426 int data_len, fixed_len, string_len;
1427 int f_len = 0, s_len = 0;
1428 struct srv_info_struct *servers=NULL;
1429 int counted=0,total=0;
1430 int i,missed;
1431 fstring domain;
1432 bool domain_request;
1433 bool local_request;
1435 if (!str1 || !str2 || !p) {
1436 return False;
1439 /* If someone sets all the bits they don't really mean to set
1440 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1441 known servers. */
1443 if (servertype == SV_TYPE_ALL) {
1444 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1447 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1448 any other bit (they may just set this bit on its own) they
1449 want all the locally seen servers. However this bit can be
1450 set on its own so set the requested servers to be
1451 ALL - DOMAIN_ENUM. */
1453 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1454 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1457 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1458 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1460 p += 8;
1462 if (!prefix_ok(str1,"WrLehD")) {
1463 return False;
1465 if (!check_server_info(uLevel,str2)) {
1466 return False;
1469 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1470 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1471 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1473 if (strcmp(str1, "WrLehDz") == 0) {
1474 if (skip_string(param,tpscnt,p) == NULL) {
1475 return False;
1477 pull_ascii_fstring(domain, p);
1478 } else {
1479 fstrcpy(domain, lp_workgroup());
1482 DEBUG(4, ("domain [%s]\n", domain));
1484 if (lp_browse_list()) {
1485 total = get_server_info(servertype,&servers,domain);
1488 data_len = fixed_len = string_len = 0;
1489 missed = 0;
1491 TYPESAFE_QSORT(servers, total, srv_comp);
1494 char *lastname=NULL;
1496 for (i=0;i<total;i++) {
1497 struct srv_info_struct *s = &servers[i];
1499 if (lastname && strequal(lastname,s->name)) {
1500 continue;
1502 lastname = s->name;
1503 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1504 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1505 i, s->name, s->type, s->comment, s->domain));
1507 if (data_len < buf_len) {
1508 counted++;
1509 fixed_len += f_len;
1510 string_len += s_len;
1511 } else {
1512 missed++;
1517 *rdata_len = fixed_len + string_len;
1518 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1519 if (!*rdata) {
1520 return False;
1523 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1524 p = *rdata;
1525 f_len = fixed_len;
1526 s_len = string_len;
1529 char *lastname=NULL;
1530 int count2 = counted;
1532 for (i = 0; i < total && count2;i++) {
1533 struct srv_info_struct *s = &servers[i];
1535 if (lastname && strequal(lastname,s->name)) {
1536 continue;
1538 lastname = s->name;
1539 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1540 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1541 i, s->name, s->type, s->comment, s->domain));
1542 count2--;
1546 *rparam_len = 8;
1547 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1548 if (!*rparam) {
1549 return False;
1551 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1552 SSVAL(*rparam,2,0);
1553 SSVAL(*rparam,4,counted);
1554 SSVAL(*rparam,6,counted+missed);
1556 SAFE_FREE(servers);
1558 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1559 domain,uLevel,counted,counted+missed));
1561 return True;
1564 static int srv_name_match(const char *n1, const char *n2)
1567 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1569 * In Windows, FirstNameToReturn need not be an exact match:
1570 * the server will return a list of servers that exist on
1571 * the network greater than or equal to the FirstNameToReturn.
1573 int ret = StrCaseCmp(n1, n2);
1575 if (ret <= 0) {
1576 return 0;
1579 return ret;
1582 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1583 char *param, int tpscnt,
1584 char *data, int tdscnt,
1585 int mdrcnt, int mprcnt, char **rdata,
1586 char **rparam, int *rdata_len, int *rparam_len)
1588 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1589 char *str2 = skip_string(param,tpscnt,str1);
1590 char *p = skip_string(param,tpscnt,str2);
1591 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1592 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1593 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1594 char *p2;
1595 int data_len, fixed_len, string_len;
1596 int f_len = 0, s_len = 0;
1597 struct srv_info_struct *servers=NULL;
1598 int counted=0,first=0,total=0;
1599 int i,missed;
1600 fstring domain;
1601 fstring first_name;
1602 bool domain_request;
1603 bool local_request;
1605 if (!str1 || !str2 || !p) {
1606 return False;
1609 /* If someone sets all the bits they don't really mean to set
1610 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1611 known servers. */
1613 if (servertype == SV_TYPE_ALL) {
1614 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1617 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1618 any other bit (they may just set this bit on its own) they
1619 want all the locally seen servers. However this bit can be
1620 set on its own so set the requested servers to be
1621 ALL - DOMAIN_ENUM. */
1623 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1624 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1627 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1628 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1630 p += 8;
1632 if (strcmp(str1, "WrLehDzz") != 0) {
1633 return false;
1635 if (!check_server_info(uLevel,str2)) {
1636 return False;
1639 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1640 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1641 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1643 if (skip_string(param,tpscnt,p) == NULL) {
1644 return False;
1646 pull_ascii_fstring(domain, p);
1647 if (domain[0] == '\0') {
1648 fstrcpy(domain, lp_workgroup());
1650 p = skip_string(param,tpscnt,p);
1651 if (skip_string(param,tpscnt,p) == NULL) {
1652 return False;
1654 pull_ascii_fstring(first_name, p);
1656 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1657 domain, first_name));
1659 if (lp_browse_list()) {
1660 total = get_server_info(servertype,&servers,domain);
1663 data_len = fixed_len = string_len = 0;
1664 missed = 0;
1666 TYPESAFE_QSORT(servers, total, srv_comp);
1668 if (first_name[0] != '\0') {
1669 struct srv_info_struct *first_server = NULL;
1671 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1672 srv_name_match, first_server);
1673 if (first_server) {
1674 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1676 * The binary search may not find the exact match
1677 * so we need to search backward to find the first match
1679 * This implements the strange matching windows
1680 * implements. (see the comment in srv_name_match().
1682 for (;first > 0;) {
1683 int ret;
1684 ret = StrCaseCmp(first_name,
1685 servers[first-1].name);
1686 if (ret > 0) {
1687 break;
1689 first--;
1691 } else {
1692 /* we should return no entries */
1693 first = total;
1698 char *lastname=NULL;
1700 for (i=first;i<total;i++) {
1701 struct srv_info_struct *s = &servers[i];
1703 if (lastname && strequal(lastname,s->name)) {
1704 continue;
1706 lastname = s->name;
1707 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1708 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1709 i, s->name, s->type, s->comment, s->domain));
1711 if (data_len < buf_len) {
1712 counted++;
1713 fixed_len += f_len;
1714 string_len += s_len;
1715 } else {
1716 missed++;
1721 *rdata_len = fixed_len + string_len;
1722 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1723 if (!*rdata) {
1724 return False;
1727 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1728 p = *rdata;
1729 f_len = fixed_len;
1730 s_len = string_len;
1733 char *lastname=NULL;
1734 int count2 = counted;
1736 for (i = first; i < total && count2;i++) {
1737 struct srv_info_struct *s = &servers[i];
1739 if (lastname && strequal(lastname,s->name)) {
1740 continue;
1742 lastname = s->name;
1743 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1744 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1745 i, s->name, s->type, s->comment, s->domain));
1746 count2--;
1750 *rparam_len = 8;
1751 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1752 if (!*rparam) {
1753 return False;
1755 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1756 SSVAL(*rparam,2,0);
1757 SSVAL(*rparam,4,counted);
1758 SSVAL(*rparam,6,counted+missed);
1760 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1761 domain,uLevel,first,first_name,
1762 first < total ? servers[first].name : "",
1763 counted,counted+missed));
1765 SAFE_FREE(servers);
1767 return True;
1770 /****************************************************************************
1771 command 0x34 - suspected of being a "Lookup Names" stub api
1772 ****************************************************************************/
1774 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1775 char *param, int tpscnt,
1776 char *data, int tdscnt,
1777 int mdrcnt, int mprcnt, char **rdata,
1778 char **rparam, int *rdata_len, int *rparam_len)
1780 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1781 char *str2 = skip_string(param,tpscnt,str1);
1782 char *p = skip_string(param,tpscnt,str2);
1783 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1784 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1785 int counted=0;
1786 int missed=0;
1788 if (!str1 || !str2 || !p) {
1789 return False;
1792 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1793 str1, str2, p, uLevel, buf_len));
1795 if (!prefix_ok(str1,"zWrLeh")) {
1796 return False;
1799 *rdata_len = 0;
1801 *rparam_len = 8;
1802 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1803 if (!*rparam) {
1804 return False;
1807 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1808 SSVAL(*rparam,2,0);
1809 SSVAL(*rparam,4,counted);
1810 SSVAL(*rparam,6,counted+missed);
1812 return True;
1815 /****************************************************************************
1816 get info about a share
1817 ****************************************************************************/
1819 static bool check_share_info(int uLevel, char* id)
1821 switch( uLevel ) {
1822 case 0:
1823 if (strcmp(id,"B13") != 0) {
1824 return False;
1826 break;
1827 case 1:
1828 /* Level-2 descriptor is allowed (and ignored) */
1829 if (strcmp(id,"B13BWz") != 0 &&
1830 strcmp(id,"B13BWzWWWzB9B") != 0) {
1831 return False;
1833 break;
1834 case 2:
1835 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1836 return False;
1838 break;
1839 case 91:
1840 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1841 return False;
1843 break;
1844 default:
1845 return False;
1847 return True;
1850 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1851 char** buf, int* buflen,
1852 char** stringbuf, int* stringspace, char* baseaddr)
1854 int struct_len;
1855 char* p;
1856 char* p2;
1857 int l2;
1858 int len;
1860 switch( uLevel ) {
1861 case 0:
1862 struct_len = 13;
1863 break;
1864 case 1:
1865 struct_len = 20;
1866 break;
1867 case 2:
1868 struct_len = 40;
1869 break;
1870 case 91:
1871 struct_len = 68;
1872 break;
1873 default:
1874 return -1;
1877 if (!buf) {
1878 len = 0;
1880 if (uLevel > 0) {
1881 len += StrlenExpanded(conn,snum,lp_comment(snum));
1883 if (uLevel > 1) {
1884 len += strlen(lp_pathname(snum)) + 1;
1886 if (buflen) {
1887 *buflen = struct_len;
1889 if (stringspace) {
1890 *stringspace = len;
1892 return struct_len + len;
1895 len = struct_len;
1896 p = *buf;
1897 if ((*buflen) < struct_len) {
1898 return -1;
1901 if (stringbuf) {
1902 p2 = *stringbuf;
1903 l2 = *stringspace;
1904 } else {
1905 p2 = p + struct_len;
1906 l2 = (*buflen) - struct_len;
1909 if (!baseaddr) {
1910 baseaddr = p;
1913 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1915 if (uLevel > 0) {
1916 int type;
1918 SCVAL(p,13,0);
1919 type = STYPE_DISKTREE;
1920 if (lp_print_ok(snum)) {
1921 type = STYPE_PRINTQ;
1923 if (strequal("IPC",lp_fstype(snum))) {
1924 type = STYPE_IPC;
1926 SSVAL(p,14,type); /* device type */
1927 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1928 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1931 if (uLevel > 1) {
1932 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1933 SSVALS(p,22,-1); /* max uses */
1934 SSVAL(p,24,1); /* current uses */
1935 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1936 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1937 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1940 if (uLevel > 2) {
1941 memset(p+40,0,SHPWLEN+2);
1942 SSVAL(p,50,0);
1943 SIVAL(p,52,0);
1944 SSVAL(p,56,0);
1945 SSVAL(p,58,0);
1946 SIVAL(p,60,0);
1947 SSVAL(p,64,0);
1948 SSVAL(p,66,0);
1951 if (stringbuf) {
1952 (*buf) = p + struct_len;
1953 (*buflen) -= struct_len;
1954 (*stringbuf) = p2;
1955 (*stringspace) = l2;
1956 } else {
1957 (*buf) = p2;
1958 (*buflen) -= len;
1961 return len;
1964 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1965 char *param, int tpscnt,
1966 char *data, int tdscnt,
1967 int mdrcnt,int mprcnt,
1968 char **rdata,char **rparam,
1969 int *rdata_len,int *rparam_len)
1971 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1972 char *str2 = skip_string(param,tpscnt,str1);
1973 char *netname = skip_string(param,tpscnt,str2);
1974 char *p = skip_string(param,tpscnt,netname);
1975 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1976 int snum;
1978 if (!str1 || !str2 || !netname || !p) {
1979 return False;
1982 snum = find_service(netname);
1983 if (snum < 0) {
1984 return False;
1987 /* check it's a supported varient */
1988 if (!prefix_ok(str1,"zWrLh")) {
1989 return False;
1991 if (!check_share_info(uLevel,str2)) {
1992 return False;
1995 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1996 if (!*rdata) {
1997 return False;
1999 p = *rdata;
2000 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2001 if (*rdata_len < 0) {
2002 return False;
2005 *rparam_len = 6;
2006 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2007 if (!*rparam) {
2008 return False;
2010 SSVAL(*rparam,0,NERR_Success);
2011 SSVAL(*rparam,2,0); /* converter word */
2012 SSVAL(*rparam,4,*rdata_len);
2014 return True;
2017 /****************************************************************************
2018 View the list of available shares.
2020 This function is the server side of the NetShareEnum() RAP call.
2021 It fills the return buffer with share names and share comments.
2022 Note that the return buffer normally (in all known cases) allows only
2023 twelve byte strings for share names (plus one for a nul terminator).
2024 Share names longer than 12 bytes must be skipped.
2025 ****************************************************************************/
2027 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2028 char *param, int tpscnt,
2029 char *data, int tdscnt,
2030 int mdrcnt,
2031 int mprcnt,
2032 char **rdata,
2033 char **rparam,
2034 int *rdata_len,
2035 int *rparam_len )
2037 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2038 char *str2 = skip_string(param,tpscnt,str1);
2039 char *p = skip_string(param,tpscnt,str2);
2040 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2041 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2042 char *p2;
2043 int count = 0;
2044 int total=0,counted=0;
2045 bool missed = False;
2046 int i;
2047 int data_len, fixed_len, string_len;
2048 int f_len = 0, s_len = 0;
2050 if (!str1 || !str2 || !p) {
2051 return False;
2054 if (!prefix_ok(str1,"WrLeh")) {
2055 return False;
2057 if (!check_share_info(uLevel,str2)) {
2058 return False;
2061 /* Ensure all the usershares are loaded. */
2062 become_root();
2063 load_registry_shares();
2064 count = load_usershare_shares();
2065 unbecome_root();
2067 data_len = fixed_len = string_len = 0;
2068 for (i=0;i<count;i++) {
2069 fstring servicename_dos;
2070 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2071 continue;
2073 push_ascii_fstring(servicename_dos, lp_servicename(i));
2074 /* Maximum name length = 13. */
2075 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2076 total++;
2077 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2078 if (data_len < buf_len) {
2079 counted++;
2080 fixed_len += f_len;
2081 string_len += s_len;
2082 } else {
2083 missed = True;
2088 *rdata_len = fixed_len + string_len;
2089 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2090 if (!*rdata) {
2091 return False;
2094 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2095 p = *rdata;
2096 f_len = fixed_len;
2097 s_len = string_len;
2099 for( i = 0; i < count; i++ ) {
2100 fstring servicename_dos;
2101 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2102 continue;
2105 push_ascii_fstring(servicename_dos, lp_servicename(i));
2106 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2107 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2108 break;
2113 *rparam_len = 8;
2114 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2115 if (!*rparam) {
2116 return False;
2118 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2119 SSVAL(*rparam,2,0);
2120 SSVAL(*rparam,4,counted);
2121 SSVAL(*rparam,6,total);
2123 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2124 counted,total,uLevel,
2125 buf_len,*rdata_len,mdrcnt));
2127 return True;
2130 /****************************************************************************
2131 Add a share
2132 ****************************************************************************/
2134 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2135 char *param, int tpscnt,
2136 char *data, int tdscnt,
2137 int mdrcnt,int mprcnt,
2138 char **rdata,char **rparam,
2139 int *rdata_len,int *rparam_len)
2141 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2142 char *str2 = skip_string(param,tpscnt,str1);
2143 char *p = skip_string(param,tpscnt,str2);
2144 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2145 fstring sharename;
2146 fstring comment;
2147 char *pathname = NULL;
2148 unsigned int offset;
2149 int res = ERRunsup;
2150 size_t converted_size;
2152 WERROR werr = WERR_OK;
2153 TALLOC_CTX *mem_ctx = talloc_tos();
2154 NTSTATUS status;
2155 struct rpc_pipe_client *cli = NULL;
2156 union srvsvc_NetShareInfo info;
2157 struct srvsvc_NetShareInfo2 info2;
2159 if (!str1 || !str2 || !p) {
2160 return False;
2163 /* check it's a supported varient */
2164 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2165 return False;
2167 if (!check_share_info(uLevel,str2)) {
2168 return False;
2170 if (uLevel != 2) {
2171 return False;
2174 /* Do we have a string ? */
2175 if (skip_string(data,mdrcnt,data) == NULL) {
2176 return False;
2178 pull_ascii_fstring(sharename,data);
2180 if (mdrcnt < 28) {
2181 return False;
2184 /* only support disk share adds */
2185 if (SVAL(data,14)!=STYPE_DISKTREE) {
2186 return False;
2189 offset = IVAL(data, 16);
2190 if (offset >= mdrcnt) {
2191 res = ERRinvalidparam;
2192 goto out;
2195 /* Do we have a string ? */
2196 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2197 return False;
2199 pull_ascii_fstring(comment, offset? (data+offset) : "");
2201 offset = IVAL(data, 26);
2203 if (offset >= mdrcnt) {
2204 res = ERRinvalidparam;
2205 goto out;
2208 /* Do we have a string ? */
2209 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2210 return False;
2213 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2214 offset ? (data+offset) : "", &converted_size))
2216 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2217 strerror(errno)));
2220 if (!pathname) {
2221 return false;
2224 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2225 rpc_srvsvc_dispatch, conn->server_info,
2226 &cli);
2227 if (!NT_STATUS_IS_OK(status)) {
2228 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2229 nt_errstr(status)));
2230 res = W_ERROR_V(ntstatus_to_werror(status));
2231 goto out;
2234 info2.name = sharename;
2235 info2.type = STYPE_DISKTREE;
2236 info2.comment = comment;
2237 info2.permissions = 0;
2238 info2.max_users = 0;
2239 info2.current_users = 0;
2240 info2.path = pathname;
2241 info2.password = NULL;
2243 info.info2 = &info2;
2245 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2246 cli->srv_name_slash,
2248 &info,
2249 NULL,
2250 &werr);
2251 if (!NT_STATUS_IS_OK(status)) {
2252 res = W_ERROR_V(ntstatus_to_werror(status));
2253 goto out;
2255 if (!W_ERROR_IS_OK(werr)) {
2256 res = W_ERROR_V(werr);
2257 goto out;
2260 *rparam_len = 6;
2261 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2262 if (!*rparam) {
2263 return False;
2265 SSVAL(*rparam,0,NERR_Success);
2266 SSVAL(*rparam,2,0); /* converter word */
2267 SSVAL(*rparam,4,*rdata_len);
2268 *rdata_len = 0;
2270 return True;
2272 out:
2274 *rparam_len = 4;
2275 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2276 if (!*rparam) {
2277 return False;
2279 *rdata_len = 0;
2280 SSVAL(*rparam,0,res);
2281 SSVAL(*rparam,2,0);
2282 return True;
2285 /****************************************************************************
2286 view list of groups available
2287 ****************************************************************************/
2289 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2290 char *param, int tpscnt,
2291 char *data, int tdscnt,
2292 int mdrcnt,int mprcnt,
2293 char **rdata,char **rparam,
2294 int *rdata_len,int *rparam_len)
2296 int i;
2297 int errflags=0;
2298 int resume_context, cli_buf_size;
2299 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2300 char *str2 = skip_string(param,tpscnt,str1);
2301 char *p = skip_string(param,tpscnt,str2);
2303 uint32_t num_groups;
2304 uint32_t resume_handle;
2305 struct rpc_pipe_client *samr_pipe;
2306 struct policy_handle samr_handle, domain_handle;
2307 NTSTATUS status;
2309 if (!str1 || !str2 || !p) {
2310 return False;
2313 if (strcmp(str1,"WrLeh") != 0) {
2314 return False;
2317 /* parameters
2318 * W-> resume context (number of users to skip)
2319 * r -> return parameter pointer to receive buffer
2320 * L -> length of receive buffer
2321 * e -> return parameter number of entries
2322 * h -> return parameter total number of users
2325 if (strcmp("B21",str2) != 0) {
2326 return False;
2329 status = rpc_pipe_open_internal(
2330 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2331 conn->server_info, &samr_pipe);
2332 if (!NT_STATUS_IS_OK(status)) {
2333 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2334 nt_errstr(status)));
2335 return false;
2338 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2339 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2340 if (!NT_STATUS_IS_OK(status)) {
2341 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2342 nt_errstr(status)));
2343 return false;
2346 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2347 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2348 get_global_sam_sid(), &domain_handle);
2349 if (!NT_STATUS_IS_OK(status)) {
2350 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2351 nt_errstr(status)));
2352 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2353 return false;
2356 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2357 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2358 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2359 "%d\n", resume_context, cli_buf_size));
2361 *rdata_len = cli_buf_size;
2362 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2363 if (!*rdata) {
2364 return False;
2367 p = *rdata;
2369 errflags = NERR_Success;
2370 num_groups = 0;
2371 resume_handle = 0;
2373 while (true) {
2374 struct samr_SamArray *sam_entries;
2375 uint32_t num_entries;
2377 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2378 &domain_handle,
2379 &resume_handle,
2380 &sam_entries, 1,
2381 &num_entries);
2382 if (!NT_STATUS_IS_OK(status)) {
2383 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2384 "%s\n", nt_errstr(status)));
2385 break;
2388 if (num_entries == 0) {
2389 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2390 "no entries -- done\n"));
2391 break;
2394 for(i=0; i<num_entries; i++) {
2395 const char *name;
2397 name = sam_entries->entries[i].name.string;
2399 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2400 /* set overflow error */
2401 DEBUG(3,("overflow on entry %d group %s\n", i,
2402 name));
2403 errflags=234;
2404 break;
2407 /* truncate the name at 21 chars. */
2408 memset(p, 0, 21);
2409 strlcpy(p, name, 21);
2410 DEBUG(10,("adding entry %d group %s\n", i, p));
2411 p += 21;
2412 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2413 * idea why... */
2414 num_groups += 1;
2417 if (errflags != NERR_Success) {
2418 break;
2421 TALLOC_FREE(sam_entries);
2424 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2425 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2427 *rdata_len = PTR_DIFF(p,*rdata);
2429 *rparam_len = 8;
2430 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2431 if (!*rparam) {
2432 return False;
2434 SSVAL(*rparam, 0, errflags);
2435 SSVAL(*rparam, 2, 0); /* converter word */
2436 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2437 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2439 return(True);
2442 /*******************************************************************
2443 Get groups that a user is a member of.
2444 ******************************************************************/
2446 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2447 char *param, int tpscnt,
2448 char *data, int tdscnt,
2449 int mdrcnt,int mprcnt,
2450 char **rdata,char **rparam,
2451 int *rdata_len,int *rparam_len)
2453 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2454 char *str2 = skip_string(param,tpscnt,str1);
2455 char *UserName = skip_string(param,tpscnt,str2);
2456 char *p = skip_string(param,tpscnt,UserName);
2457 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2458 const char *level_string;
2459 int count=0;
2460 bool ret = False;
2461 uint32_t i;
2462 char *endp = NULL;
2464 struct rpc_pipe_client *samr_pipe;
2465 struct policy_handle samr_handle, domain_handle, user_handle;
2466 struct lsa_String name;
2467 struct lsa_Strings names;
2468 struct samr_Ids type, rid;
2469 struct samr_RidWithAttributeArray *rids;
2470 NTSTATUS status;
2472 if (!str1 || !str2 || !UserName || !p) {
2473 return False;
2476 *rparam_len = 8;
2477 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2478 if (!*rparam) {
2479 return False;
2482 /* check it's a supported varient */
2484 if ( strcmp(str1,"zWrLeh") != 0 )
2485 return False;
2487 switch( uLevel ) {
2488 case 0:
2489 level_string = "B21";
2490 break;
2491 default:
2492 return False;
2495 if (strcmp(level_string,str2) != 0)
2496 return False;
2498 *rdata_len = mdrcnt + 1024;
2499 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2500 if (!*rdata) {
2501 return False;
2504 SSVAL(*rparam,0,NERR_Success);
2505 SSVAL(*rparam,2,0); /* converter word */
2507 p = *rdata;
2508 endp = *rdata + *rdata_len;
2510 status = rpc_pipe_open_internal(
2511 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2512 conn->server_info, &samr_pipe);
2513 if (!NT_STATUS_IS_OK(status)) {
2514 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2515 nt_errstr(status)));
2516 return false;
2519 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2520 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2521 if (!NT_STATUS_IS_OK(status)) {
2522 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2523 nt_errstr(status)));
2524 return false;
2527 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2528 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2529 get_global_sam_sid(), &domain_handle);
2530 if (!NT_STATUS_IS_OK(status)) {
2531 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2532 nt_errstr(status)));
2533 goto close_sam;
2536 name.string = UserName;
2538 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2539 &domain_handle, 1, &name,
2540 &rid, &type);
2541 if (!NT_STATUS_IS_OK(status)) {
2542 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2543 nt_errstr(status)));
2544 goto close_domain;
2547 if (type.ids[0] != SID_NAME_USER) {
2548 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2549 sid_type_lookup(type.ids[0])));
2550 goto close_domain;
2553 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2554 &domain_handle,
2555 SAMR_USER_ACCESS_GET_GROUPS,
2556 rid.ids[0], &user_handle);
2557 if (!NT_STATUS_IS_OK(status)) {
2558 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2559 nt_errstr(status)));
2560 goto close_domain;
2563 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2564 &user_handle, &rids);
2565 if (!NT_STATUS_IS_OK(status)) {
2566 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2567 nt_errstr(status)));
2568 goto close_user;
2571 for (i=0; i<rids->count; i++) {
2573 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2574 &domain_handle,
2575 1, &rids->rids[i].rid,
2576 &names, &type);
2577 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2578 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2579 p += 21;
2580 count++;
2584 *rdata_len = PTR_DIFF(p,*rdata);
2586 SSVAL(*rparam,4,count); /* is this right?? */
2587 SSVAL(*rparam,6,count); /* is this right?? */
2589 ret = True;
2591 close_user:
2592 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2593 close_domain:
2594 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2595 close_sam:
2596 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2598 return ret;
2601 /*******************************************************************
2602 Get all users.
2603 ******************************************************************/
2605 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2606 char *param, int tpscnt,
2607 char *data, int tdscnt,
2608 int mdrcnt,int mprcnt,
2609 char **rdata,char **rparam,
2610 int *rdata_len,int *rparam_len)
2612 int count_sent=0;
2613 int num_users=0;
2614 int errflags=0;
2615 int i, resume_context, cli_buf_size;
2616 uint32_t resume_handle;
2618 struct rpc_pipe_client *samr_pipe;
2619 struct policy_handle samr_handle, domain_handle;
2620 NTSTATUS status;
2622 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2623 char *str2 = skip_string(param,tpscnt,str1);
2624 char *p = skip_string(param,tpscnt,str2);
2625 char *endp = NULL;
2627 if (!str1 || !str2 || !p) {
2628 return False;
2631 if (strcmp(str1,"WrLeh") != 0)
2632 return False;
2633 /* parameters
2634 * W-> resume context (number of users to skip)
2635 * r -> return parameter pointer to receive buffer
2636 * L -> length of receive buffer
2637 * e -> return parameter number of entries
2638 * h -> return parameter total number of users
2641 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2642 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2643 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2644 resume_context, cli_buf_size));
2646 *rparam_len = 8;
2647 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2648 if (!*rparam) {
2649 return False;
2652 /* check it's a supported varient */
2653 if (strcmp("B21",str2) != 0)
2654 return False;
2656 *rdata_len = cli_buf_size;
2657 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2658 if (!*rdata) {
2659 return False;
2662 p = *rdata;
2663 endp = *rdata + *rdata_len;
2665 status = rpc_pipe_open_internal(
2666 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2667 conn->server_info, &samr_pipe);
2668 if (!NT_STATUS_IS_OK(status)) {
2669 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2670 nt_errstr(status)));
2671 return false;
2674 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2675 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2676 if (!NT_STATUS_IS_OK(status)) {
2677 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2678 nt_errstr(status)));
2679 return false;
2682 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2683 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2684 get_global_sam_sid(), &domain_handle);
2685 if (!NT_STATUS_IS_OK(status)) {
2686 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2687 nt_errstr(status)));
2688 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2689 return false;
2692 errflags=NERR_Success;
2694 resume_handle = 0;
2696 while (true) {
2697 struct samr_SamArray *sam_entries;
2698 uint32_t num_entries;
2700 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2701 &domain_handle,
2702 &resume_handle,
2703 0, &sam_entries, 1,
2704 &num_entries);
2706 if (!NT_STATUS_IS_OK(status)) {
2707 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2708 "%s\n", nt_errstr(status)));
2709 break;
2712 if (num_entries == 0) {
2713 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2714 "no entries -- done\n"));
2715 break;
2718 for (i=0; i<num_entries; i++) {
2719 const char *name;
2721 name = sam_entries->entries[i].name.string;
2723 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2724 &&(strlen(name)<=21)) {
2725 strlcpy(p,name,PTR_DIFF(endp,p));
2726 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2727 "username %s\n",count_sent,p));
2728 p += 21;
2729 count_sent++;
2730 } else {
2731 /* set overflow error */
2732 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2733 "username %s\n",count_sent,name));
2734 errflags=234;
2735 break;
2739 if (errflags != NERR_Success) {
2740 break;
2743 TALLOC_FREE(sam_entries);
2746 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2747 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2749 *rdata_len = PTR_DIFF(p,*rdata);
2751 SSVAL(*rparam,0,errflags);
2752 SSVAL(*rparam,2,0); /* converter word */
2753 SSVAL(*rparam,4,count_sent); /* is this right?? */
2754 SSVAL(*rparam,6,num_users); /* is this right?? */
2756 return True;
2759 /****************************************************************************
2760 Get the time of day info.
2761 ****************************************************************************/
2763 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2764 char *param, int tpscnt,
2765 char *data, int tdscnt,
2766 int mdrcnt,int mprcnt,
2767 char **rdata,char **rparam,
2768 int *rdata_len,int *rparam_len)
2770 struct tm *t;
2771 time_t unixdate = time(NULL);
2772 char *p;
2774 *rparam_len = 4;
2775 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2776 if (!*rparam) {
2777 return False;
2780 *rdata_len = 21;
2781 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2782 if (!*rdata) {
2783 return False;
2786 SSVAL(*rparam,0,NERR_Success);
2787 SSVAL(*rparam,2,0); /* converter word */
2789 p = *rdata;
2791 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2792 by NT in a "net time" operation,
2793 it seems to ignore the one below */
2795 /* the client expects to get localtime, not GMT, in this bit
2796 (I think, this needs testing) */
2797 t = localtime(&unixdate);
2798 if (!t) {
2799 return False;
2802 SIVAL(p,4,0); /* msecs ? */
2803 SCVAL(p,8,t->tm_hour);
2804 SCVAL(p,9,t->tm_min);
2805 SCVAL(p,10,t->tm_sec);
2806 SCVAL(p,11,0); /* hundredths of seconds */
2807 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2808 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2809 SCVAL(p,16,t->tm_mday);
2810 SCVAL(p,17,t->tm_mon + 1);
2811 SSVAL(p,18,1900+t->tm_year);
2812 SCVAL(p,20,t->tm_wday);
2814 return True;
2817 /****************************************************************************
2818 Set the user password.
2819 *****************************************************************************/
2821 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2822 char *param, int tpscnt,
2823 char *data, int tdscnt,
2824 int mdrcnt,int mprcnt,
2825 char **rdata,char **rparam,
2826 int *rdata_len,int *rparam_len)
2828 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2829 char *p = NULL;
2830 fstring user;
2831 fstring pass1,pass2;
2833 /* Skip 2 strings. */
2834 p = skip_string(param,tpscnt,np);
2835 p = skip_string(param,tpscnt,p);
2837 if (!np || !p) {
2838 return False;
2841 /* Do we have a string ? */
2842 if (skip_string(param,tpscnt,p) == NULL) {
2843 return False;
2845 pull_ascii_fstring(user,p);
2847 p = skip_string(param,tpscnt,p);
2848 if (!p) {
2849 return False;
2852 memset(pass1,'\0',sizeof(pass1));
2853 memset(pass2,'\0',sizeof(pass2));
2855 * We use 31 here not 32 as we're checking
2856 * the last byte we want to access is safe.
2858 if (!is_offset_safe(param,tpscnt,p,31)) {
2859 return False;
2861 memcpy(pass1,p,16);
2862 memcpy(pass2,p+16,16);
2864 *rparam_len = 4;
2865 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2866 if (!*rparam) {
2867 return False;
2870 *rdata_len = 0;
2872 SSVAL(*rparam,0,NERR_badpass);
2873 SSVAL(*rparam,2,0); /* converter word */
2875 DEBUG(3,("Set password for <%s>\n",user));
2878 * Attempt to verify the old password against smbpasswd entries
2879 * Win98 clients send old and new password in plaintext for this call.
2883 struct auth_serversupplied_info *server_info = NULL;
2884 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2886 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2888 become_root();
2889 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2890 SSVAL(*rparam,0,NERR_Success);
2892 unbecome_root();
2894 TALLOC_FREE(server_info);
2896 data_blob_clear_free(&password);
2900 * If the plaintext change failed, attempt
2901 * the old encrypted method. NT will generate this
2902 * after trying the samr method. Note that this
2903 * method is done as a last resort as this
2904 * password change method loses the NT password hash
2905 * and cannot change the UNIX password as no plaintext
2906 * is received.
2909 if(SVAL(*rparam,0) != NERR_Success) {
2910 struct samu *hnd = NULL;
2912 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2913 become_root();
2914 if (change_lanman_password(hnd,(uchar *)pass2)) {
2915 SSVAL(*rparam,0,NERR_Success);
2917 unbecome_root();
2918 TALLOC_FREE(hnd);
2922 memset((char *)pass1,'\0',sizeof(fstring));
2923 memset((char *)pass2,'\0',sizeof(fstring));
2925 return(True);
2928 /****************************************************************************
2929 Set the user password (SamOEM version - gets plaintext).
2930 ****************************************************************************/
2932 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2933 char *param, int tpscnt,
2934 char *data, int tdscnt,
2935 int mdrcnt,int mprcnt,
2936 char **rdata,char **rparam,
2937 int *rdata_len,int *rparam_len)
2939 fstring user;
2940 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2942 TALLOC_CTX *mem_ctx = talloc_tos();
2943 NTSTATUS status;
2944 struct rpc_pipe_client *cli = NULL;
2945 struct lsa_AsciiString server, account;
2946 struct samr_CryptPassword password;
2947 struct samr_Password hash;
2948 int errcode = NERR_badpass;
2949 int bufsize;
2951 *rparam_len = 4;
2952 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2953 if (!*rparam) {
2954 return False;
2957 if (!p) {
2958 return False;
2960 *rdata_len = 0;
2962 SSVAL(*rparam,0,NERR_badpass);
2965 * Check the parameter definition is correct.
2968 /* Do we have a string ? */
2969 if (skip_string(param,tpscnt,p) == 0) {
2970 return False;
2972 if(!strequal(p, "zsT")) {
2973 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2974 return False;
2976 p = skip_string(param, tpscnt, p);
2977 if (!p) {
2978 return False;
2981 /* Do we have a string ? */
2982 if (skip_string(param,tpscnt,p) == 0) {
2983 return False;
2985 if(!strequal(p, "B516B16")) {
2986 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2987 return False;
2989 p = skip_string(param,tpscnt,p);
2990 if (!p) {
2991 return False;
2993 /* Do we have a string ? */
2994 if (skip_string(param,tpscnt,p) == 0) {
2995 return False;
2997 p += pull_ascii_fstring(user,p);
2999 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3001 if (tdscnt != 532) {
3002 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3003 goto out;
3006 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3007 if (bufsize != 532) {
3008 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3009 goto out;
3012 memcpy(password.data, data, 516);
3013 memcpy(hash.hash, data+516, 16);
3015 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3016 rpc_samr_dispatch, conn->server_info,
3017 &cli);
3018 if (!NT_STATUS_IS_OK(status)) {
3019 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3020 nt_errstr(status)));
3021 errcode = W_ERROR_V(ntstatus_to_werror(status));
3022 goto out;
3025 init_lsa_AsciiString(&server, global_myname());
3026 init_lsa_AsciiString(&account, user);
3028 status = rpccli_samr_OemChangePasswordUser2(cli, mem_ctx,
3029 &server,
3030 &account,
3031 &password,
3032 &hash);
3033 if (!NT_STATUS_IS_OK(status)) {
3034 errcode = W_ERROR_V(ntstatus_to_werror(status));
3035 goto out;
3038 errcode = NERR_Success;
3039 out:
3040 SSVAL(*rparam,0,errcode);
3041 SSVAL(*rparam,2,0); /* converter word */
3043 return(True);
3046 /****************************************************************************
3047 delete a print job
3048 Form: <W> <>
3049 ****************************************************************************/
3051 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
3052 char *param, int tpscnt,
3053 char *data, int tdscnt,
3054 int mdrcnt,int mprcnt,
3055 char **rdata,char **rparam,
3056 int *rdata_len,int *rparam_len)
3058 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3059 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3060 char *str2 = skip_string(param,tpscnt,str1);
3061 char *p = skip_string(param,tpscnt,str2);
3062 uint32 jobid;
3063 fstring sharename;
3064 int errcode;
3065 WERROR werr = WERR_OK;
3067 TALLOC_CTX *mem_ctx = talloc_tos();
3068 NTSTATUS status;
3069 struct rpc_pipe_client *cli = NULL;
3070 struct policy_handle handle;
3071 struct spoolss_DevmodeContainer devmode_ctr;
3072 enum spoolss_JobControl command;
3074 if (!str1 || !str2 || !p) {
3075 return False;
3078 * We use 1 here not 2 as we're checking
3079 * the last byte we want to access is safe.
3081 if (!is_offset_safe(param,tpscnt,p,1)) {
3082 return False;
3084 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3085 return False;
3087 /* check it's a supported varient */
3088 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3089 return(False);
3091 *rparam_len = 4;
3092 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3093 if (!*rparam) {
3094 return False;
3096 *rdata_len = 0;
3098 ZERO_STRUCT(handle);
3100 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3101 rpc_spoolss_dispatch, conn->server_info,
3102 &cli);
3103 if (!NT_STATUS_IS_OK(status)) {
3104 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3105 nt_errstr(status)));
3106 errcode = W_ERROR_V(ntstatus_to_werror(status));
3107 goto out;
3110 ZERO_STRUCT(devmode_ctr);
3112 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3113 sharename,
3114 NULL,
3115 devmode_ctr,
3116 SEC_FLAG_MAXIMUM_ALLOWED,
3117 &handle,
3118 &werr);
3119 if (!NT_STATUS_IS_OK(status)) {
3120 errcode = W_ERROR_V(ntstatus_to_werror(status));
3121 goto out;
3123 if (!W_ERROR_IS_OK(werr)) {
3124 errcode = W_ERROR_V(werr);
3125 goto out;
3128 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3129 * and NERR_DestNotFound if share did not exist */
3131 errcode = NERR_Success;
3133 switch (function) {
3134 case 81: /* delete */
3135 command = SPOOLSS_JOB_CONTROL_DELETE;
3136 break;
3137 case 82: /* pause */
3138 command = SPOOLSS_JOB_CONTROL_PAUSE;
3139 break;
3140 case 83: /* resume */
3141 command = SPOOLSS_JOB_CONTROL_RESUME;
3142 break;
3143 default:
3144 errcode = NERR_notsupported;
3145 goto out;
3148 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3149 &handle,
3150 jobid,
3151 NULL, /* unique ptr ctr */
3152 command,
3153 &werr);
3154 if (!NT_STATUS_IS_OK(status)) {
3155 errcode = W_ERROR_V(ntstatus_to_werror(status));
3156 goto out;
3158 if (!W_ERROR_IS_OK(werr)) {
3159 errcode = W_ERROR_V(werr);
3160 goto out;
3163 out:
3164 if (cli && is_valid_policy_hnd(&handle)) {
3165 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3168 SSVAL(*rparam,0,errcode);
3169 SSVAL(*rparam,2,0); /* converter word */
3171 return(True);
3174 /****************************************************************************
3175 Purge a print queue - or pause or resume it.
3176 ****************************************************************************/
3178 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3179 char *param, int tpscnt,
3180 char *data, int tdscnt,
3181 int mdrcnt,int mprcnt,
3182 char **rdata,char **rparam,
3183 int *rdata_len,int *rparam_len)
3185 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3186 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3187 char *str2 = skip_string(param,tpscnt,str1);
3188 char *QueueName = skip_string(param,tpscnt,str2);
3189 int errcode = NERR_notsupported;
3190 WERROR werr = WERR_OK;
3191 NTSTATUS status;
3193 TALLOC_CTX *mem_ctx = talloc_tos();
3194 struct rpc_pipe_client *cli = NULL;
3195 struct policy_handle handle;
3196 struct spoolss_SetPrinterInfoCtr info_ctr;
3197 struct spoolss_DevmodeContainer devmode_ctr;
3198 struct sec_desc_buf secdesc_ctr;
3199 enum spoolss_PrinterControl command;
3201 if (!str1 || !str2 || !QueueName) {
3202 return False;
3205 /* check it's a supported varient */
3206 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3207 return(False);
3209 *rparam_len = 4;
3210 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3211 if (!*rparam) {
3212 return False;
3214 *rdata_len = 0;
3216 if (skip_string(param,tpscnt,QueueName) == NULL) {
3217 return False;
3220 ZERO_STRUCT(handle);
3222 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3223 rpc_spoolss_dispatch, conn->server_info,
3224 &cli);
3225 if (!NT_STATUS_IS_OK(status)) {
3226 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3227 nt_errstr(status)));
3228 errcode = W_ERROR_V(ntstatus_to_werror(status));
3229 goto out;
3232 ZERO_STRUCT(devmode_ctr);
3234 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3235 QueueName,
3236 NULL,
3237 devmode_ctr,
3238 SEC_FLAG_MAXIMUM_ALLOWED,
3239 &handle,
3240 &werr);
3241 if (!NT_STATUS_IS_OK(status)) {
3242 errcode = W_ERROR_V(ntstatus_to_werror(status));
3243 goto out;
3245 if (!W_ERROR_IS_OK(werr)) {
3246 errcode = W_ERROR_V(werr);
3247 goto out;
3250 switch (function) {
3251 case 74: /* Pause queue */
3252 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3253 break;
3254 case 75: /* Resume queue */
3255 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3256 break;
3257 case 103: /* Purge */
3258 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3259 break;
3260 default:
3261 werr = WERR_NOT_SUPPORTED;
3262 break;
3265 if (!W_ERROR_IS_OK(werr)) {
3266 errcode = W_ERROR_V(werr);
3267 goto out;
3270 ZERO_STRUCT(info_ctr);
3271 ZERO_STRUCT(secdesc_ctr);
3273 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3274 &handle,
3275 &info_ctr,
3276 &devmode_ctr,
3277 &secdesc_ctr,
3278 command,
3279 &werr);
3280 if (!NT_STATUS_IS_OK(status)) {
3281 errcode = W_ERROR_V(ntstatus_to_werror(status));
3282 goto out;
3284 if (!W_ERROR_IS_OK(werr)) {
3285 errcode = W_ERROR_V(werr);
3286 goto out;
3289 errcode = W_ERROR_V(werr);
3291 out:
3293 if (cli && is_valid_policy_hnd(&handle)) {
3294 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3297 SSVAL(*rparam,0,errcode);
3298 SSVAL(*rparam,2,0); /* converter word */
3300 return(True);
3303 /****************************************************************************
3304 set the property of a print job (undocumented?)
3305 ? function = 0xb -> set name of print job
3306 ? function = 0x6 -> move print job up/down
3307 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3308 or <WWsTP> <WB21BB16B10zWWzDDz>
3309 ****************************************************************************/
3311 static int check_printjob_info(struct pack_desc* desc,
3312 int uLevel, char* id)
3314 desc->subformat = NULL;
3315 switch( uLevel ) {
3316 case 0: desc->format = "W"; break;
3317 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3318 case 2: desc->format = "WWzWWDDzz"; break;
3319 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3320 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3321 default:
3322 DEBUG(0,("check_printjob_info: invalid level %d\n",
3323 uLevel ));
3324 return False;
3326 if (id == NULL || strcmp(desc->format,id) != 0) {
3327 DEBUG(0,("check_printjob_info: invalid format %s\n",
3328 id ? id : "<NULL>" ));
3329 return False;
3331 return True;
3334 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3335 char *param, int tpscnt,
3336 char *data, int tdscnt,
3337 int mdrcnt,int mprcnt,
3338 char **rdata,char **rparam,
3339 int *rdata_len,int *rparam_len)
3341 struct pack_desc desc;
3342 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3343 char *str2 = skip_string(param,tpscnt,str1);
3344 char *p = skip_string(param,tpscnt,str2);
3345 uint32 jobid;
3346 fstring sharename;
3347 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3348 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3349 int errcode;
3351 TALLOC_CTX *mem_ctx = talloc_tos();
3352 WERROR werr;
3353 NTSTATUS status;
3354 struct rpc_pipe_client *cli = NULL;
3355 struct policy_handle handle;
3356 struct spoolss_DevmodeContainer devmode_ctr;
3357 struct spoolss_JobInfoContainer ctr;
3358 union spoolss_JobInfo info;
3359 struct spoolss_SetJobInfo1 info1;
3361 if (!str1 || !str2 || !p) {
3362 return False;
3365 * We use 1 here not 2 as we're checking
3366 * the last byte we want to access is safe.
3368 if (!is_offset_safe(param,tpscnt,p,1)) {
3369 return False;
3371 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3372 return False;
3373 *rparam_len = 4;
3374 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3375 if (!*rparam) {
3376 return False;
3379 *rdata_len = 0;
3381 /* check it's a supported varient */
3382 if ((strcmp(str1,"WWsTP")) ||
3383 (!check_printjob_info(&desc,uLevel,str2)))
3384 return(False);
3386 errcode = NERR_notsupported;
3388 switch (function) {
3389 case 0xb:
3390 /* change print job name, data gives the name */
3391 break;
3392 default:
3393 goto out;
3396 ZERO_STRUCT(handle);
3398 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3399 rpc_spoolss_dispatch, conn->server_info,
3400 &cli);
3401 if (!NT_STATUS_IS_OK(status)) {
3402 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3403 nt_errstr(status)));
3404 errcode = W_ERROR_V(ntstatus_to_werror(status));
3405 goto out;
3408 ZERO_STRUCT(devmode_ctr);
3410 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3411 sharename,
3412 NULL,
3413 devmode_ctr,
3414 SEC_FLAG_MAXIMUM_ALLOWED,
3415 &handle,
3416 &werr);
3417 if (!NT_STATUS_IS_OK(status)) {
3418 errcode = W_ERROR_V(ntstatus_to_werror(status));
3419 goto out;
3421 if (!W_ERROR_IS_OK(werr)) {
3422 errcode = W_ERROR_V(werr);
3423 goto out;
3426 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3427 &handle,
3428 jobid,
3429 1, /* level */
3430 0, /* offered */
3431 &info);
3432 if (!W_ERROR_IS_OK(werr)) {
3433 errcode = W_ERROR_V(werr);
3434 goto out;
3437 ZERO_STRUCT(ctr);
3439 info1.job_id = info.info1.job_id;
3440 info1.printer_name = info.info1.printer_name;
3441 info1.user_name = info.info1.user_name;
3442 info1.document_name = data;
3443 info1.data_type = info.info1.data_type;
3444 info1.text_status = info.info1.text_status;
3445 info1.status = info.info1.status;
3446 info1.priority = info.info1.priority;
3447 info1.position = info.info1.position;
3448 info1.total_pages = info.info1.total_pages;
3449 info1.pages_printed = info.info1.pages_printed;
3450 info1.submitted = info.info1.submitted;
3452 ctr.level = 1;
3453 ctr.info.info1 = &info1;
3455 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3456 &handle,
3457 jobid,
3458 &ctr,
3460 &werr);
3461 if (!NT_STATUS_IS_OK(status)) {
3462 errcode = W_ERROR_V(ntstatus_to_werror(status));
3463 goto out;
3465 if (!W_ERROR_IS_OK(werr)) {
3466 errcode = W_ERROR_V(werr);
3467 goto out;
3470 errcode = NERR_Success;
3471 out:
3473 if (cli && is_valid_policy_hnd(&handle)) {
3474 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3477 SSVALS(*rparam,0,errcode);
3478 SSVAL(*rparam,2,0); /* converter word */
3480 return(True);
3484 /****************************************************************************
3485 Get info about the server.
3486 ****************************************************************************/
3488 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3489 char *param, int tpscnt,
3490 char *data, int tdscnt,
3491 int mdrcnt,int mprcnt,
3492 char **rdata,char **rparam,
3493 int *rdata_len,int *rparam_len)
3495 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3496 char *str2 = skip_string(param,tpscnt,str1);
3497 char *p = skip_string(param,tpscnt,str2);
3498 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3499 char *p2;
3500 int struct_len;
3502 NTSTATUS status;
3503 WERROR werr;
3504 TALLOC_CTX *mem_ctx = talloc_tos();
3505 struct rpc_pipe_client *cli = NULL;
3506 union srvsvc_NetSrvInfo info;
3507 int errcode;
3509 if (!str1 || !str2 || !p) {
3510 return False;
3513 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3515 /* check it's a supported varient */
3516 if (!prefix_ok(str1,"WrLh")) {
3517 return False;
3520 switch( uLevel ) {
3521 case 0:
3522 if (strcmp(str2,"B16") != 0) {
3523 return False;
3525 struct_len = 16;
3526 break;
3527 case 1:
3528 if (strcmp(str2,"B16BBDz") != 0) {
3529 return False;
3531 struct_len = 26;
3532 break;
3533 case 2:
3534 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3535 return False;
3537 struct_len = 134;
3538 break;
3539 case 3:
3540 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3541 return False;
3543 struct_len = 144;
3544 break;
3545 case 20:
3546 if (strcmp(str2,"DN") != 0) {
3547 return False;
3549 struct_len = 6;
3550 break;
3551 case 50:
3552 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3553 return False;
3555 struct_len = 42;
3556 break;
3557 default:
3558 return False;
3561 *rdata_len = mdrcnt;
3562 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3563 if (!*rdata) {
3564 return False;
3567 p = *rdata;
3568 p2 = p + struct_len;
3570 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3571 rpc_srvsvc_dispatch, conn->server_info,
3572 &cli);
3573 if (!NT_STATUS_IS_OK(status)) {
3574 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3575 nt_errstr(status)));
3576 errcode = W_ERROR_V(ntstatus_to_werror(status));
3577 goto out;
3580 status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3581 NULL,
3582 101,
3583 &info,
3584 &werr);
3585 if (!NT_STATUS_IS_OK(status)) {
3586 errcode = W_ERROR_V(ntstatus_to_werror(status));
3587 goto out;
3589 if (!W_ERROR_IS_OK(werr)) {
3590 errcode = W_ERROR_V(werr);
3591 goto out;
3594 if (info.info101 == NULL) {
3595 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3596 goto out;
3599 if (uLevel != 20) {
3600 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3601 STR_ASCII|STR_UPPER|STR_TERMINATE);
3603 p += 16;
3604 if (uLevel > 0) {
3605 SCVAL(p,0,info.info101->version_major);
3606 SCVAL(p,1,info.info101->version_minor);
3607 SIVAL(p,2,info.info101->server_type);
3609 if (mdrcnt == struct_len) {
3610 SIVAL(p,6,0);
3611 } else {
3612 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3613 if (mdrcnt - struct_len <= 0) {
3614 return false;
3616 push_ascii(p2,
3617 info.info101->comment,
3618 MIN(mdrcnt - struct_len,
3619 MAX_SERVER_STRING_LENGTH),
3620 STR_TERMINATE);
3621 p2 = skip_string(*rdata,*rdata_len,p2);
3622 if (!p2) {
3623 return False;
3628 if (uLevel > 1) {
3629 return False; /* not yet implemented */
3632 errcode = NERR_Success;
3634 out:
3636 *rdata_len = PTR_DIFF(p2,*rdata);
3638 *rparam_len = 6;
3639 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3640 if (!*rparam) {
3641 return False;
3643 SSVAL(*rparam,0,errcode);
3644 SSVAL(*rparam,2,0); /* converter word */
3645 SSVAL(*rparam,4,*rdata_len);
3647 return True;
3650 /****************************************************************************
3651 Get info about the server.
3652 ****************************************************************************/
3654 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3655 char *param, int tpscnt,
3656 char *data, int tdscnt,
3657 int mdrcnt,int mprcnt,
3658 char **rdata,char **rparam,
3659 int *rdata_len,int *rparam_len)
3661 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3662 char *str2 = skip_string(param,tpscnt,str1);
3663 char *p = skip_string(param,tpscnt,str2);
3664 char *p2;
3665 char *endp;
3666 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3668 if (!str1 || !str2 || !p) {
3669 return False;
3672 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3674 *rparam_len = 6;
3675 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3676 if (!*rparam) {
3677 return False;
3680 /* check it's a supported varient */
3681 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3682 return False;
3685 *rdata_len = mdrcnt + 1024;
3686 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3687 if (!*rdata) {
3688 return False;
3691 SSVAL(*rparam,0,NERR_Success);
3692 SSVAL(*rparam,2,0); /* converter word */
3694 p = *rdata;
3695 endp = *rdata + *rdata_len;
3697 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3698 if (!p2) {
3699 return False;
3702 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3703 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3704 strupper_m(p2);
3705 p2 = skip_string(*rdata,*rdata_len,p2);
3706 if (!p2) {
3707 return False;
3709 p += 4;
3711 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3712 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3713 p2 = skip_string(*rdata,*rdata_len,p2);
3714 if (!p2) {
3715 return False;
3717 p += 4;
3719 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3720 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3721 strupper_m(p2);
3722 p2 = skip_string(*rdata,*rdata_len,p2);
3723 if (!p2) {
3724 return False;
3726 p += 4;
3728 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3729 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3730 p += 2;
3732 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3733 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3734 p2 = skip_string(*rdata,*rdata_len,p2);
3735 if (!p2) {
3736 return False;
3738 p += 4;
3740 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3741 strlcpy(p2,"",PTR_DIFF(endp,p2));
3742 p2 = skip_string(*rdata,*rdata_len,p2);
3743 if (!p2) {
3744 return False;
3746 p += 4;
3748 *rdata_len = PTR_DIFF(p2,*rdata);
3750 SSVAL(*rparam,4,*rdata_len);
3752 return True;
3755 /****************************************************************************
3756 get info about a user
3758 struct user_info_11 {
3759 char usri11_name[21]; 0-20
3760 char usri11_pad; 21
3761 char *usri11_comment; 22-25
3762 char *usri11_usr_comment; 26-29
3763 unsigned short usri11_priv; 30-31
3764 unsigned long usri11_auth_flags; 32-35
3765 long usri11_password_age; 36-39
3766 char *usri11_homedir; 40-43
3767 char *usri11_parms; 44-47
3768 long usri11_last_logon; 48-51
3769 long usri11_last_logoff; 52-55
3770 unsigned short usri11_bad_pw_count; 56-57
3771 unsigned short usri11_num_logons; 58-59
3772 char *usri11_logon_server; 60-63
3773 unsigned short usri11_country_code; 64-65
3774 char *usri11_workstations; 66-69
3775 unsigned long usri11_max_storage; 70-73
3776 unsigned short usri11_units_per_week; 74-75
3777 unsigned char *usri11_logon_hours; 76-79
3778 unsigned short usri11_code_page; 80-81
3781 where:
3783 usri11_name specifies the user name for which information is retrieved
3785 usri11_pad aligns the next data structure element to a word boundary
3787 usri11_comment is a null terminated ASCII comment
3789 usri11_user_comment is a null terminated ASCII comment about the user
3791 usri11_priv specifies the level of the privilege assigned to the user.
3792 The possible values are:
3794 Name Value Description
3795 USER_PRIV_GUEST 0 Guest privilege
3796 USER_PRIV_USER 1 User privilege
3797 USER_PRV_ADMIN 2 Administrator privilege
3799 usri11_auth_flags specifies the account operator privileges. The
3800 possible values are:
3802 Name Value Description
3803 AF_OP_PRINT 0 Print operator
3806 Leach, Naik [Page 28]
3810 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3813 AF_OP_COMM 1 Communications operator
3814 AF_OP_SERVER 2 Server operator
3815 AF_OP_ACCOUNTS 3 Accounts operator
3818 usri11_password_age specifies how many seconds have elapsed since the
3819 password was last changed.
3821 usri11_home_dir points to a null terminated ASCII string that contains
3822 the path name of the user's home directory.
3824 usri11_parms points to a null terminated ASCII string that is set
3825 aside for use by applications.
3827 usri11_last_logon specifies the time when the user last logged on.
3828 This value is stored as the number of seconds elapsed since
3829 00:00:00, January 1, 1970.
3831 usri11_last_logoff specifies the time when the user last logged off.
3832 This value is stored as the number of seconds elapsed since
3833 00:00:00, January 1, 1970. A value of 0 means the last logoff
3834 time is unknown.
3836 usri11_bad_pw_count specifies the number of incorrect passwords
3837 entered since the last successful logon.
3839 usri11_log1_num_logons specifies the number of times this user has
3840 logged on. A value of -1 means the number of logons is unknown.
3842 usri11_logon_server points to a null terminated ASCII string that
3843 contains the name of the server to which logon requests are sent.
3844 A null string indicates logon requests should be sent to the
3845 domain controller.
3847 usri11_country_code specifies the country code for the user's language
3848 of choice.
3850 usri11_workstations points to a null terminated ASCII string that
3851 contains the names of workstations the user may log on from.
3852 There may be up to 8 workstations, with the names separated by
3853 commas. A null strings indicates there are no restrictions.
3855 usri11_max_storage specifies the maximum amount of disk space the user
3856 can occupy. A value of 0xffffffff indicates there are no
3857 restrictions.
3859 usri11_units_per_week specifies the equal number of time units into
3860 which a week is divided. This value must be equal to 168.
3862 usri11_logon_hours points to a 21 byte (168 bits) string that
3863 specifies the time during which the user can log on. Each bit
3864 represents one unique hour in a week. The first bit (bit 0, word
3865 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3869 Leach, Naik [Page 29]
3873 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3876 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3877 are no restrictions.
3879 usri11_code_page specifies the code page for the user's language of
3880 choice
3882 All of the pointers in this data structure need to be treated
3883 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3884 to be ignored. The converter word returned in the parameters section
3885 needs to be subtracted from the lower 16 bits to calculate an offset
3886 into the return buffer where this ASCII string resides.
3888 There is no auxiliary data in the response.
3890 ****************************************************************************/
3892 #define usri11_name 0
3893 #define usri11_pad 21
3894 #define usri11_comment 22
3895 #define usri11_usr_comment 26
3896 #define usri11_full_name 30
3897 #define usri11_priv 34
3898 #define usri11_auth_flags 36
3899 #define usri11_password_age 40
3900 #define usri11_homedir 44
3901 #define usri11_parms 48
3902 #define usri11_last_logon 52
3903 #define usri11_last_logoff 56
3904 #define usri11_bad_pw_count 60
3905 #define usri11_num_logons 62
3906 #define usri11_logon_server 64
3907 #define usri11_country_code 68
3908 #define usri11_workstations 70
3909 #define usri11_max_storage 74
3910 #define usri11_units_per_week 78
3911 #define usri11_logon_hours 80
3912 #define usri11_code_page 84
3913 #define usri11_end 86
3915 #define USER_PRIV_GUEST 0
3916 #define USER_PRIV_USER 1
3917 #define USER_PRIV_ADMIN 2
3919 #define AF_OP_PRINT 0
3920 #define AF_OP_COMM 1
3921 #define AF_OP_SERVER 2
3922 #define AF_OP_ACCOUNTS 3
3925 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3926 char *param, int tpscnt,
3927 char *data, int tdscnt,
3928 int mdrcnt,int mprcnt,
3929 char **rdata,char **rparam,
3930 int *rdata_len,int *rparam_len)
3932 struct smbd_server_connection *sconn = smbd_server_conn;
3933 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3934 char *str2 = skip_string(param,tpscnt,str1);
3935 char *UserName = skip_string(param,tpscnt,str2);
3936 char *p = skip_string(param,tpscnt,UserName);
3937 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3938 char *p2;
3939 char *endp;
3940 const char *level_string;
3942 /* get NIS home of a previously validated user - simeon */
3943 /* With share level security vuid will always be zero.
3944 Don't depend on vuser being non-null !!. JRA */
3945 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3946 if(vuser != NULL) {
3947 DEBUG(3,(" Username of UID %d is %s\n",
3948 (int)vuser->server_info->utok.uid,
3949 vuser->server_info->unix_name));
3952 if (!str1 || !str2 || !UserName || !p) {
3953 return False;
3956 *rparam_len = 6;
3957 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3958 if (!*rparam) {
3959 return False;
3962 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3964 /* check it's a supported variant */
3965 if (strcmp(str1,"zWrLh") != 0) {
3966 return False;
3968 switch( uLevel ) {
3969 case 0: level_string = "B21"; break;
3970 case 1: level_string = "B21BB16DWzzWz"; break;
3971 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3972 case 10: level_string = "B21Bzzz"; break;
3973 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3974 default: return False;
3977 if (strcmp(level_string,str2) != 0) {
3978 return False;
3981 *rdata_len = mdrcnt + 1024;
3982 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3983 if (!*rdata) {
3984 return False;
3987 SSVAL(*rparam,0,NERR_Success);
3988 SSVAL(*rparam,2,0); /* converter word */
3990 p = *rdata;
3991 endp = *rdata + *rdata_len;
3992 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3993 if (!p2) {
3994 return False;
3997 memset(p,0,21);
3998 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4000 if (uLevel > 0) {
4001 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4002 *p2 = 0;
4005 if (uLevel >= 10) {
4006 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4007 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4008 p2 = skip_string(*rdata,*rdata_len,p2);
4009 if (!p2) {
4010 return False;
4013 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4014 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4015 p2 = skip_string(*rdata,*rdata_len,p2);
4016 if (!p2) {
4017 return False;
4020 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4021 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4022 strlcpy(p2,((vuser != NULL)
4023 ? pdb_get_fullname(vuser->server_info->sam_account)
4024 : UserName),PTR_DIFF(endp,p2));
4025 p2 = skip_string(*rdata,*rdata_len,p2);
4026 if (!p2) {
4027 return False;
4031 if (uLevel == 11) {
4032 const char *homedir = "";
4033 if (vuser != NULL) {
4034 homedir = pdb_get_homedir(
4035 vuser->server_info->sam_account);
4037 /* modelled after NTAS 3.51 reply */
4038 SSVAL(p,usri11_priv,
4039 (get_current_uid(conn) == sec_initial_uid())?
4040 USER_PRIV_ADMIN:USER_PRIV_USER);
4041 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4042 SIVALS(p,usri11_password_age,-1); /* password age */
4043 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4044 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4045 p2 = skip_string(*rdata,*rdata_len,p2);
4046 if (!p2) {
4047 return False;
4049 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4050 strlcpy(p2,"",PTR_DIFF(endp,p2));
4051 p2 = skip_string(*rdata,*rdata_len,p2);
4052 if (!p2) {
4053 return False;
4055 SIVAL(p,usri11_last_logon,0); /* last logon */
4056 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4057 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4058 SSVALS(p,usri11_num_logons,-1); /* num logons */
4059 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4060 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4061 p2 = skip_string(*rdata,*rdata_len,p2);
4062 if (!p2) {
4063 return False;
4065 SSVAL(p,usri11_country_code,0); /* country code */
4067 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4068 strlcpy(p2,"",PTR_DIFF(endp,p2));
4069 p2 = skip_string(*rdata,*rdata_len,p2);
4070 if (!p2) {
4071 return False;
4074 SIVALS(p,usri11_max_storage,-1); /* max storage */
4075 SSVAL(p,usri11_units_per_week,168); /* units per week */
4076 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4078 /* a simple way to get logon hours at all times. */
4079 memset(p2,0xff,21);
4080 SCVAL(p2,21,0); /* fix zero termination */
4081 p2 = skip_string(*rdata,*rdata_len,p2);
4082 if (!p2) {
4083 return False;
4086 SSVAL(p,usri11_code_page,0); /* code page */
4089 if (uLevel == 1 || uLevel == 2) {
4090 memset(p+22,' ',16); /* password */
4091 SIVALS(p,38,-1); /* password age */
4092 SSVAL(p,42,
4093 (get_current_uid(conn) == sec_initial_uid())?
4094 USER_PRIV_ADMIN:USER_PRIV_USER);
4095 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4096 strlcpy(p2, vuser ? pdb_get_homedir(
4097 vuser->server_info->sam_account) : "",
4098 PTR_DIFF(endp,p2));
4099 p2 = skip_string(*rdata,*rdata_len,p2);
4100 if (!p2) {
4101 return False;
4103 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4104 *p2++ = 0;
4105 SSVAL(p,52,0); /* flags */
4106 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4107 strlcpy(p2, vuser ? pdb_get_logon_script(
4108 vuser->server_info->sam_account) : "",
4109 PTR_DIFF(endp,p2));
4110 p2 = skip_string(*rdata,*rdata_len,p2);
4111 if (!p2) {
4112 return False;
4114 if (uLevel == 2) {
4115 SIVAL(p,60,0); /* auth_flags */
4116 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4117 strlcpy(p2,((vuser != NULL)
4118 ? pdb_get_fullname(vuser->server_info->sam_account)
4119 : UserName),PTR_DIFF(endp,p2));
4120 p2 = skip_string(*rdata,*rdata_len,p2);
4121 if (!p2) {
4122 return False;
4124 SIVAL(p,68,0); /* urs_comment */
4125 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4126 strlcpy(p2,"",PTR_DIFF(endp,p2));
4127 p2 = skip_string(*rdata,*rdata_len,p2);
4128 if (!p2) {
4129 return False;
4131 SIVAL(p,76,0); /* workstations */
4132 SIVAL(p,80,0); /* last_logon */
4133 SIVAL(p,84,0); /* last_logoff */
4134 SIVALS(p,88,-1); /* acct_expires */
4135 SIVALS(p,92,-1); /* max_storage */
4136 SSVAL(p,96,168); /* units_per_week */
4137 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4138 memset(p2,-1,21);
4139 p2 += 21;
4140 SSVALS(p,102,-1); /* bad_pw_count */
4141 SSVALS(p,104,-1); /* num_logons */
4142 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4144 TALLOC_CTX *ctx = talloc_tos();
4145 int space_rem = *rdata_len - (p2 - *rdata);
4146 char *tmp;
4148 if (space_rem <= 0) {
4149 return false;
4151 tmp = talloc_strdup(ctx, "\\\\%L");
4152 if (!tmp) {
4153 return false;
4155 tmp = talloc_sub_basic(ctx,
4158 tmp);
4159 if (!tmp) {
4160 return false;
4163 push_ascii(p2,
4164 tmp,
4165 space_rem,
4166 STR_TERMINATE);
4168 p2 = skip_string(*rdata,*rdata_len,p2);
4169 if (!p2) {
4170 return False;
4172 SSVAL(p,110,49); /* country_code */
4173 SSVAL(p,112,860); /* code page */
4177 *rdata_len = PTR_DIFF(p2,*rdata);
4179 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4181 return(True);
4184 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4185 char *param, int tpscnt,
4186 char *data, int tdscnt,
4187 int mdrcnt,int mprcnt,
4188 char **rdata,char **rparam,
4189 int *rdata_len,int *rparam_len)
4191 struct smbd_server_connection *sconn = smbd_server_conn;
4192 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4193 char *str2 = skip_string(param,tpscnt,str1);
4194 char *p = skip_string(param,tpscnt,str2);
4195 int uLevel;
4196 struct pack_desc desc;
4197 char* name;
4198 /* With share level security vuid will always be zero.
4199 Don't depend on vuser being non-null !!. JRA */
4200 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4202 if (!str1 || !str2 || !p) {
4203 return False;
4206 if(vuser != NULL) {
4207 DEBUG(3,(" Username of UID %d is %s\n",
4208 (int)vuser->server_info->utok.uid,
4209 vuser->server_info->unix_name));
4212 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4213 name = get_safe_str_ptr(param,tpscnt,p,2);
4214 if (!name) {
4215 return False;
4218 memset((char *)&desc,'\0',sizeof(desc));
4220 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4222 /* check it's a supported varient */
4223 if (strcmp(str1,"OOWb54WrLh") != 0) {
4224 return False;
4226 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4227 return False;
4229 if (mdrcnt > 0) {
4230 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4231 if (!*rdata) {
4232 return False;
4236 desc.base = *rdata;
4237 desc.buflen = mdrcnt;
4238 desc.subformat = NULL;
4239 desc.format = str2;
4241 if (init_package(&desc,1,0)) {
4242 PACKI(&desc,"W",0); /* code */
4243 PACKS(&desc,"B21",name); /* eff. name */
4244 PACKS(&desc,"B",""); /* pad */
4245 PACKI(&desc,"W",
4246 (get_current_uid(conn) == sec_initial_uid())?
4247 USER_PRIV_ADMIN:USER_PRIV_USER);
4248 PACKI(&desc,"D",0); /* auth flags XXX */
4249 PACKI(&desc,"W",0); /* num logons */
4250 PACKI(&desc,"W",0); /* bad pw count */
4251 PACKI(&desc,"D",0); /* last logon */
4252 PACKI(&desc,"D",-1); /* last logoff */
4253 PACKI(&desc,"D",-1); /* logoff time */
4254 PACKI(&desc,"D",-1); /* kickoff time */
4255 PACKI(&desc,"D",0); /* password age */
4256 PACKI(&desc,"D",0); /* password can change */
4257 PACKI(&desc,"D",-1); /* password must change */
4260 fstring mypath;
4261 fstrcpy(mypath,"\\\\");
4262 fstrcat(mypath,get_local_machine_name());
4263 strupper_m(mypath);
4264 PACKS(&desc,"z",mypath); /* computer */
4267 PACKS(&desc,"z",lp_workgroup());/* domain */
4268 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4269 vuser->server_info->sam_account) : ""); /* script path */
4270 PACKI(&desc,"D",0x00000000); /* reserved */
4273 *rdata_len = desc.usedlen;
4274 *rparam_len = 6;
4275 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4276 if (!*rparam) {
4277 return False;
4279 SSVALS(*rparam,0,desc.errcode);
4280 SSVAL(*rparam,2,0);
4281 SSVAL(*rparam,4,desc.neededlen);
4283 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4285 return True;
4288 /****************************************************************************
4289 api_WAccessGetUserPerms
4290 ****************************************************************************/
4292 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4293 char *param, int tpscnt,
4294 char *data, int tdscnt,
4295 int mdrcnt,int mprcnt,
4296 char **rdata,char **rparam,
4297 int *rdata_len,int *rparam_len)
4299 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4300 char *str2 = skip_string(param,tpscnt,str1);
4301 char *user = skip_string(param,tpscnt,str2);
4302 char *resource = skip_string(param,tpscnt,user);
4304 if (!str1 || !str2 || !user || !resource) {
4305 return False;
4308 if (skip_string(param,tpscnt,resource) == NULL) {
4309 return False;
4311 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4313 /* check it's a supported varient */
4314 if (strcmp(str1,"zzh") != 0) {
4315 return False;
4317 if (strcmp(str2,"") != 0) {
4318 return False;
4321 *rparam_len = 6;
4322 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4323 if (!*rparam) {
4324 return False;
4326 SSVALS(*rparam,0,0); /* errorcode */
4327 SSVAL(*rparam,2,0); /* converter word */
4328 SSVAL(*rparam,4,0x7f); /* permission flags */
4330 return True;
4333 /****************************************************************************
4334 api_WPrintJobEnumerate
4335 ****************************************************************************/
4337 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4338 char *param, int tpscnt,
4339 char *data, int tdscnt,
4340 int mdrcnt,int mprcnt,
4341 char **rdata,char **rparam,
4342 int *rdata_len,int *rparam_len)
4344 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4345 char *str2 = skip_string(param,tpscnt,str1);
4346 char *p = skip_string(param,tpscnt,str2);
4347 int uLevel;
4348 fstring sharename;
4349 uint32 jobid;
4350 struct pack_desc desc;
4351 char *tmpdata=NULL;
4353 TALLOC_CTX *mem_ctx = talloc_tos();
4354 WERROR werr;
4355 NTSTATUS status;
4356 struct rpc_pipe_client *cli = NULL;
4357 struct policy_handle handle;
4358 struct spoolss_DevmodeContainer devmode_ctr;
4359 union spoolss_JobInfo info;
4361 if (!str1 || !str2 || !p) {
4362 return False;
4365 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4367 memset((char *)&desc,'\0',sizeof(desc));
4368 memset((char *)&status,'\0',sizeof(status));
4370 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4372 /* check it's a supported varient */
4373 if (strcmp(str1,"WWrLh") != 0) {
4374 return False;
4376 if (!check_printjob_info(&desc,uLevel,str2)) {
4377 return False;
4380 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4381 return False;
4384 ZERO_STRUCT(handle);
4386 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4387 rpc_spoolss_dispatch, conn->server_info,
4388 &cli);
4389 if (!NT_STATUS_IS_OK(status)) {
4390 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4391 nt_errstr(status)));
4392 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4393 goto out;
4396 ZERO_STRUCT(devmode_ctr);
4398 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4399 sharename,
4400 NULL,
4401 devmode_ctr,
4402 SEC_FLAG_MAXIMUM_ALLOWED,
4403 &handle,
4404 &werr);
4405 if (!NT_STATUS_IS_OK(status)) {
4406 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4407 goto out;
4409 if (!W_ERROR_IS_OK(werr)) {
4410 desc.errcode = W_ERROR_V(werr);
4411 goto out;
4414 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4415 &handle,
4416 jobid,
4417 2, /* level */
4418 0, /* offered */
4419 &info);
4420 if (!W_ERROR_IS_OK(werr)) {
4421 desc.errcode = W_ERROR_V(werr);
4422 goto out;
4425 if (mdrcnt > 0) {
4426 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4427 if (!*rdata) {
4428 return False;
4430 desc.base = *rdata;
4431 desc.buflen = mdrcnt;
4432 } else {
4434 * Don't return data but need to get correct length
4435 * init_package will return wrong size if buflen=0
4437 desc.buflen = getlen(desc.format);
4438 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4441 if (init_package(&desc,1,0)) {
4442 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4443 *rdata_len = desc.usedlen;
4444 } else {
4445 desc.errcode = NERR_JobNotFound;
4446 *rdata_len = 0;
4448 out:
4449 if (cli && is_valid_policy_hnd(&handle)) {
4450 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4453 *rparam_len = 6;
4454 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4455 if (!*rparam) {
4456 return False;
4458 SSVALS(*rparam,0,desc.errcode);
4459 SSVAL(*rparam,2,0);
4460 SSVAL(*rparam,4,desc.neededlen);
4462 SAFE_FREE(tmpdata);
4464 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4466 return True;
4469 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4470 char *param, int tpscnt,
4471 char *data, int tdscnt,
4472 int mdrcnt,int mprcnt,
4473 char **rdata,char **rparam,
4474 int *rdata_len,int *rparam_len)
4476 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4477 char *str2 = skip_string(param,tpscnt,str1);
4478 char *p = skip_string(param,tpscnt,str2);
4479 char *name = p;
4480 int uLevel;
4481 int i, succnt=0;
4482 struct pack_desc desc;
4484 TALLOC_CTX *mem_ctx = talloc_tos();
4485 WERROR werr;
4486 NTSTATUS status;
4487 struct rpc_pipe_client *cli = NULL;
4488 struct policy_handle handle;
4489 struct spoolss_DevmodeContainer devmode_ctr;
4490 uint32_t count;
4491 union spoolss_JobInfo *info;
4493 if (!str1 || !str2 || !p) {
4494 return False;
4497 memset((char *)&desc,'\0',sizeof(desc));
4499 p = skip_string(param,tpscnt,p);
4500 if (!p) {
4501 return False;
4503 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4505 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4507 /* check it's a supported variant */
4508 if (strcmp(str1,"zWrLeh") != 0) {
4509 return False;
4512 if (uLevel > 2) {
4513 return False; /* defined only for uLevel 0,1,2 */
4516 if (!check_printjob_info(&desc,uLevel,str2)) {
4517 return False;
4520 ZERO_STRUCT(handle);
4522 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4523 rpc_spoolss_dispatch, conn->server_info,
4524 &cli);
4525 if (!NT_STATUS_IS_OK(status)) {
4526 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4527 nt_errstr(status)));
4528 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4529 goto out;
4532 ZERO_STRUCT(devmode_ctr);
4534 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4535 name,
4536 NULL,
4537 devmode_ctr,
4538 SEC_FLAG_MAXIMUM_ALLOWED,
4539 &handle,
4540 &werr);
4541 if (!NT_STATUS_IS_OK(status)) {
4542 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4543 goto out;
4545 if (!W_ERROR_IS_OK(werr)) {
4546 desc.errcode = W_ERROR_V(werr);
4547 goto out;
4550 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4551 &handle,
4552 0, /* firstjob */
4553 0xff, /* numjobs */
4554 2, /* level */
4555 0, /* offered */
4556 &count,
4557 &info);
4558 if (!W_ERROR_IS_OK(werr)) {
4559 desc.errcode = W_ERROR_V(werr);
4560 goto out;
4563 if (mdrcnt > 0) {
4564 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4565 if (!*rdata) {
4566 return False;
4569 desc.base = *rdata;
4570 desc.buflen = mdrcnt;
4572 if (init_package(&desc,count,0)) {
4573 succnt = 0;
4574 for (i = 0; i < count; i++) {
4575 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4576 if (desc.errcode == NERR_Success) {
4577 succnt = i+1;
4581 out:
4582 if (cli && is_valid_policy_hnd(&handle)) {
4583 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4586 *rdata_len = desc.usedlen;
4588 *rparam_len = 8;
4589 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4590 if (!*rparam) {
4591 return False;
4593 SSVALS(*rparam,0,desc.errcode);
4594 SSVAL(*rparam,2,0);
4595 SSVAL(*rparam,4,succnt);
4596 SSVAL(*rparam,6,count);
4598 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4600 return True;
4603 static int check_printdest_info(struct pack_desc* desc,
4604 int uLevel, char* id)
4606 desc->subformat = NULL;
4607 switch( uLevel ) {
4608 case 0:
4609 desc->format = "B9";
4610 break;
4611 case 1:
4612 desc->format = "B9B21WWzW";
4613 break;
4614 case 2:
4615 desc->format = "z";
4616 break;
4617 case 3:
4618 desc->format = "zzzWWzzzWW";
4619 break;
4620 default:
4621 DEBUG(0,("check_printdest_info: invalid level %d\n",
4622 uLevel));
4623 return False;
4625 if (id == NULL || strcmp(desc->format,id) != 0) {
4626 DEBUG(0,("check_printdest_info: invalid string %s\n",
4627 id ? id : "<NULL>" ));
4628 return False;
4630 return True;
4633 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4634 struct pack_desc* desc)
4636 char buf[100];
4638 strncpy(buf, info2->printername, sizeof(buf)-1);
4639 buf[sizeof(buf)-1] = 0;
4640 strupper_m(buf);
4642 if (uLevel <= 1) {
4643 PACKS(desc,"B9",buf); /* szName */
4644 if (uLevel == 1) {
4645 PACKS(desc,"B21",""); /* szUserName */
4646 PACKI(desc,"W",0); /* uJobId */
4647 PACKI(desc,"W",0); /* fsStatus */
4648 PACKS(desc,"z",""); /* pszStatus */
4649 PACKI(desc,"W",0); /* time */
4653 if (uLevel == 2 || uLevel == 3) {
4654 PACKS(desc,"z",buf); /* pszPrinterName */
4655 if (uLevel == 3) {
4656 PACKS(desc,"z",""); /* pszUserName */
4657 PACKS(desc,"z",""); /* pszLogAddr */
4658 PACKI(desc,"W",0); /* uJobId */
4659 PACKI(desc,"W",0); /* fsStatus */
4660 PACKS(desc,"z",""); /* pszStatus */
4661 PACKS(desc,"z",""); /* pszComment */
4662 PACKS(desc,"z","NULL"); /* pszDrivers */
4663 PACKI(desc,"W",0); /* time */
4664 PACKI(desc,"W",0); /* pad1 */
4669 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4670 char *param, int tpscnt,
4671 char *data, int tdscnt,
4672 int mdrcnt,int mprcnt,
4673 char **rdata,char **rparam,
4674 int *rdata_len,int *rparam_len)
4676 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4677 char *str2 = skip_string(param,tpscnt,str1);
4678 char *p = skip_string(param,tpscnt,str2);
4679 char* PrinterName = p;
4680 int uLevel;
4681 struct pack_desc desc;
4682 char *tmpdata=NULL;
4684 TALLOC_CTX *mem_ctx = talloc_tos();
4685 WERROR werr;
4686 NTSTATUS status;
4687 struct rpc_pipe_client *cli = NULL;
4688 struct policy_handle handle;
4689 struct spoolss_DevmodeContainer devmode_ctr;
4690 union spoolss_PrinterInfo info;
4692 if (!str1 || !str2 || !p) {
4693 return False;
4696 memset((char *)&desc,'\0',sizeof(desc));
4698 p = skip_string(param,tpscnt,p);
4699 if (!p) {
4700 return False;
4702 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4704 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4706 /* check it's a supported varient */
4707 if (strcmp(str1,"zWrLh") != 0) {
4708 return False;
4710 if (!check_printdest_info(&desc,uLevel,str2)) {
4711 return False;
4714 ZERO_STRUCT(handle);
4716 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4717 rpc_spoolss_dispatch, conn->server_info,
4718 &cli);
4719 if (!NT_STATUS_IS_OK(status)) {
4720 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4721 nt_errstr(status)));
4722 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4723 goto out;
4726 ZERO_STRUCT(devmode_ctr);
4728 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4729 PrinterName,
4730 NULL,
4731 devmode_ctr,
4732 SEC_FLAG_MAXIMUM_ALLOWED,
4733 &handle,
4734 &werr);
4735 if (!NT_STATUS_IS_OK(status)) {
4736 *rdata_len = 0;
4737 desc.errcode = NERR_DestNotFound;
4738 desc.neededlen = 0;
4739 goto out;
4741 if (!W_ERROR_IS_OK(werr)) {
4742 *rdata_len = 0;
4743 desc.errcode = NERR_DestNotFound;
4744 desc.neededlen = 0;
4745 goto out;
4748 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4749 &handle,
4752 &info);
4753 if (!W_ERROR_IS_OK(werr)) {
4754 *rdata_len = 0;
4755 desc.errcode = NERR_DestNotFound;
4756 desc.neededlen = 0;
4757 goto out;
4760 if (mdrcnt > 0) {
4761 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4762 if (!*rdata) {
4763 return False;
4765 desc.base = *rdata;
4766 desc.buflen = mdrcnt;
4767 } else {
4769 * Don't return data but need to get correct length
4770 * init_package will return wrong size if buflen=0
4772 desc.buflen = getlen(desc.format);
4773 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4775 if (init_package(&desc,1,0)) {
4776 fill_printdest_info(&info.info2, uLevel,&desc);
4779 out:
4780 if (cli && is_valid_policy_hnd(&handle)) {
4781 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4784 *rdata_len = desc.usedlen;
4786 *rparam_len = 6;
4787 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4788 if (!*rparam) {
4789 return False;
4791 SSVALS(*rparam,0,desc.errcode);
4792 SSVAL(*rparam,2,0);
4793 SSVAL(*rparam,4,desc.neededlen);
4795 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4796 SAFE_FREE(tmpdata);
4798 return True;
4801 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4802 char *param, int tpscnt,
4803 char *data, int tdscnt,
4804 int mdrcnt,int mprcnt,
4805 char **rdata,char **rparam,
4806 int *rdata_len,int *rparam_len)
4808 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4809 char *str2 = skip_string(param,tpscnt,str1);
4810 char *p = skip_string(param,tpscnt,str2);
4811 int uLevel;
4812 int queuecnt;
4813 int i, n, succnt=0;
4814 struct pack_desc desc;
4816 TALLOC_CTX *mem_ctx = talloc_tos();
4817 WERROR werr;
4818 NTSTATUS status;
4819 struct rpc_pipe_client *cli = NULL;
4820 union spoolss_PrinterInfo *info;
4821 uint32_t count;
4823 if (!str1 || !str2 || !p) {
4824 return False;
4827 memset((char *)&desc,'\0',sizeof(desc));
4829 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4831 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4833 /* check it's a supported varient */
4834 if (strcmp(str1,"WrLeh") != 0) {
4835 return False;
4837 if (!check_printdest_info(&desc,uLevel,str2)) {
4838 return False;
4841 queuecnt = 0;
4843 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4844 rpc_spoolss_dispatch, conn->server_info,
4845 &cli);
4846 if (!NT_STATUS_IS_OK(status)) {
4847 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
4848 nt_errstr(status)));
4849 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4850 goto out;
4853 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
4854 PRINTER_ENUM_LOCAL,
4855 cli->srv_name_slash,
4858 &count,
4859 &info);
4860 if (!W_ERROR_IS_OK(werr)) {
4861 desc.errcode = W_ERROR_V(werr);
4862 *rdata_len = 0;
4863 desc.errcode = NERR_DestNotFound;
4864 desc.neededlen = 0;
4865 goto out;
4868 queuecnt = count;
4870 if (mdrcnt > 0) {
4871 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4872 if (!*rdata) {
4873 return False;
4877 desc.base = *rdata;
4878 desc.buflen = mdrcnt;
4879 if (init_package(&desc,queuecnt,0)) {
4880 succnt = 0;
4881 n = 0;
4882 for (i = 0; i < count; i++) {
4883 fill_printdest_info(&info[i].info2, uLevel,&desc);
4884 n++;
4885 if (desc.errcode == NERR_Success) {
4886 succnt = n;
4890 out:
4891 *rdata_len = desc.usedlen;
4893 *rparam_len = 8;
4894 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4895 if (!*rparam) {
4896 return False;
4898 SSVALS(*rparam,0,desc.errcode);
4899 SSVAL(*rparam,2,0);
4900 SSVAL(*rparam,4,succnt);
4901 SSVAL(*rparam,6,queuecnt);
4903 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4905 return True;
4908 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4909 char *param, int tpscnt,
4910 char *data, int tdscnt,
4911 int mdrcnt,int mprcnt,
4912 char **rdata,char **rparam,
4913 int *rdata_len,int *rparam_len)
4915 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4916 char *str2 = skip_string(param,tpscnt,str1);
4917 char *p = skip_string(param,tpscnt,str2);
4918 int uLevel;
4919 int succnt;
4920 struct pack_desc desc;
4922 if (!str1 || !str2 || !p) {
4923 return False;
4926 memset((char *)&desc,'\0',sizeof(desc));
4928 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4930 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4932 /* check it's a supported varient */
4933 if (strcmp(str1,"WrLeh") != 0) {
4934 return False;
4936 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4937 return False;
4940 if (mdrcnt > 0) {
4941 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4942 if (!*rdata) {
4943 return False;
4946 desc.base = *rdata;
4947 desc.buflen = mdrcnt;
4948 if (init_package(&desc,1,0)) {
4949 PACKS(&desc,"B41","NULL");
4952 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4954 *rdata_len = desc.usedlen;
4956 *rparam_len = 8;
4957 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4958 if (!*rparam) {
4959 return False;
4961 SSVALS(*rparam,0,desc.errcode);
4962 SSVAL(*rparam,2,0);
4963 SSVAL(*rparam,4,succnt);
4964 SSVAL(*rparam,6,1);
4966 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4968 return True;
4971 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4972 char *param, int tpscnt,
4973 char *data, int tdscnt,
4974 int mdrcnt,int mprcnt,
4975 char **rdata,char **rparam,
4976 int *rdata_len,int *rparam_len)
4978 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4979 char *str2 = skip_string(param,tpscnt,str1);
4980 char *p = skip_string(param,tpscnt,str2);
4981 int uLevel;
4982 int succnt;
4983 struct pack_desc desc;
4985 if (!str1 || !str2 || !p) {
4986 return False;
4988 memset((char *)&desc,'\0',sizeof(desc));
4990 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4992 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4994 /* check it's a supported varient */
4995 if (strcmp(str1,"WrLeh") != 0) {
4996 return False;
4998 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4999 return False;
5002 if (mdrcnt > 0) {
5003 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5004 if (!*rdata) {
5005 return False;
5008 desc.base = *rdata;
5009 desc.buflen = mdrcnt;
5010 desc.format = str2;
5011 if (init_package(&desc,1,0)) {
5012 PACKS(&desc,"B13","lpd");
5015 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5017 *rdata_len = desc.usedlen;
5019 *rparam_len = 8;
5020 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5021 if (!*rparam) {
5022 return False;
5024 SSVALS(*rparam,0,desc.errcode);
5025 SSVAL(*rparam,2,0);
5026 SSVAL(*rparam,4,succnt);
5027 SSVAL(*rparam,6,1);
5029 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5031 return True;
5034 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
5035 char *param, int tpscnt,
5036 char *data, int tdscnt,
5037 int mdrcnt,int mprcnt,
5038 char **rdata,char **rparam,
5039 int *rdata_len,int *rparam_len)
5041 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5042 char *str2 = skip_string(param,tpscnt,str1);
5043 char *p = skip_string(param,tpscnt,str2);
5044 int uLevel;
5045 int succnt;
5046 struct pack_desc desc;
5048 if (!str1 || !str2 || !p) {
5049 return False;
5052 memset((char *)&desc,'\0',sizeof(desc));
5054 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5056 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5058 /* check it's a supported varient */
5059 if (strcmp(str1,"WrLeh") != 0) {
5060 return False;
5062 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5063 return False;
5066 if (mdrcnt > 0) {
5067 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5068 if (!*rdata) {
5069 return False;
5072 memset((char *)&desc,'\0',sizeof(desc));
5073 desc.base = *rdata;
5074 desc.buflen = mdrcnt;
5075 desc.format = str2;
5076 if (init_package(&desc,1,0)) {
5077 PACKS(&desc,"B13","lp0");
5080 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5082 *rdata_len = desc.usedlen;
5084 *rparam_len = 8;
5085 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5086 if (!*rparam) {
5087 return False;
5089 SSVALS(*rparam,0,desc.errcode);
5090 SSVAL(*rparam,2,0);
5091 SSVAL(*rparam,4,succnt);
5092 SSVAL(*rparam,6,1);
5094 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5096 return True;
5099 /****************************************************************************
5100 List open sessions
5101 ****************************************************************************/
5103 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5104 char *param, int tpscnt,
5105 char *data, int tdscnt,
5106 int mdrcnt,int mprcnt,
5107 char **rdata,char **rparam,
5108 int *rdata_len,int *rparam_len)
5111 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5112 char *str2 = skip_string(param,tpscnt,str1);
5113 char *p = skip_string(param,tpscnt,str2);
5114 int uLevel;
5115 struct pack_desc desc;
5116 struct sessionid *session_list;
5117 int i, num_sessions;
5119 if (!str1 || !str2 || !p) {
5120 return False;
5123 memset((char *)&desc,'\0',sizeof(desc));
5125 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5127 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5128 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5129 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5131 /* check it's a supported varient */
5132 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5133 return False;
5135 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5136 return False;
5139 num_sessions = list_sessions(talloc_tos(), &session_list);
5141 if (mdrcnt > 0) {
5142 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5143 if (!*rdata) {
5144 return False;
5147 memset((char *)&desc,'\0',sizeof(desc));
5148 desc.base = *rdata;
5149 desc.buflen = mdrcnt;
5150 desc.format = str2;
5151 if (!init_package(&desc,num_sessions,0)) {
5152 return False;
5155 for(i=0; i<num_sessions; i++) {
5156 PACKS(&desc, "z", session_list[i].remote_machine);
5157 PACKS(&desc, "z", session_list[i].username);
5158 PACKI(&desc, "W", 1); /* num conns */
5159 PACKI(&desc, "W", 0); /* num opens */
5160 PACKI(&desc, "W", 1); /* num users */
5161 PACKI(&desc, "D", 0); /* session time */
5162 PACKI(&desc, "D", 0); /* idle time */
5163 PACKI(&desc, "D", 0); /* flags */
5164 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5167 *rdata_len = desc.usedlen;
5169 *rparam_len = 8;
5170 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5171 if (!*rparam) {
5172 return False;
5174 SSVALS(*rparam,0,desc.errcode);
5175 SSVAL(*rparam,2,0); /* converter */
5176 SSVAL(*rparam,4,num_sessions); /* count */
5178 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5180 return True;
5184 /****************************************************************************
5185 The buffer was too small.
5186 ****************************************************************************/
5188 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5189 int mdrcnt, int mprcnt,
5190 char **rdata, char **rparam,
5191 int *rdata_len, int *rparam_len)
5193 *rparam_len = MIN(*rparam_len,mprcnt);
5194 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5195 if (!*rparam) {
5196 return False;
5199 *rdata_len = 0;
5201 SSVAL(*rparam,0,NERR_BufTooSmall);
5203 DEBUG(3,("Supplied buffer too small in API command\n"));
5205 return True;
5208 /****************************************************************************
5209 The request is not supported.
5210 ****************************************************************************/
5212 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5213 char *param, int tpscnt,
5214 char *data, int tdscnt,
5215 int mdrcnt, int mprcnt,
5216 char **rdata, char **rparam,
5217 int *rdata_len, int *rparam_len)
5219 *rparam_len = 4;
5220 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5221 if (!*rparam) {
5222 return False;
5225 *rdata_len = 0;
5227 SSVAL(*rparam,0,NERR_notsupported);
5228 SSVAL(*rparam,2,0); /* converter word */
5230 DEBUG(3,("Unsupported API command\n"));
5232 return True;
5235 static const struct {
5236 const char *name;
5237 int id;
5238 bool (*fn)(connection_struct *, uint16,
5239 char *, int,
5240 char *, int,
5241 int,int,char **,char **,int *,int *);
5242 bool auth_user; /* Deny anonymous access? */
5243 } api_commands[] = {
5244 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5245 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5246 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5247 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5248 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5249 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5250 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5251 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5252 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5253 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5254 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5255 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5256 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5257 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5258 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5259 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5260 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5261 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5262 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5263 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5264 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5265 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5266 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5267 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5268 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5269 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5270 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5271 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5272 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5273 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5274 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5275 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5276 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5277 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5278 {NULL, -1, api_Unsupported}
5279 /* The following RAP calls are not implemented by Samba:
5281 RAP_WFileEnum2 - anon not OK
5286 /****************************************************************************
5287 Handle remote api calls.
5288 ****************************************************************************/
5290 void api_reply(connection_struct *conn, uint16 vuid,
5291 struct smb_request *req,
5292 char *data, char *params,
5293 int tdscnt, int tpscnt,
5294 int mdrcnt, int mprcnt)
5296 struct smbd_server_connection *sconn = smbd_server_conn;
5297 int api_command;
5298 char *rdata = NULL;
5299 char *rparam = NULL;
5300 const char *name1 = NULL;
5301 const char *name2 = NULL;
5302 int rdata_len = 0;
5303 int rparam_len = 0;
5304 bool reply=False;
5305 int i;
5307 if (!params) {
5308 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5309 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5310 return;
5313 if (tpscnt < 2) {
5314 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5315 return;
5317 api_command = SVAL(params,0);
5318 /* Is there a string at position params+2 ? */
5319 if (skip_string(params,tpscnt,params+2)) {
5320 name1 = params + 2;
5321 } else {
5322 name1 = "";
5324 name2 = skip_string(params,tpscnt,params+2);
5325 if (!name2) {
5326 name2 = "";
5329 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5330 api_command,
5331 name1,
5332 name2,
5333 tdscnt,tpscnt,mdrcnt,mprcnt));
5335 for (i=0;api_commands[i].name;i++) {
5336 if (api_commands[i].id == api_command && api_commands[i].fn) {
5337 DEBUG(3,("Doing %s\n",api_commands[i].name));
5338 break;
5342 /* Check whether this api call can be done anonymously */
5344 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5345 user_struct *user = get_valid_user_struct(sconn, vuid);
5347 if (!user || user->server_info->guest) {
5348 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5349 return;
5353 rdata = (char *)SMB_MALLOC(1024);
5354 if (rdata) {
5355 memset(rdata,'\0',1024);
5358 rparam = (char *)SMB_MALLOC(1024);
5359 if (rparam) {
5360 memset(rparam,'\0',1024);
5363 if(!rdata || !rparam) {
5364 DEBUG(0,("api_reply: malloc fail !\n"));
5365 SAFE_FREE(rdata);
5366 SAFE_FREE(rparam);
5367 reply_nterror(req, NT_STATUS_NO_MEMORY);
5368 return;
5371 reply = api_commands[i].fn(conn,
5372 vuid,
5373 params,tpscnt, /* params + length */
5374 data,tdscnt, /* data + length */
5375 mdrcnt,mprcnt,
5376 &rdata,&rparam,&rdata_len,&rparam_len);
5379 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5380 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5381 &rdata,&rparam,&rdata_len,&rparam_len);
5384 /* if we get False back then it's actually unsupported */
5385 if (!reply) {
5386 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5387 &rdata,&rparam,&rdata_len,&rparam_len);
5390 /* If api_Unsupported returns false we can't return anything. */
5391 if (reply) {
5392 send_trans_reply(conn, req, rparam, rparam_len,
5393 rdata, rdata_len, False);
5396 SAFE_FREE(rdata);
5397 SAFE_FREE(rparam);
5398 return;