s3-lanman: remove defines now provided by IDL.
[Samba/ekacnet.git] / source3 / smbd / lanman.c
blob871e2b707d13fb3b89b51fa05b28fd5610104c9b
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 "rpc_client/cli_spoolss.h"
33 #include "rpc_client/init_spoolss.h"
34 #include "../librpc/gen_ndr/cli_srvsvc.h"
35 #include "../librpc/gen_ndr/srv_samr.h"
36 #include "../librpc/gen_ndr/srv_srvsvc.h"
37 #include "../librpc/gen_ndr/rap.h"
38 #include "../lib/util/binsearch.h"
39 #include "../libcli/auth/libcli_auth.h"
41 #ifdef CHECK_TYPES
42 #undef CHECK_TYPES
43 #endif
44 #define CHECK_TYPES 0
46 #define NERR_Success 0
47 #define NERR_badpass 86
48 #define NERR_notsupported 50
50 #define NERR_BASE (2100)
51 #define NERR_BufTooSmall (NERR_BASE+23)
52 #define NERR_JobNotFound (NERR_BASE+51)
53 #define NERR_DestNotFound (NERR_BASE+52)
55 #define ACCESS_READ 0x01
56 #define ACCESS_WRITE 0x02
57 #define ACCESS_CREATE 0x04
59 #define SHPWLEN 8 /* share password length */
61 /* Limit size of ipc replies */
63 static char *smb_realloc_limit(void *ptr, size_t size)
65 char *val;
67 size = MAX((size),4*1024);
68 val = (char *)SMB_REALLOC(ptr,size);
69 if (val) {
70 memset(val,'\0',size);
72 return val;
75 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
76 char *param, int tpscnt,
77 char *data, int tdscnt,
78 int mdrcnt, int mprcnt,
79 char **rdata, char **rparam,
80 int *rdata_len, int *rparam_len);
82 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
83 int mdrcnt, int mprcnt,
84 char **rdata, char **rparam,
85 int *rdata_len, int *rparam_len);
88 static int CopyExpanded(connection_struct *conn,
89 int snum, char **dst, char *src, int *p_space_remaining)
91 TALLOC_CTX *ctx = talloc_tos();
92 char *buf = NULL;
93 int l;
95 if (!src || !dst || !p_space_remaining || !(*dst) ||
96 *p_space_remaining <= 0) {
97 return 0;
100 buf = talloc_strdup(ctx, src);
101 if (!buf) {
102 *p_space_remaining = 0;
103 return 0;
105 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
106 if (!buf) {
107 *p_space_remaining = 0;
108 return 0;
110 buf = talloc_sub_advanced(ctx,
111 lp_servicename(SNUM(conn)),
112 conn->server_info->unix_name,
113 conn->connectpath,
114 conn->server_info->utok.gid,
115 conn->server_info->sanitized_username,
116 pdb_get_domain(conn->server_info->sam_account),
117 buf);
118 if (!buf) {
119 *p_space_remaining = 0;
120 return 0;
122 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
123 if (l == -1) {
124 return 0;
126 (*dst) += l;
127 (*p_space_remaining) -= l;
128 return l;
131 static int CopyAndAdvance(char **dst, char *src, int *n)
133 int l;
134 if (!src || !dst || !n || !(*dst)) {
135 return 0;
137 l = push_ascii(*dst,src,*n, STR_TERMINATE);
138 if (l == -1) {
139 return 0;
141 (*dst) += l;
142 (*n) -= l;
143 return l;
146 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
148 TALLOC_CTX *ctx = talloc_tos();
149 char *buf = NULL;
150 if (!s) {
151 return 0;
153 buf = talloc_strdup(ctx,s);
154 if (!buf) {
155 return 0;
157 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
158 if (!buf) {
159 return 0;
161 buf = talloc_sub_advanced(ctx,
162 lp_servicename(SNUM(conn)),
163 conn->server_info->unix_name,
164 conn->connectpath,
165 conn->server_info->utok.gid,
166 conn->server_info->sanitized_username,
167 pdb_get_domain(conn->server_info->sam_account),
168 buf);
169 if (!buf) {
170 return 0;
172 return strlen(buf) + 1;
175 /*******************************************************************
176 Check a API string for validity when we only need to check the prefix.
177 ******************************************************************/
179 static bool prefix_ok(const char *str, const char *prefix)
181 return(strncmp(str,prefix,strlen(prefix)) == 0);
184 struct pack_desc {
185 const char *format; /* formatstring for structure */
186 const char *subformat; /* subformat for structure */
187 char *base; /* baseaddress of buffer */
188 int buflen; /* remaining size for fixed part; on init: length of base */
189 int subcount; /* count of substructures */
190 char *structbuf; /* pointer into buffer for remaining fixed part */
191 int stringlen; /* remaining size for variable part */
192 char *stringbuf; /* pointer into buffer for remaining variable part */
193 int neededlen; /* total needed size */
194 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
195 const char *curpos; /* current position; pointer into format or subformat */
196 int errcode;
199 static int get_counter(const char **p)
201 int i, n;
202 if (!p || !(*p)) {
203 return 1;
205 if (!isdigit((int)**p)) {
206 return 1;
208 for (n = 0;;) {
209 i = **p;
210 if (isdigit(i)) {
211 n = 10 * n + (i - '0');
212 } else {
213 return n;
215 (*p)++;
219 static int getlen(const char *p)
221 int n = 0;
222 if (!p) {
223 return 0;
226 while (*p) {
227 switch( *p++ ) {
228 case 'W': /* word (2 byte) */
229 n += 2;
230 break;
231 case 'K': /* status word? (2 byte) */
232 n += 2;
233 break;
234 case 'N': /* count of substructures (word) at end */
235 n += 2;
236 break;
237 case 'D': /* double word (4 byte) */
238 case 'z': /* offset to zero terminated string (4 byte) */
239 case 'l': /* offset to user data (4 byte) */
240 n += 4;
241 break;
242 case 'b': /* offset to data (with counter) (4 byte) */
243 n += 4;
244 get_counter(&p);
245 break;
246 case 'B': /* byte (with optional counter) */
247 n += get_counter(&p);
248 break;
251 return n;
254 static bool init_package(struct pack_desc *p, int count, int subcount)
256 int n = p->buflen;
257 int i;
259 if (!p->format || !p->base) {
260 return False;
263 i = count * getlen(p->format);
264 if (p->subformat) {
265 i += subcount * getlen(p->subformat);
267 p->structbuf = p->base;
268 p->neededlen = 0;
269 p->usedlen = 0;
270 p->subcount = 0;
271 p->curpos = p->format;
272 if (i > n) {
273 p->neededlen = i;
274 i = n = 0;
275 #if 0
277 * This is the old error code we used. Aparently
278 * WinNT/2k systems return ERRbuftoosmall (2123) and
279 * OS/2 needs this. I'm leaving this here so we can revert
280 * if needed. JRA.
282 p->errcode = ERRmoredata;
283 #else
284 p->errcode = ERRbuftoosmall;
285 #endif
286 } else {
287 p->errcode = NERR_Success;
289 p->buflen = i;
290 n -= i;
291 p->stringbuf = p->base + i;
292 p->stringlen = n;
293 return (p->errcode == NERR_Success);
296 static int package(struct pack_desc *p, ...)
298 va_list args;
299 int needed=0, stringneeded;
300 const char *str=NULL;
301 int is_string=0, stringused;
302 int32 temp;
304 va_start(args,p);
306 if (!*p->curpos) {
307 if (!p->subcount) {
308 p->curpos = p->format;
309 } else {
310 p->curpos = p->subformat;
311 p->subcount--;
314 #if CHECK_TYPES
315 str = va_arg(args,char*);
316 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
317 #endif
318 stringneeded = -1;
320 if (!p->curpos) {
321 va_end(args);
322 return 0;
325 switch( *p->curpos++ ) {
326 case 'W': /* word (2 byte) */
327 needed = 2;
328 temp = va_arg(args,int);
329 if (p->buflen >= needed) {
330 SSVAL(p->structbuf,0,temp);
332 break;
333 case 'K': /* status word? (2 byte) */
334 needed = 2;
335 temp = va_arg(args,int);
336 if (p->buflen >= needed) {
337 SSVAL(p->structbuf,0,temp);
339 break;
340 case 'N': /* count of substructures (word) at end */
341 needed = 2;
342 p->subcount = va_arg(args,int);
343 if (p->buflen >= needed) {
344 SSVAL(p->structbuf,0,p->subcount);
346 break;
347 case 'D': /* double word (4 byte) */
348 needed = 4;
349 temp = va_arg(args,int);
350 if (p->buflen >= needed) {
351 SIVAL(p->structbuf,0,temp);
353 break;
354 case 'B': /* byte (with optional counter) */
355 needed = get_counter(&p->curpos);
357 char *s = va_arg(args,char*);
358 if (p->buflen >= needed) {
359 StrnCpy(p->structbuf,s?s:"",needed-1);
362 break;
363 case 'z': /* offset to zero terminated string (4 byte) */
364 str = va_arg(args,char*);
365 stringneeded = (str ? strlen(str)+1 : 0);
366 is_string = 1;
367 break;
368 case 'l': /* offset to user data (4 byte) */
369 str = va_arg(args,char*);
370 stringneeded = va_arg(args,int);
371 is_string = 0;
372 break;
373 case 'b': /* offset to data (with counter) (4 byte) */
374 str = va_arg(args,char*);
375 stringneeded = get_counter(&p->curpos);
376 is_string = 0;
377 break;
380 va_end(args);
381 if (stringneeded >= 0) {
382 needed = 4;
383 if (p->buflen >= needed) {
384 stringused = stringneeded;
385 if (stringused > p->stringlen) {
386 stringused = (is_string ? p->stringlen : 0);
387 if (p->errcode == NERR_Success) {
388 p->errcode = ERRmoredata;
391 if (!stringused) {
392 SIVAL(p->structbuf,0,0);
393 } else {
394 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
395 memcpy(p->stringbuf,str?str:"",stringused);
396 if (is_string) {
397 p->stringbuf[stringused-1] = '\0';
399 p->stringbuf += stringused;
400 p->stringlen -= stringused;
401 p->usedlen += stringused;
404 p->neededlen += stringneeded;
407 p->neededlen += needed;
408 if (p->buflen >= needed) {
409 p->structbuf += needed;
410 p->buflen -= needed;
411 p->usedlen += needed;
412 } else {
413 if (p->errcode == NERR_Success) {
414 p->errcode = ERRmoredata;
417 return 1;
420 #if CHECK_TYPES
421 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
422 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
423 #else
424 #define PACK(desc,t,v) package(desc,v)
425 #define PACKl(desc,t,v,l) package(desc,v,l)
426 #endif
428 static void PACKI(struct pack_desc* desc, const char *t,int v)
430 PACK(desc,t,v);
433 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
435 PACK(desc,t,v);
438 /****************************************************************************
439 Get a print queue.
440 ****************************************************************************/
442 static void PackDriverData(struct pack_desc* desc)
444 char drivdata[4+4+32];
445 SIVAL(drivdata,0,sizeof drivdata); /* cb */
446 SIVAL(drivdata,4,1000); /* lVersion */
447 memset(drivdata+8,0,32); /* szDeviceName */
448 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
449 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
452 static int check_printq_info(struct pack_desc* desc,
453 unsigned int uLevel, char *id1, char *id2)
455 desc->subformat = NULL;
456 switch( uLevel ) {
457 case 0:
458 desc->format = "B13";
459 break;
460 case 1:
461 desc->format = "B13BWWWzzzzzWW";
462 break;
463 case 2:
464 desc->format = "B13BWWWzzzzzWN";
465 desc->subformat = "WB21BB16B10zWWzDDz";
466 break;
467 case 3:
468 desc->format = "zWWWWzzzzWWzzl";
469 break;
470 case 4:
471 desc->format = "zWWWWzzzzWNzzl";
472 desc->subformat = "WWzWWDDzz";
473 break;
474 case 5:
475 desc->format = "z";
476 break;
477 case 51:
478 desc->format = "K";
479 break;
480 case 52:
481 desc->format = "WzzzzzzzzN";
482 desc->subformat = "z";
483 break;
484 default:
485 DEBUG(0,("check_printq_info: invalid level %d\n",
486 uLevel ));
487 return False;
489 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
490 DEBUG(0,("check_printq_info: invalid format %s\n",
491 id1 ? id1 : "<NULL>" ));
492 return False;
494 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
495 DEBUG(0,("check_printq_info: invalid subformat %s\n",
496 id2 ? id2 : "<NULL>" ));
497 return False;
499 return True;
503 #define RAP_JOB_STATUS_QUEUED 0
504 #define RAP_JOB_STATUS_PAUSED 1
505 #define RAP_JOB_STATUS_SPOOLING 2
506 #define RAP_JOB_STATUS_PRINTING 3
507 #define RAP_JOB_STATUS_PRINTED 4
509 #define RAP_QUEUE_STATUS_PAUSED 1
510 #define RAP_QUEUE_STATUS_ERROR 2
512 /* turn a print job status into a on the wire status
514 static int printj_spoolss_status(int v)
516 if (v == JOB_STATUS_QUEUED)
517 return RAP_JOB_STATUS_QUEUED;
518 if (v & JOB_STATUS_PAUSED)
519 return RAP_JOB_STATUS_PAUSED;
520 if (v & JOB_STATUS_SPOOLING)
521 return RAP_JOB_STATUS_SPOOLING;
522 if (v & JOB_STATUS_PRINTING)
523 return RAP_JOB_STATUS_PRINTING;
524 return 0;
527 /* turn a print queue status into a on the wire status
529 static int printq_spoolss_status(int v)
531 if (v == PRINTER_STATUS_OK)
532 return 0;
533 if (v & PRINTER_STATUS_PAUSED)
534 return RAP_QUEUE_STATUS_PAUSED;
535 return RAP_QUEUE_STATUS_ERROR;
538 static void fill_spoolss_printjob_info(int uLevel,
539 struct pack_desc *desc,
540 struct spoolss_JobInfo2 *info2,
541 int n)
543 time_t t = spoolss_Time_to_time_t(&info2->submitted);
545 /* the client expects localtime */
546 t -= get_time_zone(t);
548 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
549 if (uLevel == 1) {
550 PACKS(desc,"B21", info2->user_name); /* szUserName */
551 PACKS(desc,"B",""); /* pad */
552 PACKS(desc,"B16",""); /* szNotifyName */
553 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
554 PACKS(desc,"z",""); /* pszParms */
555 PACKI(desc,"W",n+1); /* uPosition */
556 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
557 PACKS(desc,"z",""); /* pszStatus */
558 PACKI(desc,"D", t); /* ulSubmitted */
559 PACKI(desc,"D", info2->size); /* ulSize */
560 PACKS(desc,"z", info2->document_name); /* pszComment */
562 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
563 PACKI(desc,"W", info2->priority); /* uPriority */
564 PACKS(desc,"z", info2->user_name); /* pszUserName */
565 PACKI(desc,"W",n+1); /* uPosition */
566 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
567 PACKI(desc,"D",t); /* ulSubmitted */
568 PACKI(desc,"D", info2->size); /* ulSize */
569 PACKS(desc,"z","Samba"); /* pszComment */
570 PACKS(desc,"z", info2->document_name); /* pszDocument */
571 if (uLevel == 3) {
572 PACKS(desc,"z",""); /* pszNotifyName */
573 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
574 PACKS(desc,"z",""); /* pszParms */
575 PACKS(desc,"z",""); /* pszStatus */
576 PACKS(desc,"z", info2->printer_name); /* pszQueue */
577 PACKS(desc,"z","lpd"); /* pszQProcName */
578 PACKS(desc,"z",""); /* pszQProcParms */
579 PACKS(desc,"z","NULL"); /* pszDriverName */
580 PackDriverData(desc); /* pDriverData */
581 PACKS(desc,"z",""); /* pszPrinterName */
582 } else if (uLevel == 4) { /* OS2 */
583 PACKS(desc,"z",""); /* pszSpoolFileName */
584 PACKS(desc,"z",""); /* pszPortName */
585 PACKS(desc,"z",""); /* pszStatus */
586 PACKI(desc,"D",0); /* ulPagesSpooled */
587 PACKI(desc,"D",0); /* ulPagesSent */
588 PACKI(desc,"D",0); /* ulPagesPrinted */
589 PACKI(desc,"D",0); /* ulTimePrinted */
590 PACKI(desc,"D",0); /* ulExtendJobStatus */
591 PACKI(desc,"D",0); /* ulStartPage */
592 PACKI(desc,"D",0); /* ulEndPage */
597 /********************************************************************
598 Respond to the DosPrintQInfo command with a level of 52
599 This is used to get printer driver information for Win9x clients
600 ********************************************************************/
601 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
602 struct pack_desc* desc, int count,
603 const char *printer_name)
605 int i;
606 fstring location;
607 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
608 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
609 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
611 PACKI(desc, "W", 0x0400); /* don't know */
612 PACKS(desc, "z", driver->driver_name); /* long printer name */
613 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
614 PACKS(desc, "z", driver->data_file); /* Datafile name */
615 PACKS(desc, "z", driver->monitor_name); /* language monitor */
617 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
618 standard_sub_basic( "", "", location, sizeof(location)-1 );
619 PACKS(desc,"z", location); /* share to retrieve files */
621 PACKS(desc,"z", driver->default_datatype); /* default data type */
622 PACKS(desc,"z", driver->help_file); /* helpfile name */
623 PACKS(desc,"z", driver->driver_path); /* driver name */
625 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
626 DEBUG(3,("Driver: %s:\n",driver->driver_path));
627 DEBUG(3,("Data File: %s:\n",driver->data_file));
628 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
629 DEBUG(3,("Driver Location: %s:\n",location));
630 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
631 DEBUG(3,("Help File: %s:\n",driver->help_file));
632 PACKI(desc,"N",count); /* number of files to copy */
634 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
636 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
637 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
638 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
641 /* sanity check */
642 if ( i != count )
643 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
644 count, i));
646 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
648 desc->errcode=NERR_Success;
652 static const char *strip_unc(const char *unc)
654 char *p;
656 if (unc == NULL) {
657 return NULL;
660 if ((p = strrchr(unc, '\\')) != NULL) {
661 return p+1;
664 return unc;
667 static void fill_printq_info(int uLevel,
668 struct pack_desc* desc,
669 int count,
670 union spoolss_JobInfo *job_info,
671 struct spoolss_DriverInfo3 *driver_info,
672 struct spoolss_PrinterInfo2 *printer_info)
674 switch (uLevel) {
675 case 0:
676 case 1:
677 case 2:
678 PACKS(desc,"B13", strip_unc(printer_info->printername));
679 break;
680 case 3:
681 case 4:
682 case 5:
683 PACKS(desc,"z", strip_unc(printer_info->printername));
684 break;
685 case 51:
686 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
687 break;
690 if (uLevel == 1 || uLevel == 2) {
691 PACKS(desc,"B",""); /* alignment */
692 PACKI(desc,"W",5); /* priority */
693 PACKI(desc,"W",0); /* start time */
694 PACKI(desc,"W",0); /* until time */
695 PACKS(desc,"z",""); /* pSepFile */
696 PACKS(desc,"z","lpd"); /* pPrProc */
697 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
698 PACKS(desc,"z",""); /* pParms */
699 if (printer_info->printername == NULL) {
700 PACKS(desc,"z","UNKNOWN PRINTER");
701 PACKI(desc,"W",LPSTAT_ERROR);
702 } else {
703 PACKS(desc,"z", printer_info->comment);
704 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
706 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
709 if (uLevel == 3 || uLevel == 4) {
710 PACKI(desc,"W",5); /* uPriority */
711 PACKI(desc,"W",0); /* uStarttime */
712 PACKI(desc,"W",0); /* uUntiltime */
713 PACKI(desc,"W",5); /* pad1 */
714 PACKS(desc,"z",""); /* pszSepFile */
715 PACKS(desc,"z","WinPrint"); /* pszPrProc */
716 PACKS(desc,"z",NULL); /* pszParms */
717 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
718 /* "don't ask" that it's done this way to fix corrupted
719 Win9X/ME printer comments. */
720 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
721 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
722 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
723 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
724 PackDriverData(desc); /* pDriverData */
727 if (uLevel == 2 || uLevel == 4) {
728 int i;
729 for (i = 0; i < count; i++) {
730 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
734 if (uLevel==52)
735 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
738 /* This function returns the number of files for a given driver */
739 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
741 int result = 0;
743 /* count the number of files */
744 while (driver->dependent_files && *driver->dependent_files[result])
745 result++;
747 return result;
750 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
751 char *param, int tpscnt,
752 char *data, int tdscnt,
753 int mdrcnt,int mprcnt,
754 char **rdata,char **rparam,
755 int *rdata_len,int *rparam_len)
757 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
758 char *str2 = skip_string(param,tpscnt,str1);
759 char *p = skip_string(param,tpscnt,str2);
760 char *QueueName = p;
761 unsigned int uLevel;
762 uint32_t count = 0;
763 char *str3;
764 struct pack_desc desc;
765 char* tmpdata=NULL;
767 WERROR werr = WERR_OK;
768 TALLOC_CTX *mem_ctx = talloc_tos();
769 NTSTATUS status;
770 struct rpc_pipe_client *cli = NULL;
771 struct policy_handle handle;
772 struct spoolss_DevmodeContainer devmode_ctr;
773 union spoolss_DriverInfo driver_info;
774 union spoolss_JobInfo *job_info;
775 union spoolss_PrinterInfo printer_info;
777 if (!str1 || !str2 || !p) {
778 return False;
780 memset((char *)&desc,'\0',sizeof(desc));
782 p = skip_string(param,tpscnt,p);
783 if (!p) {
784 return False;
786 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
787 str3 = get_safe_str_ptr(param,tpscnt,p,4);
788 /* str3 may be null here and is checked in check_printq_info(). */
790 /* remove any trailing username */
791 if ((p = strchr_m(QueueName,'%')))
792 *p = 0;
794 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
796 /* check it's a supported varient */
797 if (!prefix_ok(str1,"zWrLh"))
798 return False;
799 if (!check_printq_info(&desc,uLevel,str2,str3)) {
801 * Patch from Scott Moomaw <scott@bridgewater.edu>
802 * to return the 'invalid info level' error if an
803 * unknown level was requested.
805 *rdata_len = 0;
806 *rparam_len = 6;
807 *rparam = smb_realloc_limit(*rparam,*rparam_len);
808 if (!*rparam) {
809 return False;
811 SSVALS(*rparam,0,ERRunknownlevel);
812 SSVAL(*rparam,2,0);
813 SSVAL(*rparam,4,0);
814 return(True);
817 ZERO_STRUCT(handle);
819 status = rpc_connect_spoolss_pipe(conn, &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 "RAW",
832 devmode_ctr,
833 PRINTER_ACCESS_USE,
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_connect_spoolss_pipe(conn, &cli);
1009 if (!NT_STATUS_IS_OK(status)) {
1010 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1011 nt_errstr(status)));
1012 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1013 goto out;
1016 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1017 PRINTER_ENUM_LOCAL,
1018 cli->srv_name_slash,
1021 &num_printers,
1022 &printer_info);
1023 if (!W_ERROR_IS_OK(werr)) {
1024 desc.errcode = W_ERROR_V(werr);
1025 goto out;
1028 queuecnt = num_printers;
1030 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1031 if (job_info == NULL) {
1032 goto err;
1035 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1036 if (driver_info == NULL) {
1037 goto err;
1040 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1041 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1042 goto err;
1045 if (mdrcnt > 0) {
1046 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1047 if (!*rdata) {
1048 goto err;
1051 desc.base = *rdata;
1052 desc.buflen = mdrcnt;
1054 subcnt = 0;
1055 for (i = 0; i < num_printers; i++) {
1057 uint32_t num_jobs;
1058 struct policy_handle handle;
1059 const char *printername;
1061 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1062 if (printername == NULL) {
1063 goto err;
1066 ZERO_STRUCT(handle);
1067 ZERO_STRUCT(devmode_ctr);
1069 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1070 printername,
1071 "RAW",
1072 devmode_ctr,
1073 PRINTER_ACCESS_USE,
1074 &handle,
1075 &werr);
1076 if (!NT_STATUS_IS_OK(status)) {
1077 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1078 goto out;
1080 if (!W_ERROR_IS_OK(werr)) {
1081 desc.errcode = W_ERROR_V(werr);
1082 goto out;
1085 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1086 &handle,
1087 0, /* firstjob */
1088 0xff, /* numjobs */
1089 2, /* level */
1090 0, /* offered */
1091 &num_jobs,
1092 &job_info[i]);
1093 if (!W_ERROR_IS_OK(werr)) {
1094 desc.errcode = W_ERROR_V(werr);
1095 goto out;
1098 if (uLevel==52) {
1099 uint32_t server_major_version;
1100 uint32_t server_minor_version;
1102 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1103 &handle,
1104 "Windows 4.0",
1105 3, /* level */
1107 0, /* version */
1109 &driver_info[i],
1110 &server_major_version,
1111 &server_minor_version);
1112 if (!W_ERROR_IS_OK(werr)) {
1113 desc.errcode = W_ERROR_V(werr);
1114 goto out;
1118 subcntarr[i] = num_jobs;
1119 subcnt += subcntarr[i];
1121 if (cli && is_valid_policy_hnd(&handle)) {
1122 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1126 if (init_package(&desc,queuecnt,subcnt)) {
1127 for (i = 0; i < num_printers; i++) {
1128 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1129 if (desc.errcode == NERR_Success) {
1130 succnt = i;
1135 SAFE_FREE(subcntarr);
1136 out:
1137 *rdata_len = desc.usedlen;
1138 *rparam_len = 8;
1139 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1140 if (!*rparam) {
1141 goto err;
1143 SSVALS(*rparam,0,desc.errcode);
1144 SSVAL(*rparam,2,0);
1145 SSVAL(*rparam,4,succnt);
1146 SSVAL(*rparam,6,queuecnt);
1148 return True;
1150 err:
1152 SAFE_FREE(subcntarr);
1154 return False;
1157 /****************************************************************************
1158 Get info level for a server list query.
1159 ****************************************************************************/
1161 static bool check_server_info(int uLevel, char* id)
1163 switch( uLevel ) {
1164 case 0:
1165 if (strcmp(id,"B16") != 0) {
1166 return False;
1168 break;
1169 case 1:
1170 if (strcmp(id,"B16BBDz") != 0) {
1171 return False;
1173 break;
1174 default:
1175 return False;
1177 return True;
1180 struct srv_info_struct {
1181 fstring name;
1182 uint32 type;
1183 fstring comment;
1184 fstring domain;
1185 bool server_added;
1188 /*******************************************************************
1189 Get server info lists from the files saved by nmbd. Return the
1190 number of entries.
1191 ******************************************************************/
1193 static int get_server_info(uint32 servertype,
1194 struct srv_info_struct **servers,
1195 const char *domain)
1197 int count=0;
1198 int alloced=0;
1199 char **lines;
1200 bool local_list_only;
1201 int i;
1203 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1204 if (!lines) {
1205 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1206 return 0;
1209 /* request for everything is code for request all servers */
1210 if (servertype == SV_TYPE_ALL) {
1211 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1214 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1216 DEBUG(4,("Servertype search: %8x\n",servertype));
1218 for (i=0;lines[i];i++) {
1219 fstring stype;
1220 struct srv_info_struct *s;
1221 const char *ptr = lines[i];
1222 bool ok = True;
1223 TALLOC_CTX *frame = NULL;
1224 char *p;
1226 if (!*ptr) {
1227 continue;
1230 if (count == alloced) {
1231 alloced += 10;
1232 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1233 if (!*servers) {
1234 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1235 TALLOC_FREE(lines);
1236 return 0;
1238 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1240 s = &(*servers)[count];
1242 frame = talloc_stackframe();
1243 s->name[0] = '\0';
1244 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1245 TALLOC_FREE(frame);
1246 continue;
1248 fstrcpy(s->name, p);
1250 stype[0] = '\0';
1251 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1252 TALLOC_FREE(frame);
1253 continue;
1255 fstrcpy(stype, p);
1257 s->comment[0] = '\0';
1258 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1259 TALLOC_FREE(frame);
1260 continue;
1262 fstrcpy(s->comment, p);
1263 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1265 s->domain[0] = '\0';
1266 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1267 /* this allows us to cope with an old nmbd */
1268 fstrcpy(s->domain,lp_workgroup());
1269 } else {
1270 fstrcpy(s->domain, p);
1272 TALLOC_FREE(frame);
1274 if (sscanf(stype,"%X",&s->type) != 1) {
1275 DEBUG(4,("r:host file "));
1276 ok = False;
1279 /* Filter the servers/domains we return based on what was asked for. */
1281 /* Check to see if we are being asked for a local list only. */
1282 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1283 DEBUG(4,("r: local list only"));
1284 ok = False;
1287 /* doesn't match up: don't want it */
1288 if (!(servertype & s->type)) {
1289 DEBUG(4,("r:serv type "));
1290 ok = False;
1293 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1294 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1295 DEBUG(4,("s: dom mismatch "));
1296 ok = False;
1299 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1300 ok = False;
1303 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1304 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1306 if (ok) {
1307 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1308 s->name, s->type, s->comment, s->domain));
1309 s->server_added = True;
1310 count++;
1311 } else {
1312 DEBUG(4,("%20s %8x %25s %15s\n",
1313 s->name, s->type, s->comment, s->domain));
1317 TALLOC_FREE(lines);
1318 return count;
1321 /*******************************************************************
1322 Fill in a server info structure.
1323 ******************************************************************/
1325 static int fill_srv_info(struct srv_info_struct *service,
1326 int uLevel, char **buf, int *buflen,
1327 char **stringbuf, int *stringspace, char *baseaddr)
1329 int struct_len;
1330 char* p;
1331 char* p2;
1332 int l2;
1333 int len;
1335 switch (uLevel) {
1336 case 0:
1337 struct_len = 16;
1338 break;
1339 case 1:
1340 struct_len = 26;
1341 break;
1342 default:
1343 return -1;
1346 if (!buf) {
1347 len = 0;
1348 switch (uLevel) {
1349 case 1:
1350 len = strlen(service->comment)+1;
1351 break;
1354 *buflen = struct_len;
1355 *stringspace = len;
1356 return struct_len + len;
1359 len = struct_len;
1360 p = *buf;
1361 if (*buflen < struct_len) {
1362 return -1;
1364 if (stringbuf) {
1365 p2 = *stringbuf;
1366 l2 = *stringspace;
1367 } else {
1368 p2 = p + struct_len;
1369 l2 = *buflen - struct_len;
1371 if (!baseaddr) {
1372 baseaddr = p;
1375 switch (uLevel) {
1376 case 0:
1377 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1378 break;
1380 case 1:
1381 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1382 SIVAL(p,18,service->type);
1383 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1384 len += CopyAndAdvance(&p2,service->comment,&l2);
1385 break;
1388 if (stringbuf) {
1389 *buf = p + struct_len;
1390 *buflen -= struct_len;
1391 *stringbuf = p2;
1392 *stringspace = l2;
1393 } else {
1394 *buf = p2;
1395 *buflen -= len;
1397 return len;
1401 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1403 return StrCaseCmp(s1->name,s2->name);
1406 /****************************************************************************
1407 View list of servers available (or possibly domains). The info is
1408 extracted from lists saved by nmbd on the local host.
1409 ****************************************************************************/
1411 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1412 char *param, int tpscnt,
1413 char *data, int tdscnt,
1414 int mdrcnt, int mprcnt, char **rdata,
1415 char **rparam, int *rdata_len, int *rparam_len)
1417 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1418 char *str2 = skip_string(param,tpscnt,str1);
1419 char *p = skip_string(param,tpscnt,str2);
1420 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1421 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1422 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1423 char *p2;
1424 int data_len, fixed_len, string_len;
1425 int f_len = 0, s_len = 0;
1426 struct srv_info_struct *servers=NULL;
1427 int counted=0,total=0;
1428 int i,missed;
1429 fstring domain;
1430 bool domain_request;
1431 bool local_request;
1433 if (!str1 || !str2 || !p) {
1434 return False;
1437 /* If someone sets all the bits they don't really mean to set
1438 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1439 known servers. */
1441 if (servertype == SV_TYPE_ALL) {
1442 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1445 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1446 any other bit (they may just set this bit on its own) they
1447 want all the locally seen servers. However this bit can be
1448 set on its own so set the requested servers to be
1449 ALL - DOMAIN_ENUM. */
1451 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1452 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1455 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1456 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1458 p += 8;
1460 if (!prefix_ok(str1,"WrLehD")) {
1461 return False;
1463 if (!check_server_info(uLevel,str2)) {
1464 return False;
1467 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1468 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1469 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1471 if (strcmp(str1, "WrLehDz") == 0) {
1472 if (skip_string(param,tpscnt,p) == NULL) {
1473 return False;
1475 pull_ascii_fstring(domain, p);
1476 } else {
1477 fstrcpy(domain, lp_workgroup());
1480 DEBUG(4, ("domain [%s]\n", domain));
1482 if (lp_browse_list()) {
1483 total = get_server_info(servertype,&servers,domain);
1486 data_len = fixed_len = string_len = 0;
1487 missed = 0;
1489 TYPESAFE_QSORT(servers, total, srv_comp);
1492 char *lastname=NULL;
1494 for (i=0;i<total;i++) {
1495 struct srv_info_struct *s = &servers[i];
1497 if (lastname && strequal(lastname,s->name)) {
1498 continue;
1500 lastname = s->name;
1501 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1502 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1503 i, s->name, s->type, s->comment, s->domain));
1505 if (data_len < buf_len) {
1506 counted++;
1507 fixed_len += f_len;
1508 string_len += s_len;
1509 } else {
1510 missed++;
1515 *rdata_len = fixed_len + string_len;
1516 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1517 if (!*rdata) {
1518 return False;
1521 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1522 p = *rdata;
1523 f_len = fixed_len;
1524 s_len = string_len;
1527 char *lastname=NULL;
1528 int count2 = counted;
1530 for (i = 0; i < total && count2;i++) {
1531 struct srv_info_struct *s = &servers[i];
1533 if (lastname && strequal(lastname,s->name)) {
1534 continue;
1536 lastname = s->name;
1537 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1538 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1539 i, s->name, s->type, s->comment, s->domain));
1540 count2--;
1544 *rparam_len = 8;
1545 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1546 if (!*rparam) {
1547 return False;
1549 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1550 SSVAL(*rparam,2,0);
1551 SSVAL(*rparam,4,counted);
1552 SSVAL(*rparam,6,counted+missed);
1554 SAFE_FREE(servers);
1556 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1557 domain,uLevel,counted,counted+missed));
1559 return True;
1562 static int srv_name_match(const char *n1, const char *n2)
1565 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1567 * In Windows, FirstNameToReturn need not be an exact match:
1568 * the server will return a list of servers that exist on
1569 * the network greater than or equal to the FirstNameToReturn.
1571 int ret = StrCaseCmp(n1, n2);
1573 if (ret <= 0) {
1574 return 0;
1577 return ret;
1580 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1581 char *param, int tpscnt,
1582 char *data, int tdscnt,
1583 int mdrcnt, int mprcnt, char **rdata,
1584 char **rparam, int *rdata_len, int *rparam_len)
1586 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1587 char *str2 = skip_string(param,tpscnt,str1);
1588 char *p = skip_string(param,tpscnt,str2);
1589 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1590 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1591 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1592 char *p2;
1593 int data_len, fixed_len, string_len;
1594 int f_len = 0, s_len = 0;
1595 struct srv_info_struct *servers=NULL;
1596 int counted=0,first=0,total=0;
1597 int i,missed;
1598 fstring domain;
1599 fstring first_name;
1600 bool domain_request;
1601 bool local_request;
1603 if (!str1 || !str2 || !p) {
1604 return False;
1607 /* If someone sets all the bits they don't really mean to set
1608 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1609 known servers. */
1611 if (servertype == SV_TYPE_ALL) {
1612 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1615 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1616 any other bit (they may just set this bit on its own) they
1617 want all the locally seen servers. However this bit can be
1618 set on its own so set the requested servers to be
1619 ALL - DOMAIN_ENUM. */
1621 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1622 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1625 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1626 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1628 p += 8;
1630 if (strcmp(str1, "WrLehDzz") != 0) {
1631 return false;
1633 if (!check_server_info(uLevel,str2)) {
1634 return False;
1637 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1638 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1639 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1641 if (skip_string(param,tpscnt,p) == NULL) {
1642 return False;
1644 pull_ascii_fstring(domain, p);
1645 if (domain[0] == '\0') {
1646 fstrcpy(domain, lp_workgroup());
1648 p = skip_string(param,tpscnt,p);
1649 if (skip_string(param,tpscnt,p) == NULL) {
1650 return False;
1652 pull_ascii_fstring(first_name, p);
1654 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1655 domain, first_name));
1657 if (lp_browse_list()) {
1658 total = get_server_info(servertype,&servers,domain);
1661 data_len = fixed_len = string_len = 0;
1662 missed = 0;
1664 TYPESAFE_QSORT(servers, total, srv_comp);
1666 if (first_name[0] != '\0') {
1667 struct srv_info_struct *first_server = NULL;
1669 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1670 srv_name_match, first_server);
1671 if (first_server) {
1672 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1674 * The binary search may not find the exact match
1675 * so we need to search backward to find the first match
1677 * This implements the strange matching windows
1678 * implements. (see the comment in srv_name_match().
1680 for (;first > 0;) {
1681 int ret;
1682 ret = StrCaseCmp(first_name,
1683 servers[first-1].name);
1684 if (ret > 0) {
1685 break;
1687 first--;
1689 } else {
1690 /* we should return no entries */
1691 first = total;
1696 char *lastname=NULL;
1698 for (i=first;i<total;i++) {
1699 struct srv_info_struct *s = &servers[i];
1701 if (lastname && strequal(lastname,s->name)) {
1702 continue;
1704 lastname = s->name;
1705 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1706 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1707 i, s->name, s->type, s->comment, s->domain));
1709 if (data_len < buf_len) {
1710 counted++;
1711 fixed_len += f_len;
1712 string_len += s_len;
1713 } else {
1714 missed++;
1719 *rdata_len = fixed_len + string_len;
1720 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1721 if (!*rdata) {
1722 return False;
1725 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1726 p = *rdata;
1727 f_len = fixed_len;
1728 s_len = string_len;
1731 char *lastname=NULL;
1732 int count2 = counted;
1734 for (i = first; i < total && count2;i++) {
1735 struct srv_info_struct *s = &servers[i];
1737 if (lastname && strequal(lastname,s->name)) {
1738 continue;
1740 lastname = s->name;
1741 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1742 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1743 i, s->name, s->type, s->comment, s->domain));
1744 count2--;
1748 *rparam_len = 8;
1749 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1750 if (!*rparam) {
1751 return False;
1753 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1754 SSVAL(*rparam,2,0);
1755 SSVAL(*rparam,4,counted);
1756 SSVAL(*rparam,6,counted+missed);
1758 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1759 domain,uLevel,first,first_name,
1760 first < total ? servers[first].name : "",
1761 counted,counted+missed));
1763 SAFE_FREE(servers);
1765 return True;
1768 /****************************************************************************
1769 command 0x34 - suspected of being a "Lookup Names" stub api
1770 ****************************************************************************/
1772 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1773 char *param, int tpscnt,
1774 char *data, int tdscnt,
1775 int mdrcnt, int mprcnt, char **rdata,
1776 char **rparam, int *rdata_len, int *rparam_len)
1778 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1779 char *str2 = skip_string(param,tpscnt,str1);
1780 char *p = skip_string(param,tpscnt,str2);
1781 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1782 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1783 int counted=0;
1784 int missed=0;
1786 if (!str1 || !str2 || !p) {
1787 return False;
1790 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1791 str1, str2, p, uLevel, buf_len));
1793 if (!prefix_ok(str1,"zWrLeh")) {
1794 return False;
1797 *rdata_len = 0;
1799 *rparam_len = 8;
1800 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1801 if (!*rparam) {
1802 return False;
1805 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1806 SSVAL(*rparam,2,0);
1807 SSVAL(*rparam,4,counted);
1808 SSVAL(*rparam,6,counted+missed);
1810 return True;
1813 /****************************************************************************
1814 get info about a share
1815 ****************************************************************************/
1817 static bool check_share_info(int uLevel, char* id)
1819 switch( uLevel ) {
1820 case 0:
1821 if (strcmp(id,"B13") != 0) {
1822 return False;
1824 break;
1825 case 1:
1826 /* Level-2 descriptor is allowed (and ignored) */
1827 if (strcmp(id,"B13BWz") != 0 &&
1828 strcmp(id,"B13BWzWWWzB9B") != 0) {
1829 return False;
1831 break;
1832 case 2:
1833 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1834 return False;
1836 break;
1837 case 91:
1838 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1839 return False;
1841 break;
1842 default:
1843 return False;
1845 return True;
1848 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1849 char** buf, int* buflen,
1850 char** stringbuf, int* stringspace, char* baseaddr)
1852 int struct_len;
1853 char* p;
1854 char* p2;
1855 int l2;
1856 int len;
1858 switch( uLevel ) {
1859 case 0:
1860 struct_len = 13;
1861 break;
1862 case 1:
1863 struct_len = 20;
1864 break;
1865 case 2:
1866 struct_len = 40;
1867 break;
1868 case 91:
1869 struct_len = 68;
1870 break;
1871 default:
1872 return -1;
1875 if (!buf) {
1876 len = 0;
1878 if (uLevel > 0) {
1879 len += StrlenExpanded(conn,snum,lp_comment(snum));
1881 if (uLevel > 1) {
1882 len += strlen(lp_pathname(snum)) + 1;
1884 if (buflen) {
1885 *buflen = struct_len;
1887 if (stringspace) {
1888 *stringspace = len;
1890 return struct_len + len;
1893 len = struct_len;
1894 p = *buf;
1895 if ((*buflen) < struct_len) {
1896 return -1;
1899 if (stringbuf) {
1900 p2 = *stringbuf;
1901 l2 = *stringspace;
1902 } else {
1903 p2 = p + struct_len;
1904 l2 = (*buflen) - struct_len;
1907 if (!baseaddr) {
1908 baseaddr = p;
1911 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1913 if (uLevel > 0) {
1914 int type;
1916 SCVAL(p,13,0);
1917 type = STYPE_DISKTREE;
1918 if (lp_print_ok(snum)) {
1919 type = STYPE_PRINTQ;
1921 if (strequal("IPC",lp_fstype(snum))) {
1922 type = STYPE_IPC;
1924 SSVAL(p,14,type); /* device type */
1925 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1926 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1929 if (uLevel > 1) {
1930 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1931 SSVALS(p,22,-1); /* max uses */
1932 SSVAL(p,24,1); /* current uses */
1933 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1934 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1935 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1938 if (uLevel > 2) {
1939 memset(p+40,0,SHPWLEN+2);
1940 SSVAL(p,50,0);
1941 SIVAL(p,52,0);
1942 SSVAL(p,56,0);
1943 SSVAL(p,58,0);
1944 SIVAL(p,60,0);
1945 SSVAL(p,64,0);
1946 SSVAL(p,66,0);
1949 if (stringbuf) {
1950 (*buf) = p + struct_len;
1951 (*buflen) -= struct_len;
1952 (*stringbuf) = p2;
1953 (*stringspace) = l2;
1954 } else {
1955 (*buf) = p2;
1956 (*buflen) -= len;
1959 return len;
1962 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1963 char *param, int tpscnt,
1964 char *data, int tdscnt,
1965 int mdrcnt,int mprcnt,
1966 char **rdata,char **rparam,
1967 int *rdata_len,int *rparam_len)
1969 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1970 char *str2 = skip_string(param,tpscnt,str1);
1971 char *netname = skip_string(param,tpscnt,str2);
1972 char *p = skip_string(param,tpscnt,netname);
1973 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1974 int snum;
1976 if (!str1 || !str2 || !netname || !p) {
1977 return False;
1980 snum = find_service(netname);
1981 if (snum < 0) {
1982 return False;
1985 /* check it's a supported varient */
1986 if (!prefix_ok(str1,"zWrLh")) {
1987 return False;
1989 if (!check_share_info(uLevel,str2)) {
1990 return False;
1993 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1994 if (!*rdata) {
1995 return False;
1997 p = *rdata;
1998 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1999 if (*rdata_len < 0) {
2000 return False;
2003 *rparam_len = 6;
2004 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2005 if (!*rparam) {
2006 return False;
2008 SSVAL(*rparam,0,NERR_Success);
2009 SSVAL(*rparam,2,0); /* converter word */
2010 SSVAL(*rparam,4,*rdata_len);
2012 return True;
2015 /****************************************************************************
2016 View the list of available shares.
2018 This function is the server side of the NetShareEnum() RAP call.
2019 It fills the return buffer with share names and share comments.
2020 Note that the return buffer normally (in all known cases) allows only
2021 twelve byte strings for share names (plus one for a nul terminator).
2022 Share names longer than 12 bytes must be skipped.
2023 ****************************************************************************/
2025 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
2026 char *param, int tpscnt,
2027 char *data, int tdscnt,
2028 int mdrcnt,
2029 int mprcnt,
2030 char **rdata,
2031 char **rparam,
2032 int *rdata_len,
2033 int *rparam_len )
2035 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2036 char *str2 = skip_string(param,tpscnt,str1);
2037 char *p = skip_string(param,tpscnt,str2);
2038 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2039 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2040 char *p2;
2041 int count = 0;
2042 int total=0,counted=0;
2043 bool missed = False;
2044 int i;
2045 int data_len, fixed_len, string_len;
2046 int f_len = 0, s_len = 0;
2048 if (!str1 || !str2 || !p) {
2049 return False;
2052 if (!prefix_ok(str1,"WrLeh")) {
2053 return False;
2055 if (!check_share_info(uLevel,str2)) {
2056 return False;
2059 /* Ensure all the usershares are loaded. */
2060 become_root();
2061 load_registry_shares();
2062 count = load_usershare_shares();
2063 unbecome_root();
2065 data_len = fixed_len = string_len = 0;
2066 for (i=0;i<count;i++) {
2067 fstring servicename_dos;
2068 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2069 continue;
2071 push_ascii_fstring(servicename_dos, lp_servicename(i));
2072 /* Maximum name length = 13. */
2073 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2074 total++;
2075 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2076 if (data_len < buf_len) {
2077 counted++;
2078 fixed_len += f_len;
2079 string_len += s_len;
2080 } else {
2081 missed = True;
2086 *rdata_len = fixed_len + string_len;
2087 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2088 if (!*rdata) {
2089 return False;
2092 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2093 p = *rdata;
2094 f_len = fixed_len;
2095 s_len = string_len;
2097 for( i = 0; i < count; i++ ) {
2098 fstring servicename_dos;
2099 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2100 continue;
2103 push_ascii_fstring(servicename_dos, lp_servicename(i));
2104 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2105 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2106 break;
2111 *rparam_len = 8;
2112 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2113 if (!*rparam) {
2114 return False;
2116 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2117 SSVAL(*rparam,2,0);
2118 SSVAL(*rparam,4,counted);
2119 SSVAL(*rparam,6,total);
2121 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2122 counted,total,uLevel,
2123 buf_len,*rdata_len,mdrcnt));
2125 return True;
2128 /****************************************************************************
2129 Add a share
2130 ****************************************************************************/
2132 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2133 char *param, int tpscnt,
2134 char *data, int tdscnt,
2135 int mdrcnt,int mprcnt,
2136 char **rdata,char **rparam,
2137 int *rdata_len,int *rparam_len)
2139 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2140 char *str2 = skip_string(param,tpscnt,str1);
2141 char *p = skip_string(param,tpscnt,str2);
2142 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2143 fstring sharename;
2144 fstring comment;
2145 char *pathname = NULL;
2146 unsigned int offset;
2147 int res = ERRunsup;
2148 size_t converted_size;
2150 WERROR werr = WERR_OK;
2151 TALLOC_CTX *mem_ctx = talloc_tos();
2152 NTSTATUS status;
2153 struct rpc_pipe_client *cli = NULL;
2154 union srvsvc_NetShareInfo info;
2155 struct srvsvc_NetShareInfo2 info2;
2157 if (!str1 || !str2 || !p) {
2158 return False;
2161 /* check it's a supported varient */
2162 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2163 return False;
2165 if (!check_share_info(uLevel,str2)) {
2166 return False;
2168 if (uLevel != 2) {
2169 return False;
2172 /* Do we have a string ? */
2173 if (skip_string(data,mdrcnt,data) == NULL) {
2174 return False;
2176 pull_ascii_fstring(sharename,data);
2178 if (mdrcnt < 28) {
2179 return False;
2182 /* only support disk share adds */
2183 if (SVAL(data,14)!=STYPE_DISKTREE) {
2184 return False;
2187 offset = IVAL(data, 16);
2188 if (offset >= mdrcnt) {
2189 res = ERRinvalidparam;
2190 goto out;
2193 /* Do we have a string ? */
2194 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2195 return False;
2197 pull_ascii_fstring(comment, offset? (data+offset) : "");
2199 offset = IVAL(data, 26);
2201 if (offset >= mdrcnt) {
2202 res = ERRinvalidparam;
2203 goto out;
2206 /* Do we have a string ? */
2207 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2208 return False;
2211 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2212 offset ? (data+offset) : "", &converted_size))
2214 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2215 strerror(errno)));
2218 if (!pathname) {
2219 return false;
2222 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2223 rpc_srvsvc_dispatch, conn->server_info,
2224 &cli);
2225 if (!NT_STATUS_IS_OK(status)) {
2226 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2227 nt_errstr(status)));
2228 res = W_ERROR_V(ntstatus_to_werror(status));
2229 goto out;
2232 info2.name = sharename;
2233 info2.type = STYPE_DISKTREE;
2234 info2.comment = comment;
2235 info2.permissions = 0;
2236 info2.max_users = 0;
2237 info2.current_users = 0;
2238 info2.path = pathname;
2239 info2.password = NULL;
2241 info.info2 = &info2;
2243 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2244 cli->srv_name_slash,
2246 &info,
2247 NULL,
2248 &werr);
2249 if (!NT_STATUS_IS_OK(status)) {
2250 res = W_ERROR_V(ntstatus_to_werror(status));
2251 goto out;
2253 if (!W_ERROR_IS_OK(werr)) {
2254 res = W_ERROR_V(werr);
2255 goto out;
2258 *rparam_len = 6;
2259 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2260 if (!*rparam) {
2261 return False;
2263 SSVAL(*rparam,0,NERR_Success);
2264 SSVAL(*rparam,2,0); /* converter word */
2265 SSVAL(*rparam,4,*rdata_len);
2266 *rdata_len = 0;
2268 return True;
2270 out:
2272 *rparam_len = 4;
2273 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2274 if (!*rparam) {
2275 return False;
2277 *rdata_len = 0;
2278 SSVAL(*rparam,0,res);
2279 SSVAL(*rparam,2,0);
2280 return True;
2283 /****************************************************************************
2284 view list of groups available
2285 ****************************************************************************/
2287 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2288 char *param, int tpscnt,
2289 char *data, int tdscnt,
2290 int mdrcnt,int mprcnt,
2291 char **rdata,char **rparam,
2292 int *rdata_len,int *rparam_len)
2294 int i;
2295 int errflags=0;
2296 int resume_context, cli_buf_size;
2297 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2298 char *str2 = skip_string(param,tpscnt,str1);
2299 char *p = skip_string(param,tpscnt,str2);
2301 uint32_t num_groups;
2302 uint32_t resume_handle;
2303 struct rpc_pipe_client *samr_pipe;
2304 struct policy_handle samr_handle, domain_handle;
2305 NTSTATUS status;
2307 if (!str1 || !str2 || !p) {
2308 return False;
2311 if (strcmp(str1,"WrLeh") != 0) {
2312 return False;
2315 /* parameters
2316 * W-> resume context (number of users to skip)
2317 * r -> return parameter pointer to receive buffer
2318 * L -> length of receive buffer
2319 * e -> return parameter number of entries
2320 * h -> return parameter total number of users
2323 if (strcmp("B21",str2) != 0) {
2324 return False;
2327 status = rpc_pipe_open_internal(
2328 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2329 conn->server_info, &samr_pipe);
2330 if (!NT_STATUS_IS_OK(status)) {
2331 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2332 nt_errstr(status)));
2333 return false;
2336 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2337 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2338 if (!NT_STATUS_IS_OK(status)) {
2339 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2340 nt_errstr(status)));
2341 return false;
2344 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2345 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2346 get_global_sam_sid(), &domain_handle);
2347 if (!NT_STATUS_IS_OK(status)) {
2348 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2349 nt_errstr(status)));
2350 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2351 return false;
2354 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2355 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2356 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2357 "%d\n", resume_context, cli_buf_size));
2359 *rdata_len = cli_buf_size;
2360 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2361 if (!*rdata) {
2362 return False;
2365 p = *rdata;
2367 errflags = NERR_Success;
2368 num_groups = 0;
2369 resume_handle = 0;
2371 while (true) {
2372 struct samr_SamArray *sam_entries;
2373 uint32_t num_entries;
2375 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2376 &domain_handle,
2377 &resume_handle,
2378 &sam_entries, 1,
2379 &num_entries);
2380 if (!NT_STATUS_IS_OK(status)) {
2381 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2382 "%s\n", nt_errstr(status)));
2383 break;
2386 if (num_entries == 0) {
2387 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2388 "no entries -- done\n"));
2389 break;
2392 for(i=0; i<num_entries; i++) {
2393 const char *name;
2395 name = sam_entries->entries[i].name.string;
2397 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2398 /* set overflow error */
2399 DEBUG(3,("overflow on entry %d group %s\n", i,
2400 name));
2401 errflags=234;
2402 break;
2405 /* truncate the name at 21 chars. */
2406 memset(p, 0, 21);
2407 strlcpy(p, name, 21);
2408 DEBUG(10,("adding entry %d group %s\n", i, p));
2409 p += 21;
2410 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2411 * idea why... */
2412 num_groups += 1;
2415 if (errflags != NERR_Success) {
2416 break;
2419 TALLOC_FREE(sam_entries);
2422 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2423 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2425 *rdata_len = PTR_DIFF(p,*rdata);
2427 *rparam_len = 8;
2428 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2429 if (!*rparam) {
2430 return False;
2432 SSVAL(*rparam, 0, errflags);
2433 SSVAL(*rparam, 2, 0); /* converter word */
2434 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2435 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2437 return(True);
2440 /*******************************************************************
2441 Get groups that a user is a member of.
2442 ******************************************************************/
2444 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2445 char *param, int tpscnt,
2446 char *data, int tdscnt,
2447 int mdrcnt,int mprcnt,
2448 char **rdata,char **rparam,
2449 int *rdata_len,int *rparam_len)
2451 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2452 char *str2 = skip_string(param,tpscnt,str1);
2453 char *UserName = skip_string(param,tpscnt,str2);
2454 char *p = skip_string(param,tpscnt,UserName);
2455 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2456 const char *level_string;
2457 int count=0;
2458 bool ret = False;
2459 uint32_t i;
2460 char *endp = NULL;
2462 struct rpc_pipe_client *samr_pipe;
2463 struct policy_handle samr_handle, domain_handle, user_handle;
2464 struct lsa_String name;
2465 struct lsa_Strings names;
2466 struct samr_Ids type, rid;
2467 struct samr_RidWithAttributeArray *rids;
2468 NTSTATUS status;
2470 if (!str1 || !str2 || !UserName || !p) {
2471 return False;
2474 *rparam_len = 8;
2475 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2476 if (!*rparam) {
2477 return False;
2480 /* check it's a supported varient */
2482 if ( strcmp(str1,"zWrLeh") != 0 )
2483 return False;
2485 switch( uLevel ) {
2486 case 0:
2487 level_string = "B21";
2488 break;
2489 default:
2490 return False;
2493 if (strcmp(level_string,str2) != 0)
2494 return False;
2496 *rdata_len = mdrcnt + 1024;
2497 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2498 if (!*rdata) {
2499 return False;
2502 SSVAL(*rparam,0,NERR_Success);
2503 SSVAL(*rparam,2,0); /* converter word */
2505 p = *rdata;
2506 endp = *rdata + *rdata_len;
2508 status = rpc_pipe_open_internal(
2509 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2510 conn->server_info, &samr_pipe);
2511 if (!NT_STATUS_IS_OK(status)) {
2512 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2513 nt_errstr(status)));
2514 return false;
2517 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2518 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2519 if (!NT_STATUS_IS_OK(status)) {
2520 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2521 nt_errstr(status)));
2522 return false;
2525 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2526 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2527 get_global_sam_sid(), &domain_handle);
2528 if (!NT_STATUS_IS_OK(status)) {
2529 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2530 nt_errstr(status)));
2531 goto close_sam;
2534 name.string = UserName;
2536 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2537 &domain_handle, 1, &name,
2538 &rid, &type);
2539 if (!NT_STATUS_IS_OK(status)) {
2540 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2541 nt_errstr(status)));
2542 goto close_domain;
2545 if (type.ids[0] != SID_NAME_USER) {
2546 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2547 sid_type_lookup(type.ids[0])));
2548 goto close_domain;
2551 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2552 &domain_handle,
2553 SAMR_USER_ACCESS_GET_GROUPS,
2554 rid.ids[0], &user_handle);
2555 if (!NT_STATUS_IS_OK(status)) {
2556 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2557 nt_errstr(status)));
2558 goto close_domain;
2561 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2562 &user_handle, &rids);
2563 if (!NT_STATUS_IS_OK(status)) {
2564 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2565 nt_errstr(status)));
2566 goto close_user;
2569 for (i=0; i<rids->count; i++) {
2571 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2572 &domain_handle,
2573 1, &rids->rids[i].rid,
2574 &names, &type);
2575 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2576 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2577 p += 21;
2578 count++;
2582 *rdata_len = PTR_DIFF(p,*rdata);
2584 SSVAL(*rparam,4,count); /* is this right?? */
2585 SSVAL(*rparam,6,count); /* is this right?? */
2587 ret = True;
2589 close_user:
2590 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2591 close_domain:
2592 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2593 close_sam:
2594 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2596 return ret;
2599 /*******************************************************************
2600 Get all users.
2601 ******************************************************************/
2603 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2604 char *param, int tpscnt,
2605 char *data, int tdscnt,
2606 int mdrcnt,int mprcnt,
2607 char **rdata,char **rparam,
2608 int *rdata_len,int *rparam_len)
2610 int count_sent=0;
2611 int num_users=0;
2612 int errflags=0;
2613 int i, resume_context, cli_buf_size;
2614 uint32_t resume_handle;
2616 struct rpc_pipe_client *samr_pipe;
2617 struct policy_handle samr_handle, domain_handle;
2618 NTSTATUS status;
2620 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2621 char *str2 = skip_string(param,tpscnt,str1);
2622 char *p = skip_string(param,tpscnt,str2);
2623 char *endp = NULL;
2625 if (!str1 || !str2 || !p) {
2626 return False;
2629 if (strcmp(str1,"WrLeh") != 0)
2630 return False;
2631 /* parameters
2632 * W-> resume context (number of users to skip)
2633 * r -> return parameter pointer to receive buffer
2634 * L -> length of receive buffer
2635 * e -> return parameter number of entries
2636 * h -> return parameter total number of users
2639 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2640 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2641 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2642 resume_context, cli_buf_size));
2644 *rparam_len = 8;
2645 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2646 if (!*rparam) {
2647 return False;
2650 /* check it's a supported varient */
2651 if (strcmp("B21",str2) != 0)
2652 return False;
2654 *rdata_len = cli_buf_size;
2655 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2656 if (!*rdata) {
2657 return False;
2660 p = *rdata;
2661 endp = *rdata + *rdata_len;
2663 status = rpc_pipe_open_internal(
2664 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2665 conn->server_info, &samr_pipe);
2666 if (!NT_STATUS_IS_OK(status)) {
2667 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2668 nt_errstr(status)));
2669 return false;
2672 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2673 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2674 if (!NT_STATUS_IS_OK(status)) {
2675 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2676 nt_errstr(status)));
2677 return false;
2680 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2681 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2682 get_global_sam_sid(), &domain_handle);
2683 if (!NT_STATUS_IS_OK(status)) {
2684 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2685 nt_errstr(status)));
2686 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2687 return false;
2690 errflags=NERR_Success;
2692 resume_handle = 0;
2694 while (true) {
2695 struct samr_SamArray *sam_entries;
2696 uint32_t num_entries;
2698 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2699 &domain_handle,
2700 &resume_handle,
2701 0, &sam_entries, 1,
2702 &num_entries);
2704 if (!NT_STATUS_IS_OK(status)) {
2705 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2706 "%s\n", nt_errstr(status)));
2707 break;
2710 if (num_entries == 0) {
2711 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2712 "no entries -- done\n"));
2713 break;
2716 for (i=0; i<num_entries; i++) {
2717 const char *name;
2719 name = sam_entries->entries[i].name.string;
2721 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2722 &&(strlen(name)<=21)) {
2723 strlcpy(p,name,PTR_DIFF(endp,p));
2724 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2725 "username %s\n",count_sent,p));
2726 p += 21;
2727 count_sent++;
2728 } else {
2729 /* set overflow error */
2730 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2731 "username %s\n",count_sent,name));
2732 errflags=234;
2733 break;
2737 if (errflags != NERR_Success) {
2738 break;
2741 TALLOC_FREE(sam_entries);
2744 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2745 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2747 *rdata_len = PTR_DIFF(p,*rdata);
2749 SSVAL(*rparam,0,errflags);
2750 SSVAL(*rparam,2,0); /* converter word */
2751 SSVAL(*rparam,4,count_sent); /* is this right?? */
2752 SSVAL(*rparam,6,num_users); /* is this right?? */
2754 return True;
2757 /****************************************************************************
2758 Get the time of day info.
2759 ****************************************************************************/
2761 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2762 char *param, int tpscnt,
2763 char *data, int tdscnt,
2764 int mdrcnt,int mprcnt,
2765 char **rdata,char **rparam,
2766 int *rdata_len,int *rparam_len)
2768 struct tm *t;
2769 time_t unixdate = time(NULL);
2770 char *p;
2772 *rparam_len = 4;
2773 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2774 if (!*rparam) {
2775 return False;
2778 *rdata_len = 21;
2779 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2780 if (!*rdata) {
2781 return False;
2784 SSVAL(*rparam,0,NERR_Success);
2785 SSVAL(*rparam,2,0); /* converter word */
2787 p = *rdata;
2789 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2790 by NT in a "net time" operation,
2791 it seems to ignore the one below */
2793 /* the client expects to get localtime, not GMT, in this bit
2794 (I think, this needs testing) */
2795 t = localtime(&unixdate);
2796 if (!t) {
2797 return False;
2800 SIVAL(p,4,0); /* msecs ? */
2801 SCVAL(p,8,t->tm_hour);
2802 SCVAL(p,9,t->tm_min);
2803 SCVAL(p,10,t->tm_sec);
2804 SCVAL(p,11,0); /* hundredths of seconds */
2805 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2806 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2807 SCVAL(p,16,t->tm_mday);
2808 SCVAL(p,17,t->tm_mon + 1);
2809 SSVAL(p,18,1900+t->tm_year);
2810 SCVAL(p,20,t->tm_wday);
2812 return True;
2815 /****************************************************************************
2816 Set the user password.
2817 *****************************************************************************/
2819 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2820 char *param, int tpscnt,
2821 char *data, int tdscnt,
2822 int mdrcnt,int mprcnt,
2823 char **rdata,char **rparam,
2824 int *rdata_len,int *rparam_len)
2826 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2827 char *p = NULL;
2828 fstring user;
2829 fstring pass1,pass2;
2830 TALLOC_CTX *mem_ctx = talloc_tos();
2831 NTSTATUS status;
2832 struct rpc_pipe_client *cli = NULL;
2833 struct policy_handle connect_handle, domain_handle, user_handle;
2834 struct lsa_String domain_name;
2835 struct dom_sid2 *domain_sid;
2836 struct lsa_String names;
2837 struct samr_Ids rids;
2838 struct samr_Ids types;
2839 struct samr_Password old_lm_hash;
2840 struct samr_Password new_lm_hash;
2841 int errcode = NERR_badpass;
2842 uint32_t rid;
2843 int encrypted;
2844 int min_pwd_length;
2846 /* Skip 2 strings. */
2847 p = skip_string(param,tpscnt,np);
2848 p = skip_string(param,tpscnt,p);
2850 if (!np || !p) {
2851 return False;
2854 /* Do we have a string ? */
2855 if (skip_string(param,tpscnt,p) == NULL) {
2856 return False;
2858 pull_ascii_fstring(user,p);
2860 p = skip_string(param,tpscnt,p);
2861 if (!p) {
2862 return False;
2865 memset(pass1,'\0',sizeof(pass1));
2866 memset(pass2,'\0',sizeof(pass2));
2868 * We use 31 here not 32 as we're checking
2869 * the last byte we want to access is safe.
2871 if (!is_offset_safe(param,tpscnt,p,31)) {
2872 return False;
2874 memcpy(pass1,p,16);
2875 memcpy(pass2,p+16,16);
2877 encrypted = get_safe_SVAL(param,tpscnt,p+32,0,-1);
2878 if (encrypted == -1) {
2879 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2880 goto out;
2883 min_pwd_length = get_safe_SVAL(param,tpscnt,p+34,0,-1);
2884 if (min_pwd_length == -1) {
2885 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2886 goto out;
2889 *rparam_len = 4;
2890 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2891 if (!*rparam) {
2892 return False;
2895 *rdata_len = 0;
2897 DEBUG(3,("Set password for <%s> (encrypted: %d, min_pwd_length: %d)\n",
2898 user, encrypted, min_pwd_length));
2900 ZERO_STRUCT(connect_handle);
2901 ZERO_STRUCT(domain_handle);
2902 ZERO_STRUCT(user_handle);
2904 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
2905 rpc_samr_dispatch, conn->server_info,
2906 &cli);
2907 if (!NT_STATUS_IS_OK(status)) {
2908 DEBUG(0,("api_SetUserPassword: could not connect to samr: %s\n",
2909 nt_errstr(status)));
2910 errcode = W_ERROR_V(ntstatus_to_werror(status));
2911 goto out;
2914 status = rpccli_samr_Connect2(cli, mem_ctx,
2915 global_myname(),
2916 SAMR_ACCESS_CONNECT_TO_SERVER |
2917 SAMR_ACCESS_ENUM_DOMAINS |
2918 SAMR_ACCESS_LOOKUP_DOMAIN,
2919 &connect_handle);
2920 if (!NT_STATUS_IS_OK(status)) {
2921 errcode = W_ERROR_V(ntstatus_to_werror(status));
2922 goto out;
2925 init_lsa_String(&domain_name, get_global_sam_name());
2927 status = rpccli_samr_LookupDomain(cli, mem_ctx,
2928 &connect_handle,
2929 &domain_name,
2930 &domain_sid);
2931 if (!NT_STATUS_IS_OK(status)) {
2932 errcode = W_ERROR_V(ntstatus_to_werror(status));
2933 goto out;
2936 status = rpccli_samr_OpenDomain(cli, mem_ctx,
2937 &connect_handle,
2938 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2939 domain_sid,
2940 &domain_handle);
2941 if (!NT_STATUS_IS_OK(status)) {
2942 errcode = W_ERROR_V(ntstatus_to_werror(status));
2943 goto out;
2946 init_lsa_String(&names, user);
2948 status = rpccli_samr_LookupNames(cli, mem_ctx,
2949 &domain_handle,
2951 &names,
2952 &rids,
2953 &types);
2954 if (!NT_STATUS_IS_OK(status)) {
2955 errcode = W_ERROR_V(ntstatus_to_werror(status));
2956 goto out;
2959 if (rids.count != 1) {
2960 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
2961 goto out;
2963 if (rids.count != types.count) {
2964 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2965 goto out;
2967 if (types.ids[0] != SID_NAME_USER) {
2968 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2969 goto out;
2972 rid = rids.ids[0];
2974 status = rpccli_samr_OpenUser(cli, mem_ctx,
2975 &domain_handle,
2976 SAMR_USER_ACCESS_CHANGE_PASSWORD,
2977 rid,
2978 &user_handle);
2979 if (!NT_STATUS_IS_OK(status)) {
2980 errcode = W_ERROR_V(ntstatus_to_werror(status));
2981 goto out;
2984 if (encrypted == 0) {
2985 E_deshash(pass1, old_lm_hash.hash);
2986 E_deshash(pass2, new_lm_hash.hash);
2987 } else {
2988 ZERO_STRUCT(old_lm_hash);
2989 ZERO_STRUCT(new_lm_hash);
2990 memcpy(old_lm_hash.hash, pass1, MIN(strlen(pass1), 16));
2991 memcpy(new_lm_hash.hash, pass1, MIN(strlen(pass2), 16));
2994 status = rpccli_samr_ChangePasswordUser(cli, mem_ctx,
2995 &user_handle,
2996 true, /* lm_present */
2997 &old_lm_hash,
2998 &new_lm_hash,
2999 false, /* nt_present */
3000 NULL, /* old_nt_crypted */
3001 NULL, /* new_nt_crypted */
3002 false, /* cross1_present */
3003 NULL, /* nt_cross */
3004 false, /* cross2_present */
3005 NULL); /* lm_cross */
3006 if (!NT_STATUS_IS_OK(status)) {
3007 errcode = W_ERROR_V(ntstatus_to_werror(status));
3008 goto out;
3011 errcode = NERR_Success;
3012 out:
3014 if (cli && is_valid_policy_hnd(&user_handle)) {
3015 rpccli_samr_Close(cli, mem_ctx, &user_handle);
3017 if (cli && is_valid_policy_hnd(&domain_handle)) {
3018 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
3020 if (cli && is_valid_policy_hnd(&connect_handle)) {
3021 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
3024 memset((char *)pass1,'\0',sizeof(fstring));
3025 memset((char *)pass2,'\0',sizeof(fstring));
3027 SSVAL(*rparam,0,errcode);
3028 SSVAL(*rparam,2,0); /* converter word */
3029 return(True);
3032 /****************************************************************************
3033 Set the user password (SamOEM version - gets plaintext).
3034 ****************************************************************************/
3036 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
3037 char *param, int tpscnt,
3038 char *data, int tdscnt,
3039 int mdrcnt,int mprcnt,
3040 char **rdata,char **rparam,
3041 int *rdata_len,int *rparam_len)
3043 fstring user;
3044 char *p = get_safe_str_ptr(param,tpscnt,param,2);
3046 TALLOC_CTX *mem_ctx = talloc_tos();
3047 NTSTATUS status;
3048 struct rpc_pipe_client *cli = NULL;
3049 struct lsa_AsciiString server, account;
3050 struct samr_CryptPassword password;
3051 struct samr_Password hash;
3052 int errcode = NERR_badpass;
3053 int bufsize;
3055 *rparam_len = 4;
3056 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3057 if (!*rparam) {
3058 return False;
3061 if (!p) {
3062 return False;
3064 *rdata_len = 0;
3066 SSVAL(*rparam,0,NERR_badpass);
3069 * Check the parameter definition is correct.
3072 /* Do we have a string ? */
3073 if (skip_string(param,tpscnt,p) == 0) {
3074 return False;
3076 if(!strequal(p, "zsT")) {
3077 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3078 return False;
3080 p = skip_string(param, tpscnt, p);
3081 if (!p) {
3082 return False;
3085 /* Do we have a string ? */
3086 if (skip_string(param,tpscnt,p) == 0) {
3087 return False;
3089 if(!strequal(p, "B516B16")) {
3090 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3091 return False;
3093 p = skip_string(param,tpscnt,p);
3094 if (!p) {
3095 return False;
3097 /* Do we have a string ? */
3098 if (skip_string(param,tpscnt,p) == 0) {
3099 return False;
3101 p += pull_ascii_fstring(user,p);
3103 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3105 if (tdscnt != 532) {
3106 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3107 goto out;
3110 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3111 if (bufsize != 532) {
3112 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3113 goto out;
3116 memcpy(password.data, data, 516);
3117 memcpy(hash.hash, data+516, 16);
3119 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3120 rpc_samr_dispatch, conn->server_info,
3121 &cli);
3122 if (!NT_STATUS_IS_OK(status)) {
3123 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3124 nt_errstr(status)));
3125 errcode = W_ERROR_V(ntstatus_to_werror(status));
3126 goto out;
3129 init_lsa_AsciiString(&server, global_myname());
3130 init_lsa_AsciiString(&account, user);
3132 status = rpccli_samr_OemChangePasswordUser2(cli, mem_ctx,
3133 &server,
3134 &account,
3135 &password,
3136 &hash);
3137 if (!NT_STATUS_IS_OK(status)) {
3138 errcode = W_ERROR_V(ntstatus_to_werror(status));
3139 goto out;
3142 errcode = NERR_Success;
3143 out:
3144 SSVAL(*rparam,0,errcode);
3145 SSVAL(*rparam,2,0); /* converter word */
3147 return(True);
3150 /****************************************************************************
3151 delete a print job
3152 Form: <W> <>
3153 ****************************************************************************/
3155 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
3156 char *param, int tpscnt,
3157 char *data, int tdscnt,
3158 int mdrcnt,int mprcnt,
3159 char **rdata,char **rparam,
3160 int *rdata_len,int *rparam_len)
3162 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3163 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3164 char *str2 = skip_string(param,tpscnt,str1);
3165 char *p = skip_string(param,tpscnt,str2);
3166 uint32 jobid;
3167 fstring sharename;
3168 int errcode;
3169 WERROR werr = WERR_OK;
3171 TALLOC_CTX *mem_ctx = talloc_tos();
3172 NTSTATUS status;
3173 struct rpc_pipe_client *cli = NULL;
3174 struct policy_handle handle;
3175 struct spoolss_DevmodeContainer devmode_ctr;
3176 enum spoolss_JobControl command;
3178 if (!str1 || !str2 || !p) {
3179 return False;
3182 * We use 1 here not 2 as we're checking
3183 * the last byte we want to access is safe.
3185 if (!is_offset_safe(param,tpscnt,p,1)) {
3186 return False;
3188 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3189 return False;
3191 /* check it's a supported varient */
3192 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3193 return(False);
3195 *rparam_len = 4;
3196 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3197 if (!*rparam) {
3198 return False;
3200 *rdata_len = 0;
3202 ZERO_STRUCT(handle);
3204 status = rpc_connect_spoolss_pipe(conn, &cli);
3205 if (!NT_STATUS_IS_OK(status)) {
3206 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3207 nt_errstr(status)));
3208 errcode = W_ERROR_V(ntstatus_to_werror(status));
3209 goto out;
3212 ZERO_STRUCT(devmode_ctr);
3214 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3215 sharename,
3216 "RAW",
3217 devmode_ctr,
3218 JOB_ACCESS_ADMINISTER,
3219 &handle,
3220 &werr);
3221 if (!NT_STATUS_IS_OK(status)) {
3222 errcode = W_ERROR_V(ntstatus_to_werror(status));
3223 goto out;
3225 if (!W_ERROR_IS_OK(werr)) {
3226 errcode = W_ERROR_V(werr);
3227 goto out;
3230 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3231 * and NERR_DestNotFound if share did not exist */
3233 errcode = NERR_Success;
3235 switch (function) {
3236 case 81: /* delete */
3237 command = SPOOLSS_JOB_CONTROL_DELETE;
3238 break;
3239 case 82: /* pause */
3240 command = SPOOLSS_JOB_CONTROL_PAUSE;
3241 break;
3242 case 83: /* resume */
3243 command = SPOOLSS_JOB_CONTROL_RESUME;
3244 break;
3245 default:
3246 errcode = NERR_notsupported;
3247 goto out;
3250 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3251 &handle,
3252 jobid,
3253 NULL, /* unique ptr ctr */
3254 command,
3255 &werr);
3256 if (!NT_STATUS_IS_OK(status)) {
3257 errcode = W_ERROR_V(ntstatus_to_werror(status));
3258 goto out;
3260 if (!W_ERROR_IS_OK(werr)) {
3261 errcode = W_ERROR_V(werr);
3262 goto out;
3265 out:
3266 if (cli && is_valid_policy_hnd(&handle)) {
3267 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3270 SSVAL(*rparam,0,errcode);
3271 SSVAL(*rparam,2,0); /* converter word */
3273 return(True);
3276 /****************************************************************************
3277 Purge a print queue - or pause or resume it.
3278 ****************************************************************************/
3280 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3281 char *param, int tpscnt,
3282 char *data, int tdscnt,
3283 int mdrcnt,int mprcnt,
3284 char **rdata,char **rparam,
3285 int *rdata_len,int *rparam_len)
3287 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3288 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3289 char *str2 = skip_string(param,tpscnt,str1);
3290 char *QueueName = skip_string(param,tpscnt,str2);
3291 int errcode = NERR_notsupported;
3292 WERROR werr = WERR_OK;
3293 NTSTATUS status;
3295 TALLOC_CTX *mem_ctx = talloc_tos();
3296 struct rpc_pipe_client *cli = NULL;
3297 struct policy_handle handle;
3298 struct spoolss_SetPrinterInfoCtr info_ctr;
3299 struct spoolss_DevmodeContainer devmode_ctr;
3300 struct sec_desc_buf secdesc_ctr;
3301 enum spoolss_PrinterControl command;
3303 if (!str1 || !str2 || !QueueName) {
3304 return False;
3307 /* check it's a supported varient */
3308 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3309 return(False);
3311 *rparam_len = 4;
3312 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3313 if (!*rparam) {
3314 return False;
3316 *rdata_len = 0;
3318 if (skip_string(param,tpscnt,QueueName) == NULL) {
3319 return False;
3322 ZERO_STRUCT(handle);
3324 status = rpc_connect_spoolss_pipe(conn, &cli);
3325 if (!NT_STATUS_IS_OK(status)) {
3326 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3327 nt_errstr(status)));
3328 errcode = W_ERROR_V(ntstatus_to_werror(status));
3329 goto out;
3332 ZERO_STRUCT(devmode_ctr);
3334 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3335 QueueName,
3336 NULL,
3337 devmode_ctr,
3338 SEC_FLAG_MAXIMUM_ALLOWED,
3339 &handle,
3340 &werr);
3341 if (!NT_STATUS_IS_OK(status)) {
3342 errcode = W_ERROR_V(ntstatus_to_werror(status));
3343 goto out;
3345 if (!W_ERROR_IS_OK(werr)) {
3346 errcode = W_ERROR_V(werr);
3347 goto out;
3350 switch (function) {
3351 case 74: /* Pause queue */
3352 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3353 break;
3354 case 75: /* Resume queue */
3355 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3356 break;
3357 case 103: /* Purge */
3358 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3359 break;
3360 default:
3361 werr = WERR_NOT_SUPPORTED;
3362 break;
3365 if (!W_ERROR_IS_OK(werr)) {
3366 errcode = W_ERROR_V(werr);
3367 goto out;
3370 ZERO_STRUCT(info_ctr);
3371 ZERO_STRUCT(secdesc_ctr);
3373 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3374 &handle,
3375 &info_ctr,
3376 &devmode_ctr,
3377 &secdesc_ctr,
3378 command,
3379 &werr);
3380 if (!NT_STATUS_IS_OK(status)) {
3381 errcode = W_ERROR_V(ntstatus_to_werror(status));
3382 goto out;
3384 if (!W_ERROR_IS_OK(werr)) {
3385 errcode = W_ERROR_V(werr);
3386 goto out;
3389 errcode = W_ERROR_V(werr);
3391 out:
3393 if (cli && is_valid_policy_hnd(&handle)) {
3394 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3397 SSVAL(*rparam,0,errcode);
3398 SSVAL(*rparam,2,0); /* converter word */
3400 return(True);
3403 /****************************************************************************
3404 set the property of a print job (undocumented?)
3405 ? function = 0xb -> set name of print job
3406 ? function = 0x6 -> move print job up/down
3407 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3408 or <WWsTP> <WB21BB16B10zWWzDDz>
3409 ****************************************************************************/
3411 static int check_printjob_info(struct pack_desc* desc,
3412 int uLevel, char* id)
3414 desc->subformat = NULL;
3415 switch( uLevel ) {
3416 case 0: desc->format = "W"; break;
3417 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3418 case 2: desc->format = "WWzWWDDzz"; break;
3419 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3420 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3421 default:
3422 DEBUG(0,("check_printjob_info: invalid level %d\n",
3423 uLevel ));
3424 return False;
3426 if (id == NULL || strcmp(desc->format,id) != 0) {
3427 DEBUG(0,("check_printjob_info: invalid format %s\n",
3428 id ? id : "<NULL>" ));
3429 return False;
3431 return True;
3434 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3435 char *param, int tpscnt,
3436 char *data, int tdscnt,
3437 int mdrcnt,int mprcnt,
3438 char **rdata,char **rparam,
3439 int *rdata_len,int *rparam_len)
3441 struct pack_desc desc;
3442 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3443 char *str2 = skip_string(param,tpscnt,str1);
3444 char *p = skip_string(param,tpscnt,str2);
3445 uint32 jobid;
3446 fstring sharename;
3447 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3448 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3449 int errcode;
3451 TALLOC_CTX *mem_ctx = talloc_tos();
3452 WERROR werr;
3453 NTSTATUS status;
3454 struct rpc_pipe_client *cli = NULL;
3455 struct policy_handle handle;
3456 struct spoolss_DevmodeContainer devmode_ctr;
3457 struct spoolss_JobInfoContainer ctr;
3458 union spoolss_JobInfo info;
3459 struct spoolss_SetJobInfo1 info1;
3461 if (!str1 || !str2 || !p) {
3462 return False;
3465 * We use 1 here not 2 as we're checking
3466 * the last byte we want to access is safe.
3468 if (!is_offset_safe(param,tpscnt,p,1)) {
3469 return False;
3471 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3472 return False;
3473 *rparam_len = 4;
3474 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3475 if (!*rparam) {
3476 return False;
3479 *rdata_len = 0;
3481 /* check it's a supported varient */
3482 if ((strcmp(str1,"WWsTP")) ||
3483 (!check_printjob_info(&desc,uLevel,str2)))
3484 return(False);
3486 errcode = NERR_notsupported;
3488 switch (function) {
3489 case 0xb:
3490 /* change print job name, data gives the name */
3491 break;
3492 default:
3493 goto out;
3496 ZERO_STRUCT(handle);
3498 status = rpc_connect_spoolss_pipe(conn, &cli);
3499 if (!NT_STATUS_IS_OK(status)) {
3500 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3501 nt_errstr(status)));
3502 errcode = W_ERROR_V(ntstatus_to_werror(status));
3503 goto out;
3506 ZERO_STRUCT(devmode_ctr);
3508 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3509 sharename,
3510 "RAW",
3511 devmode_ctr,
3512 PRINTER_ACCESS_USE,
3513 &handle,
3514 &werr);
3515 if (!NT_STATUS_IS_OK(status)) {
3516 errcode = W_ERROR_V(ntstatus_to_werror(status));
3517 goto out;
3519 if (!W_ERROR_IS_OK(werr)) {
3520 errcode = W_ERROR_V(werr);
3521 goto out;
3524 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3525 &handle,
3526 jobid,
3527 1, /* level */
3528 0, /* offered */
3529 &info);
3530 if (!W_ERROR_IS_OK(werr)) {
3531 errcode = W_ERROR_V(werr);
3532 goto out;
3535 ZERO_STRUCT(ctr);
3537 info1.job_id = info.info1.job_id;
3538 info1.printer_name = info.info1.printer_name;
3539 info1.user_name = info.info1.user_name;
3540 info1.document_name = data;
3541 info1.data_type = info.info1.data_type;
3542 info1.text_status = info.info1.text_status;
3543 info1.status = info.info1.status;
3544 info1.priority = info.info1.priority;
3545 info1.position = info.info1.position;
3546 info1.total_pages = info.info1.total_pages;
3547 info1.pages_printed = info.info1.pages_printed;
3548 info1.submitted = info.info1.submitted;
3550 ctr.level = 1;
3551 ctr.info.info1 = &info1;
3553 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3554 &handle,
3555 jobid,
3556 &ctr,
3558 &werr);
3559 if (!NT_STATUS_IS_OK(status)) {
3560 errcode = W_ERROR_V(ntstatus_to_werror(status));
3561 goto out;
3563 if (!W_ERROR_IS_OK(werr)) {
3564 errcode = W_ERROR_V(werr);
3565 goto out;
3568 errcode = NERR_Success;
3569 out:
3571 if (cli && is_valid_policy_hnd(&handle)) {
3572 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3575 SSVALS(*rparam,0,errcode);
3576 SSVAL(*rparam,2,0); /* converter word */
3578 return(True);
3582 /****************************************************************************
3583 Get info about the server.
3584 ****************************************************************************/
3586 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3587 char *param, int tpscnt,
3588 char *data, int tdscnt,
3589 int mdrcnt,int mprcnt,
3590 char **rdata,char **rparam,
3591 int *rdata_len,int *rparam_len)
3593 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3594 char *str2 = skip_string(param,tpscnt,str1);
3595 char *p = skip_string(param,tpscnt,str2);
3596 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3597 char *p2;
3598 int struct_len;
3600 NTSTATUS status;
3601 WERROR werr;
3602 TALLOC_CTX *mem_ctx = talloc_tos();
3603 struct rpc_pipe_client *cli = NULL;
3604 union srvsvc_NetSrvInfo info;
3605 int errcode;
3607 if (!str1 || !str2 || !p) {
3608 return False;
3611 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3613 /* check it's a supported varient */
3614 if (!prefix_ok(str1,"WrLh")) {
3615 return False;
3618 switch( uLevel ) {
3619 case 0:
3620 if (strcmp(str2,"B16") != 0) {
3621 return False;
3623 struct_len = 16;
3624 break;
3625 case 1:
3626 if (strcmp(str2,"B16BBDz") != 0) {
3627 return False;
3629 struct_len = 26;
3630 break;
3631 case 2:
3632 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3633 return False;
3635 struct_len = 134;
3636 break;
3637 case 3:
3638 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3639 return False;
3641 struct_len = 144;
3642 break;
3643 case 20:
3644 if (strcmp(str2,"DN") != 0) {
3645 return False;
3647 struct_len = 6;
3648 break;
3649 case 50:
3650 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3651 return False;
3653 struct_len = 42;
3654 break;
3655 default:
3656 return False;
3659 *rdata_len = mdrcnt;
3660 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3661 if (!*rdata) {
3662 return False;
3665 p = *rdata;
3666 p2 = p + struct_len;
3668 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3669 rpc_srvsvc_dispatch, conn->server_info,
3670 &cli);
3671 if (!NT_STATUS_IS_OK(status)) {
3672 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3673 nt_errstr(status)));
3674 errcode = W_ERROR_V(ntstatus_to_werror(status));
3675 goto out;
3678 status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3679 NULL,
3680 101,
3681 &info,
3682 &werr);
3683 if (!NT_STATUS_IS_OK(status)) {
3684 errcode = W_ERROR_V(ntstatus_to_werror(status));
3685 goto out;
3687 if (!W_ERROR_IS_OK(werr)) {
3688 errcode = W_ERROR_V(werr);
3689 goto out;
3692 if (info.info101 == NULL) {
3693 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3694 goto out;
3697 if (uLevel != 20) {
3698 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3699 STR_ASCII|STR_UPPER|STR_TERMINATE);
3701 p += 16;
3702 if (uLevel > 0) {
3703 SCVAL(p,0,info.info101->version_major);
3704 SCVAL(p,1,info.info101->version_minor);
3705 SIVAL(p,2,info.info101->server_type);
3707 if (mdrcnt == struct_len) {
3708 SIVAL(p,6,0);
3709 } else {
3710 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3711 if (mdrcnt - struct_len <= 0) {
3712 return false;
3714 push_ascii(p2,
3715 info.info101->comment,
3716 MIN(mdrcnt - struct_len,
3717 MAX_SERVER_STRING_LENGTH),
3718 STR_TERMINATE);
3719 p2 = skip_string(*rdata,*rdata_len,p2);
3720 if (!p2) {
3721 return False;
3726 if (uLevel > 1) {
3727 return False; /* not yet implemented */
3730 errcode = NERR_Success;
3732 out:
3734 *rdata_len = PTR_DIFF(p2,*rdata);
3736 *rparam_len = 6;
3737 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3738 if (!*rparam) {
3739 return False;
3741 SSVAL(*rparam,0,errcode);
3742 SSVAL(*rparam,2,0); /* converter word */
3743 SSVAL(*rparam,4,*rdata_len);
3745 return True;
3748 /****************************************************************************
3749 Get info about the server.
3750 ****************************************************************************/
3752 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3753 char *param, int tpscnt,
3754 char *data, int tdscnt,
3755 int mdrcnt,int mprcnt,
3756 char **rdata,char **rparam,
3757 int *rdata_len,int *rparam_len)
3759 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3760 char *str2 = skip_string(param,tpscnt,str1);
3761 char *p = skip_string(param,tpscnt,str2);
3762 char *p2;
3763 char *endp;
3764 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3766 if (!str1 || !str2 || !p) {
3767 return False;
3770 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3772 *rparam_len = 6;
3773 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3774 if (!*rparam) {
3775 return False;
3778 /* check it's a supported varient */
3779 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3780 return False;
3783 *rdata_len = mdrcnt + 1024;
3784 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3785 if (!*rdata) {
3786 return False;
3789 SSVAL(*rparam,0,NERR_Success);
3790 SSVAL(*rparam,2,0); /* converter word */
3792 p = *rdata;
3793 endp = *rdata + *rdata_len;
3795 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3796 if (!p2) {
3797 return False;
3800 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3801 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3802 strupper_m(p2);
3803 p2 = skip_string(*rdata,*rdata_len,p2);
3804 if (!p2) {
3805 return False;
3807 p += 4;
3809 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3810 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3811 p2 = skip_string(*rdata,*rdata_len,p2);
3812 if (!p2) {
3813 return False;
3815 p += 4;
3817 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3818 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3819 strupper_m(p2);
3820 p2 = skip_string(*rdata,*rdata_len,p2);
3821 if (!p2) {
3822 return False;
3824 p += 4;
3826 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3827 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3828 p += 2;
3830 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3831 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3832 p2 = skip_string(*rdata,*rdata_len,p2);
3833 if (!p2) {
3834 return False;
3836 p += 4;
3838 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3839 strlcpy(p2,"",PTR_DIFF(endp,p2));
3840 p2 = skip_string(*rdata,*rdata_len,p2);
3841 if (!p2) {
3842 return False;
3844 p += 4;
3846 *rdata_len = PTR_DIFF(p2,*rdata);
3848 SSVAL(*rparam,4,*rdata_len);
3850 return True;
3853 /****************************************************************************
3854 get info about a user
3856 struct user_info_11 {
3857 char usri11_name[21]; 0-20
3858 char usri11_pad; 21
3859 char *usri11_comment; 22-25
3860 char *usri11_usr_comment; 26-29
3861 unsigned short usri11_priv; 30-31
3862 unsigned long usri11_auth_flags; 32-35
3863 long usri11_password_age; 36-39
3864 char *usri11_homedir; 40-43
3865 char *usri11_parms; 44-47
3866 long usri11_last_logon; 48-51
3867 long usri11_last_logoff; 52-55
3868 unsigned short usri11_bad_pw_count; 56-57
3869 unsigned short usri11_num_logons; 58-59
3870 char *usri11_logon_server; 60-63
3871 unsigned short usri11_country_code; 64-65
3872 char *usri11_workstations; 66-69
3873 unsigned long usri11_max_storage; 70-73
3874 unsigned short usri11_units_per_week; 74-75
3875 unsigned char *usri11_logon_hours; 76-79
3876 unsigned short usri11_code_page; 80-81
3879 where:
3881 usri11_name specifies the user name for which information is retrieved
3883 usri11_pad aligns the next data structure element to a word boundary
3885 usri11_comment is a null terminated ASCII comment
3887 usri11_user_comment is a null terminated ASCII comment about the user
3889 usri11_priv specifies the level of the privilege assigned to the user.
3890 The possible values are:
3892 Name Value Description
3893 USER_PRIV_GUEST 0 Guest privilege
3894 USER_PRIV_USER 1 User privilege
3895 USER_PRV_ADMIN 2 Administrator privilege
3897 usri11_auth_flags specifies the account operator privileges. The
3898 possible values are:
3900 Name Value Description
3901 AF_OP_PRINT 0 Print operator
3904 Leach, Naik [Page 28]
3908 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3911 AF_OP_COMM 1 Communications operator
3912 AF_OP_SERVER 2 Server operator
3913 AF_OP_ACCOUNTS 3 Accounts operator
3916 usri11_password_age specifies how many seconds have elapsed since the
3917 password was last changed.
3919 usri11_home_dir points to a null terminated ASCII string that contains
3920 the path name of the user's home directory.
3922 usri11_parms points to a null terminated ASCII string that is set
3923 aside for use by applications.
3925 usri11_last_logon specifies the time when the user last logged on.
3926 This value is stored as the number of seconds elapsed since
3927 00:00:00, January 1, 1970.
3929 usri11_last_logoff specifies the time when the user last logged off.
3930 This value is stored as the number of seconds elapsed since
3931 00:00:00, January 1, 1970. A value of 0 means the last logoff
3932 time is unknown.
3934 usri11_bad_pw_count specifies the number of incorrect passwords
3935 entered since the last successful logon.
3937 usri11_log1_num_logons specifies the number of times this user has
3938 logged on. A value of -1 means the number of logons is unknown.
3940 usri11_logon_server points to a null terminated ASCII string that
3941 contains the name of the server to which logon requests are sent.
3942 A null string indicates logon requests should be sent to the
3943 domain controller.
3945 usri11_country_code specifies the country code for the user's language
3946 of choice.
3948 usri11_workstations points to a null terminated ASCII string that
3949 contains the names of workstations the user may log on from.
3950 There may be up to 8 workstations, with the names separated by
3951 commas. A null strings indicates there are no restrictions.
3953 usri11_max_storage specifies the maximum amount of disk space the user
3954 can occupy. A value of 0xffffffff indicates there are no
3955 restrictions.
3957 usri11_units_per_week specifies the equal number of time units into
3958 which a week is divided. This value must be equal to 168.
3960 usri11_logon_hours points to a 21 byte (168 bits) string that
3961 specifies the time during which the user can log on. Each bit
3962 represents one unique hour in a week. The first bit (bit 0, word
3963 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3967 Leach, Naik [Page 29]
3971 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3974 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3975 are no restrictions.
3977 usri11_code_page specifies the code page for the user's language of
3978 choice
3980 All of the pointers in this data structure need to be treated
3981 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3982 to be ignored. The converter word returned in the parameters section
3983 needs to be subtracted from the lower 16 bits to calculate an offset
3984 into the return buffer where this ASCII string resides.
3986 There is no auxiliary data in the response.
3988 ****************************************************************************/
3990 #define usri11_name 0
3991 #define usri11_pad 21
3992 #define usri11_comment 22
3993 #define usri11_usr_comment 26
3994 #define usri11_full_name 30
3995 #define usri11_priv 34
3996 #define usri11_auth_flags 36
3997 #define usri11_password_age 40
3998 #define usri11_homedir 44
3999 #define usri11_parms 48
4000 #define usri11_last_logon 52
4001 #define usri11_last_logoff 56
4002 #define usri11_bad_pw_count 60
4003 #define usri11_num_logons 62
4004 #define usri11_logon_server 64
4005 #define usri11_country_code 68
4006 #define usri11_workstations 70
4007 #define usri11_max_storage 74
4008 #define usri11_units_per_week 78
4009 #define usri11_logon_hours 80
4010 #define usri11_code_page 84
4011 #define usri11_end 86
4013 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
4014 char *param, int tpscnt,
4015 char *data, int tdscnt,
4016 int mdrcnt,int mprcnt,
4017 char **rdata,char **rparam,
4018 int *rdata_len,int *rparam_len)
4020 struct smbd_server_connection *sconn = smbd_server_conn;
4021 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4022 char *str2 = skip_string(param,tpscnt,str1);
4023 char *UserName = skip_string(param,tpscnt,str2);
4024 char *p = skip_string(param,tpscnt,UserName);
4025 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4026 char *p2;
4027 char *endp;
4028 const char *level_string;
4030 /* get NIS home of a previously validated user - simeon */
4031 /* With share level security vuid will always be zero.
4032 Don't depend on vuser being non-null !!. JRA */
4033 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4034 if(vuser != NULL) {
4035 DEBUG(3,(" Username of UID %d is %s\n",
4036 (int)vuser->server_info->utok.uid,
4037 vuser->server_info->unix_name));
4040 if (!str1 || !str2 || !UserName || !p) {
4041 return False;
4044 *rparam_len = 6;
4045 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4046 if (!*rparam) {
4047 return False;
4050 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4052 /* check it's a supported variant */
4053 if (strcmp(str1,"zWrLh") != 0) {
4054 return False;
4056 switch( uLevel ) {
4057 case 0: level_string = "B21"; break;
4058 case 1: level_string = "B21BB16DWzzWz"; break;
4059 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4060 case 10: level_string = "B21Bzzz"; break;
4061 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4062 default: return False;
4065 if (strcmp(level_string,str2) != 0) {
4066 return False;
4069 *rdata_len = mdrcnt + 1024;
4070 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4071 if (!*rdata) {
4072 return False;
4075 SSVAL(*rparam,0,NERR_Success);
4076 SSVAL(*rparam,2,0); /* converter word */
4078 p = *rdata;
4079 endp = *rdata + *rdata_len;
4080 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4081 if (!p2) {
4082 return False;
4085 memset(p,0,21);
4086 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4088 if (uLevel > 0) {
4089 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4090 *p2 = 0;
4093 if (uLevel >= 10) {
4094 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4095 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4096 p2 = skip_string(*rdata,*rdata_len,p2);
4097 if (!p2) {
4098 return False;
4101 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4102 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4103 p2 = skip_string(*rdata,*rdata_len,p2);
4104 if (!p2) {
4105 return False;
4108 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4109 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4110 strlcpy(p2,((vuser != NULL)
4111 ? pdb_get_fullname(vuser->server_info->sam_account)
4112 : UserName),PTR_DIFF(endp,p2));
4113 p2 = skip_string(*rdata,*rdata_len,p2);
4114 if (!p2) {
4115 return False;
4119 if (uLevel == 11) {
4120 const char *homedir = "";
4121 if (vuser != NULL) {
4122 homedir = pdb_get_homedir(
4123 vuser->server_info->sam_account);
4125 /* modelled after NTAS 3.51 reply */
4126 SSVAL(p,usri11_priv,
4127 (get_current_uid(conn) == sec_initial_uid())?
4128 USER_PRIV_ADMIN:USER_PRIV_USER);
4129 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4130 SIVALS(p,usri11_password_age,-1); /* password age */
4131 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4132 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4133 p2 = skip_string(*rdata,*rdata_len,p2);
4134 if (!p2) {
4135 return False;
4137 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4138 strlcpy(p2,"",PTR_DIFF(endp,p2));
4139 p2 = skip_string(*rdata,*rdata_len,p2);
4140 if (!p2) {
4141 return False;
4143 SIVAL(p,usri11_last_logon,0); /* last logon */
4144 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4145 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4146 SSVALS(p,usri11_num_logons,-1); /* num logons */
4147 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4148 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4149 p2 = skip_string(*rdata,*rdata_len,p2);
4150 if (!p2) {
4151 return False;
4153 SSVAL(p,usri11_country_code,0); /* country code */
4155 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4156 strlcpy(p2,"",PTR_DIFF(endp,p2));
4157 p2 = skip_string(*rdata,*rdata_len,p2);
4158 if (!p2) {
4159 return False;
4162 SIVALS(p,usri11_max_storage,-1); /* max storage */
4163 SSVAL(p,usri11_units_per_week,168); /* units per week */
4164 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4166 /* a simple way to get logon hours at all times. */
4167 memset(p2,0xff,21);
4168 SCVAL(p2,21,0); /* fix zero termination */
4169 p2 = skip_string(*rdata,*rdata_len,p2);
4170 if (!p2) {
4171 return False;
4174 SSVAL(p,usri11_code_page,0); /* code page */
4177 if (uLevel == 1 || uLevel == 2) {
4178 memset(p+22,' ',16); /* password */
4179 SIVALS(p,38,-1); /* password age */
4180 SSVAL(p,42,
4181 (get_current_uid(conn) == sec_initial_uid())?
4182 USER_PRIV_ADMIN:USER_PRIV_USER);
4183 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4184 strlcpy(p2, vuser ? pdb_get_homedir(
4185 vuser->server_info->sam_account) : "",
4186 PTR_DIFF(endp,p2));
4187 p2 = skip_string(*rdata,*rdata_len,p2);
4188 if (!p2) {
4189 return False;
4191 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4192 *p2++ = 0;
4193 SSVAL(p,52,0); /* flags */
4194 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4195 strlcpy(p2, vuser ? pdb_get_logon_script(
4196 vuser->server_info->sam_account) : "",
4197 PTR_DIFF(endp,p2));
4198 p2 = skip_string(*rdata,*rdata_len,p2);
4199 if (!p2) {
4200 return False;
4202 if (uLevel == 2) {
4203 SIVAL(p,60,0); /* auth_flags */
4204 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4205 strlcpy(p2,((vuser != NULL)
4206 ? pdb_get_fullname(vuser->server_info->sam_account)
4207 : UserName),PTR_DIFF(endp,p2));
4208 p2 = skip_string(*rdata,*rdata_len,p2);
4209 if (!p2) {
4210 return False;
4212 SIVAL(p,68,0); /* urs_comment */
4213 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4214 strlcpy(p2,"",PTR_DIFF(endp,p2));
4215 p2 = skip_string(*rdata,*rdata_len,p2);
4216 if (!p2) {
4217 return False;
4219 SIVAL(p,76,0); /* workstations */
4220 SIVAL(p,80,0); /* last_logon */
4221 SIVAL(p,84,0); /* last_logoff */
4222 SIVALS(p,88,-1); /* acct_expires */
4223 SIVALS(p,92,-1); /* max_storage */
4224 SSVAL(p,96,168); /* units_per_week */
4225 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4226 memset(p2,-1,21);
4227 p2 += 21;
4228 SSVALS(p,102,-1); /* bad_pw_count */
4229 SSVALS(p,104,-1); /* num_logons */
4230 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4232 TALLOC_CTX *ctx = talloc_tos();
4233 int space_rem = *rdata_len - (p2 - *rdata);
4234 char *tmp;
4236 if (space_rem <= 0) {
4237 return false;
4239 tmp = talloc_strdup(ctx, "\\\\%L");
4240 if (!tmp) {
4241 return false;
4243 tmp = talloc_sub_basic(ctx,
4246 tmp);
4247 if (!tmp) {
4248 return false;
4251 push_ascii(p2,
4252 tmp,
4253 space_rem,
4254 STR_TERMINATE);
4256 p2 = skip_string(*rdata,*rdata_len,p2);
4257 if (!p2) {
4258 return False;
4260 SSVAL(p,110,49); /* country_code */
4261 SSVAL(p,112,860); /* code page */
4265 *rdata_len = PTR_DIFF(p2,*rdata);
4267 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4269 return(True);
4272 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4273 char *param, int tpscnt,
4274 char *data, int tdscnt,
4275 int mdrcnt,int mprcnt,
4276 char **rdata,char **rparam,
4277 int *rdata_len,int *rparam_len)
4279 struct smbd_server_connection *sconn = smbd_server_conn;
4280 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4281 char *str2 = skip_string(param,tpscnt,str1);
4282 char *p = skip_string(param,tpscnt,str2);
4283 int uLevel;
4284 struct pack_desc desc;
4285 char* name;
4286 /* With share level security vuid will always be zero.
4287 Don't depend on vuser being non-null !!. JRA */
4288 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4290 if (!str1 || !str2 || !p) {
4291 return False;
4294 if(vuser != NULL) {
4295 DEBUG(3,(" Username of UID %d is %s\n",
4296 (int)vuser->server_info->utok.uid,
4297 vuser->server_info->unix_name));
4300 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4301 name = get_safe_str_ptr(param,tpscnt,p,2);
4302 if (!name) {
4303 return False;
4306 memset((char *)&desc,'\0',sizeof(desc));
4308 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4310 /* check it's a supported varient */
4311 if (strcmp(str1,"OOWb54WrLh") != 0) {
4312 return False;
4314 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4315 return False;
4317 if (mdrcnt > 0) {
4318 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4319 if (!*rdata) {
4320 return False;
4324 desc.base = *rdata;
4325 desc.buflen = mdrcnt;
4326 desc.subformat = NULL;
4327 desc.format = str2;
4329 if (init_package(&desc,1,0)) {
4330 PACKI(&desc,"W",0); /* code */
4331 PACKS(&desc,"B21",name); /* eff. name */
4332 PACKS(&desc,"B",""); /* pad */
4333 PACKI(&desc,"W",
4334 (get_current_uid(conn) == sec_initial_uid())?
4335 USER_PRIV_ADMIN:USER_PRIV_USER);
4336 PACKI(&desc,"D",0); /* auth flags XXX */
4337 PACKI(&desc,"W",0); /* num logons */
4338 PACKI(&desc,"W",0); /* bad pw count */
4339 PACKI(&desc,"D",0); /* last logon */
4340 PACKI(&desc,"D",-1); /* last logoff */
4341 PACKI(&desc,"D",-1); /* logoff time */
4342 PACKI(&desc,"D",-1); /* kickoff time */
4343 PACKI(&desc,"D",0); /* password age */
4344 PACKI(&desc,"D",0); /* password can change */
4345 PACKI(&desc,"D",-1); /* password must change */
4348 fstring mypath;
4349 fstrcpy(mypath,"\\\\");
4350 fstrcat(mypath,get_local_machine_name());
4351 strupper_m(mypath);
4352 PACKS(&desc,"z",mypath); /* computer */
4355 PACKS(&desc,"z",lp_workgroup());/* domain */
4356 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4357 vuser->server_info->sam_account) : ""); /* script path */
4358 PACKI(&desc,"D",0x00000000); /* reserved */
4361 *rdata_len = desc.usedlen;
4362 *rparam_len = 6;
4363 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4364 if (!*rparam) {
4365 return False;
4367 SSVALS(*rparam,0,desc.errcode);
4368 SSVAL(*rparam,2,0);
4369 SSVAL(*rparam,4,desc.neededlen);
4371 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4373 return True;
4376 /****************************************************************************
4377 api_WAccessGetUserPerms
4378 ****************************************************************************/
4380 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4381 char *param, int tpscnt,
4382 char *data, int tdscnt,
4383 int mdrcnt,int mprcnt,
4384 char **rdata,char **rparam,
4385 int *rdata_len,int *rparam_len)
4387 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4388 char *str2 = skip_string(param,tpscnt,str1);
4389 char *user = skip_string(param,tpscnt,str2);
4390 char *resource = skip_string(param,tpscnt,user);
4392 if (!str1 || !str2 || !user || !resource) {
4393 return False;
4396 if (skip_string(param,tpscnt,resource) == NULL) {
4397 return False;
4399 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4401 /* check it's a supported varient */
4402 if (strcmp(str1,"zzh") != 0) {
4403 return False;
4405 if (strcmp(str2,"") != 0) {
4406 return False;
4409 *rparam_len = 6;
4410 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4411 if (!*rparam) {
4412 return False;
4414 SSVALS(*rparam,0,0); /* errorcode */
4415 SSVAL(*rparam,2,0); /* converter word */
4416 SSVAL(*rparam,4,0x7f); /* permission flags */
4418 return True;
4421 /****************************************************************************
4422 api_WPrintJobEnumerate
4423 ****************************************************************************/
4425 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4426 char *param, int tpscnt,
4427 char *data, int tdscnt,
4428 int mdrcnt,int mprcnt,
4429 char **rdata,char **rparam,
4430 int *rdata_len,int *rparam_len)
4432 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4433 char *str2 = skip_string(param,tpscnt,str1);
4434 char *p = skip_string(param,tpscnt,str2);
4435 int uLevel;
4436 fstring sharename;
4437 uint32 jobid;
4438 struct pack_desc desc;
4439 char *tmpdata=NULL;
4441 TALLOC_CTX *mem_ctx = talloc_tos();
4442 WERROR werr;
4443 NTSTATUS status;
4444 struct rpc_pipe_client *cli = NULL;
4445 struct policy_handle handle;
4446 struct spoolss_DevmodeContainer devmode_ctr;
4447 union spoolss_JobInfo info;
4449 if (!str1 || !str2 || !p) {
4450 return False;
4453 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4455 memset((char *)&desc,'\0',sizeof(desc));
4456 memset((char *)&status,'\0',sizeof(status));
4458 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4460 /* check it's a supported varient */
4461 if (strcmp(str1,"WWrLh") != 0) {
4462 return False;
4464 if (!check_printjob_info(&desc,uLevel,str2)) {
4465 return False;
4468 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4469 return False;
4472 ZERO_STRUCT(handle);
4474 status = rpc_connect_spoolss_pipe(conn, &cli);
4475 if (!NT_STATUS_IS_OK(status)) {
4476 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4477 nt_errstr(status)));
4478 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4479 goto out;
4482 ZERO_STRUCT(devmode_ctr);
4484 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4485 sharename,
4486 "RAW",
4487 devmode_ctr,
4488 PRINTER_ACCESS_USE,
4489 &handle,
4490 &werr);
4491 if (!NT_STATUS_IS_OK(status)) {
4492 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4493 goto out;
4495 if (!W_ERROR_IS_OK(werr)) {
4496 desc.errcode = W_ERROR_V(werr);
4497 goto out;
4500 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4501 &handle,
4502 jobid,
4503 2, /* level */
4504 0, /* offered */
4505 &info);
4506 if (!W_ERROR_IS_OK(werr)) {
4507 desc.errcode = W_ERROR_V(werr);
4508 goto out;
4511 if (mdrcnt > 0) {
4512 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4513 if (!*rdata) {
4514 return False;
4516 desc.base = *rdata;
4517 desc.buflen = mdrcnt;
4518 } else {
4520 * Don't return data but need to get correct length
4521 * init_package will return wrong size if buflen=0
4523 desc.buflen = getlen(desc.format);
4524 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4527 if (init_package(&desc,1,0)) {
4528 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4529 *rdata_len = desc.usedlen;
4530 } else {
4531 desc.errcode = NERR_JobNotFound;
4532 *rdata_len = 0;
4534 out:
4535 if (cli && is_valid_policy_hnd(&handle)) {
4536 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4539 *rparam_len = 6;
4540 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4541 if (!*rparam) {
4542 return False;
4544 SSVALS(*rparam,0,desc.errcode);
4545 SSVAL(*rparam,2,0);
4546 SSVAL(*rparam,4,desc.neededlen);
4548 SAFE_FREE(tmpdata);
4550 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4552 return True;
4555 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4556 char *param, int tpscnt,
4557 char *data, int tdscnt,
4558 int mdrcnt,int mprcnt,
4559 char **rdata,char **rparam,
4560 int *rdata_len,int *rparam_len)
4562 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4563 char *str2 = skip_string(param,tpscnt,str1);
4564 char *p = skip_string(param,tpscnt,str2);
4565 char *name = p;
4566 int uLevel;
4567 int i, succnt=0;
4568 struct pack_desc desc;
4570 TALLOC_CTX *mem_ctx = talloc_tos();
4571 WERROR werr;
4572 NTSTATUS status;
4573 struct rpc_pipe_client *cli = NULL;
4574 struct policy_handle handle;
4575 struct spoolss_DevmodeContainer devmode_ctr;
4576 uint32_t count;
4577 union spoolss_JobInfo *info;
4579 if (!str1 || !str2 || !p) {
4580 return False;
4583 memset((char *)&desc,'\0',sizeof(desc));
4585 p = skip_string(param,tpscnt,p);
4586 if (!p) {
4587 return False;
4589 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4591 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4593 /* check it's a supported variant */
4594 if (strcmp(str1,"zWrLeh") != 0) {
4595 return False;
4598 if (uLevel > 2) {
4599 return False; /* defined only for uLevel 0,1,2 */
4602 if (!check_printjob_info(&desc,uLevel,str2)) {
4603 return False;
4606 ZERO_STRUCT(handle);
4608 status = rpc_connect_spoolss_pipe(conn, &cli);
4609 if (!NT_STATUS_IS_OK(status)) {
4610 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4611 nt_errstr(status)));
4612 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4613 goto out;
4616 ZERO_STRUCT(devmode_ctr);
4618 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4619 name,
4620 NULL,
4621 devmode_ctr,
4622 SEC_FLAG_MAXIMUM_ALLOWED,
4623 &handle,
4624 &werr);
4625 if (!NT_STATUS_IS_OK(status)) {
4626 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4627 goto out;
4629 if (!W_ERROR_IS_OK(werr)) {
4630 desc.errcode = W_ERROR_V(werr);
4631 goto out;
4634 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4635 &handle,
4636 0, /* firstjob */
4637 0xff, /* numjobs */
4638 2, /* level */
4639 0, /* offered */
4640 &count,
4641 &info);
4642 if (!W_ERROR_IS_OK(werr)) {
4643 desc.errcode = W_ERROR_V(werr);
4644 goto out;
4647 if (mdrcnt > 0) {
4648 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4649 if (!*rdata) {
4650 return False;
4653 desc.base = *rdata;
4654 desc.buflen = mdrcnt;
4656 if (init_package(&desc,count,0)) {
4657 succnt = 0;
4658 for (i = 0; i < count; i++) {
4659 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4660 if (desc.errcode == NERR_Success) {
4661 succnt = i+1;
4665 out:
4666 if (cli && is_valid_policy_hnd(&handle)) {
4667 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4670 *rdata_len = desc.usedlen;
4672 *rparam_len = 8;
4673 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4674 if (!*rparam) {
4675 return False;
4677 SSVALS(*rparam,0,desc.errcode);
4678 SSVAL(*rparam,2,0);
4679 SSVAL(*rparam,4,succnt);
4680 SSVAL(*rparam,6,count);
4682 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4684 return True;
4687 static int check_printdest_info(struct pack_desc* desc,
4688 int uLevel, char* id)
4690 desc->subformat = NULL;
4691 switch( uLevel ) {
4692 case 0:
4693 desc->format = "B9";
4694 break;
4695 case 1:
4696 desc->format = "B9B21WWzW";
4697 break;
4698 case 2:
4699 desc->format = "z";
4700 break;
4701 case 3:
4702 desc->format = "zzzWWzzzWW";
4703 break;
4704 default:
4705 DEBUG(0,("check_printdest_info: invalid level %d\n",
4706 uLevel));
4707 return False;
4709 if (id == NULL || strcmp(desc->format,id) != 0) {
4710 DEBUG(0,("check_printdest_info: invalid string %s\n",
4711 id ? id : "<NULL>" ));
4712 return False;
4714 return True;
4717 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4718 struct pack_desc* desc)
4720 char buf[100];
4722 strncpy(buf, info2->printername, sizeof(buf)-1);
4723 buf[sizeof(buf)-1] = 0;
4724 strupper_m(buf);
4726 if (uLevel <= 1) {
4727 PACKS(desc,"B9",buf); /* szName */
4728 if (uLevel == 1) {
4729 PACKS(desc,"B21",""); /* szUserName */
4730 PACKI(desc,"W",0); /* uJobId */
4731 PACKI(desc,"W",0); /* fsStatus */
4732 PACKS(desc,"z",""); /* pszStatus */
4733 PACKI(desc,"W",0); /* time */
4737 if (uLevel == 2 || uLevel == 3) {
4738 PACKS(desc,"z",buf); /* pszPrinterName */
4739 if (uLevel == 3) {
4740 PACKS(desc,"z",""); /* pszUserName */
4741 PACKS(desc,"z",""); /* pszLogAddr */
4742 PACKI(desc,"W",0); /* uJobId */
4743 PACKI(desc,"W",0); /* fsStatus */
4744 PACKS(desc,"z",""); /* pszStatus */
4745 PACKS(desc,"z",""); /* pszComment */
4746 PACKS(desc,"z","NULL"); /* pszDrivers */
4747 PACKI(desc,"W",0); /* time */
4748 PACKI(desc,"W",0); /* pad1 */
4753 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4754 char *param, int tpscnt,
4755 char *data, int tdscnt,
4756 int mdrcnt,int mprcnt,
4757 char **rdata,char **rparam,
4758 int *rdata_len,int *rparam_len)
4760 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4761 char *str2 = skip_string(param,tpscnt,str1);
4762 char *p = skip_string(param,tpscnt,str2);
4763 char* PrinterName = p;
4764 int uLevel;
4765 struct pack_desc desc;
4766 char *tmpdata=NULL;
4768 TALLOC_CTX *mem_ctx = talloc_tos();
4769 WERROR werr;
4770 NTSTATUS status;
4771 struct rpc_pipe_client *cli = NULL;
4772 struct policy_handle handle;
4773 struct spoolss_DevmodeContainer devmode_ctr;
4774 union spoolss_PrinterInfo info;
4776 if (!str1 || !str2 || !p) {
4777 return False;
4780 memset((char *)&desc,'\0',sizeof(desc));
4782 p = skip_string(param,tpscnt,p);
4783 if (!p) {
4784 return False;
4786 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4788 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4790 /* check it's a supported varient */
4791 if (strcmp(str1,"zWrLh") != 0) {
4792 return False;
4794 if (!check_printdest_info(&desc,uLevel,str2)) {
4795 return False;
4798 ZERO_STRUCT(handle);
4800 status = rpc_connect_spoolss_pipe(conn, &cli);
4801 if (!NT_STATUS_IS_OK(status)) {
4802 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4803 nt_errstr(status)));
4804 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4805 goto out;
4808 ZERO_STRUCT(devmode_ctr);
4810 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4811 PrinterName,
4812 NULL,
4813 devmode_ctr,
4814 SEC_FLAG_MAXIMUM_ALLOWED,
4815 &handle,
4816 &werr);
4817 if (!NT_STATUS_IS_OK(status)) {
4818 *rdata_len = 0;
4819 desc.errcode = NERR_DestNotFound;
4820 desc.neededlen = 0;
4821 goto out;
4823 if (!W_ERROR_IS_OK(werr)) {
4824 *rdata_len = 0;
4825 desc.errcode = NERR_DestNotFound;
4826 desc.neededlen = 0;
4827 goto out;
4830 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4831 &handle,
4834 &info);
4835 if (!W_ERROR_IS_OK(werr)) {
4836 *rdata_len = 0;
4837 desc.errcode = NERR_DestNotFound;
4838 desc.neededlen = 0;
4839 goto out;
4842 if (mdrcnt > 0) {
4843 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4844 if (!*rdata) {
4845 return False;
4847 desc.base = *rdata;
4848 desc.buflen = mdrcnt;
4849 } else {
4851 * Don't return data but need to get correct length
4852 * init_package will return wrong size if buflen=0
4854 desc.buflen = getlen(desc.format);
4855 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4857 if (init_package(&desc,1,0)) {
4858 fill_printdest_info(&info.info2, uLevel,&desc);
4861 out:
4862 if (cli && is_valid_policy_hnd(&handle)) {
4863 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4866 *rdata_len = desc.usedlen;
4868 *rparam_len = 6;
4869 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4870 if (!*rparam) {
4871 return False;
4873 SSVALS(*rparam,0,desc.errcode);
4874 SSVAL(*rparam,2,0);
4875 SSVAL(*rparam,4,desc.neededlen);
4877 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4878 SAFE_FREE(tmpdata);
4880 return True;
4883 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4884 char *param, int tpscnt,
4885 char *data, int tdscnt,
4886 int mdrcnt,int mprcnt,
4887 char **rdata,char **rparam,
4888 int *rdata_len,int *rparam_len)
4890 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4891 char *str2 = skip_string(param,tpscnt,str1);
4892 char *p = skip_string(param,tpscnt,str2);
4893 int uLevel;
4894 int queuecnt;
4895 int i, n, succnt=0;
4896 struct pack_desc desc;
4898 TALLOC_CTX *mem_ctx = talloc_tos();
4899 WERROR werr;
4900 NTSTATUS status;
4901 struct rpc_pipe_client *cli = NULL;
4902 union spoolss_PrinterInfo *info;
4903 uint32_t count;
4905 if (!str1 || !str2 || !p) {
4906 return False;
4909 memset((char *)&desc,'\0',sizeof(desc));
4911 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4913 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4915 /* check it's a supported varient */
4916 if (strcmp(str1,"WrLeh") != 0) {
4917 return False;
4919 if (!check_printdest_info(&desc,uLevel,str2)) {
4920 return False;
4923 queuecnt = 0;
4925 status = rpc_connect_spoolss_pipe(conn, &cli);
4926 if (!NT_STATUS_IS_OK(status)) {
4927 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
4928 nt_errstr(status)));
4929 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4930 goto out;
4933 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
4934 PRINTER_ENUM_LOCAL,
4935 cli->srv_name_slash,
4938 &count,
4939 &info);
4940 if (!W_ERROR_IS_OK(werr)) {
4941 desc.errcode = W_ERROR_V(werr);
4942 *rdata_len = 0;
4943 desc.errcode = NERR_DestNotFound;
4944 desc.neededlen = 0;
4945 goto out;
4948 queuecnt = count;
4950 if (mdrcnt > 0) {
4951 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4952 if (!*rdata) {
4953 return False;
4957 desc.base = *rdata;
4958 desc.buflen = mdrcnt;
4959 if (init_package(&desc,queuecnt,0)) {
4960 succnt = 0;
4961 n = 0;
4962 for (i = 0; i < count; i++) {
4963 fill_printdest_info(&info[i].info2, uLevel,&desc);
4964 n++;
4965 if (desc.errcode == NERR_Success) {
4966 succnt = n;
4970 out:
4971 *rdata_len = desc.usedlen;
4973 *rparam_len = 8;
4974 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4975 if (!*rparam) {
4976 return False;
4978 SSVALS(*rparam,0,desc.errcode);
4979 SSVAL(*rparam,2,0);
4980 SSVAL(*rparam,4,succnt);
4981 SSVAL(*rparam,6,queuecnt);
4983 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4985 return True;
4988 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4989 char *param, int tpscnt,
4990 char *data, int tdscnt,
4991 int mdrcnt,int mprcnt,
4992 char **rdata,char **rparam,
4993 int *rdata_len,int *rparam_len)
4995 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4996 char *str2 = skip_string(param,tpscnt,str1);
4997 char *p = skip_string(param,tpscnt,str2);
4998 int uLevel;
4999 int succnt;
5000 struct pack_desc desc;
5002 if (!str1 || !str2 || !p) {
5003 return False;
5006 memset((char *)&desc,'\0',sizeof(desc));
5008 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5010 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5012 /* check it's a supported varient */
5013 if (strcmp(str1,"WrLeh") != 0) {
5014 return False;
5016 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5017 return False;
5020 if (mdrcnt > 0) {
5021 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5022 if (!*rdata) {
5023 return False;
5026 desc.base = *rdata;
5027 desc.buflen = mdrcnt;
5028 if (init_package(&desc,1,0)) {
5029 PACKS(&desc,"B41","NULL");
5032 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5034 *rdata_len = desc.usedlen;
5036 *rparam_len = 8;
5037 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5038 if (!*rparam) {
5039 return False;
5041 SSVALS(*rparam,0,desc.errcode);
5042 SSVAL(*rparam,2,0);
5043 SSVAL(*rparam,4,succnt);
5044 SSVAL(*rparam,6,1);
5046 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5048 return True;
5051 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
5052 char *param, int tpscnt,
5053 char *data, int tdscnt,
5054 int mdrcnt,int mprcnt,
5055 char **rdata,char **rparam,
5056 int *rdata_len,int *rparam_len)
5058 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5059 char *str2 = skip_string(param,tpscnt,str1);
5060 char *p = skip_string(param,tpscnt,str2);
5061 int uLevel;
5062 int succnt;
5063 struct pack_desc desc;
5065 if (!str1 || !str2 || !p) {
5066 return False;
5068 memset((char *)&desc,'\0',sizeof(desc));
5070 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5072 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5074 /* check it's a supported varient */
5075 if (strcmp(str1,"WrLeh") != 0) {
5076 return False;
5078 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5079 return False;
5082 if (mdrcnt > 0) {
5083 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5084 if (!*rdata) {
5085 return False;
5088 desc.base = *rdata;
5089 desc.buflen = mdrcnt;
5090 desc.format = str2;
5091 if (init_package(&desc,1,0)) {
5092 PACKS(&desc,"B13","lpd");
5095 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5097 *rdata_len = desc.usedlen;
5099 *rparam_len = 8;
5100 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5101 if (!*rparam) {
5102 return False;
5104 SSVALS(*rparam,0,desc.errcode);
5105 SSVAL(*rparam,2,0);
5106 SSVAL(*rparam,4,succnt);
5107 SSVAL(*rparam,6,1);
5109 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5111 return True;
5114 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
5115 char *param, int tpscnt,
5116 char *data, int tdscnt,
5117 int mdrcnt,int mprcnt,
5118 char **rdata,char **rparam,
5119 int *rdata_len,int *rparam_len)
5121 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5122 char *str2 = skip_string(param,tpscnt,str1);
5123 char *p = skip_string(param,tpscnt,str2);
5124 int uLevel;
5125 int succnt;
5126 struct pack_desc desc;
5128 if (!str1 || !str2 || !p) {
5129 return False;
5132 memset((char *)&desc,'\0',sizeof(desc));
5134 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5136 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5138 /* check it's a supported varient */
5139 if (strcmp(str1,"WrLeh") != 0) {
5140 return False;
5142 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5143 return False;
5146 if (mdrcnt > 0) {
5147 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5148 if (!*rdata) {
5149 return False;
5152 memset((char *)&desc,'\0',sizeof(desc));
5153 desc.base = *rdata;
5154 desc.buflen = mdrcnt;
5155 desc.format = str2;
5156 if (init_package(&desc,1,0)) {
5157 PACKS(&desc,"B13","lp0");
5160 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5162 *rdata_len = desc.usedlen;
5164 *rparam_len = 8;
5165 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5166 if (!*rparam) {
5167 return False;
5169 SSVALS(*rparam,0,desc.errcode);
5170 SSVAL(*rparam,2,0);
5171 SSVAL(*rparam,4,succnt);
5172 SSVAL(*rparam,6,1);
5174 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5176 return True;
5179 /****************************************************************************
5180 List open sessions
5181 ****************************************************************************/
5183 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5184 char *param, int tpscnt,
5185 char *data, int tdscnt,
5186 int mdrcnt,int mprcnt,
5187 char **rdata,char **rparam,
5188 int *rdata_len,int *rparam_len)
5191 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5192 char *str2 = skip_string(param,tpscnt,str1);
5193 char *p = skip_string(param,tpscnt,str2);
5194 int uLevel;
5195 struct pack_desc desc;
5196 struct sessionid *session_list;
5197 int i, num_sessions;
5199 if (!str1 || !str2 || !p) {
5200 return False;
5203 memset((char *)&desc,'\0',sizeof(desc));
5205 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5207 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5208 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5209 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5211 /* check it's a supported varient */
5212 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5213 return False;
5215 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5216 return False;
5219 num_sessions = list_sessions(talloc_tos(), &session_list);
5221 if (mdrcnt > 0) {
5222 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5223 if (!*rdata) {
5224 return False;
5227 memset((char *)&desc,'\0',sizeof(desc));
5228 desc.base = *rdata;
5229 desc.buflen = mdrcnt;
5230 desc.format = str2;
5231 if (!init_package(&desc,num_sessions,0)) {
5232 return False;
5235 for(i=0; i<num_sessions; i++) {
5236 PACKS(&desc, "z", session_list[i].remote_machine);
5237 PACKS(&desc, "z", session_list[i].username);
5238 PACKI(&desc, "W", 1); /* num conns */
5239 PACKI(&desc, "W", 0); /* num opens */
5240 PACKI(&desc, "W", 1); /* num users */
5241 PACKI(&desc, "D", 0); /* session time */
5242 PACKI(&desc, "D", 0); /* idle time */
5243 PACKI(&desc, "D", 0); /* flags */
5244 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5247 *rdata_len = desc.usedlen;
5249 *rparam_len = 8;
5250 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5251 if (!*rparam) {
5252 return False;
5254 SSVALS(*rparam,0,desc.errcode);
5255 SSVAL(*rparam,2,0); /* converter */
5256 SSVAL(*rparam,4,num_sessions); /* count */
5258 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5260 return True;
5264 /****************************************************************************
5265 The buffer was too small.
5266 ****************************************************************************/
5268 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5269 int mdrcnt, int mprcnt,
5270 char **rdata, char **rparam,
5271 int *rdata_len, int *rparam_len)
5273 *rparam_len = MIN(*rparam_len,mprcnt);
5274 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5275 if (!*rparam) {
5276 return False;
5279 *rdata_len = 0;
5281 SSVAL(*rparam,0,NERR_BufTooSmall);
5283 DEBUG(3,("Supplied buffer too small in API command\n"));
5285 return True;
5288 /****************************************************************************
5289 The request is not supported.
5290 ****************************************************************************/
5292 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5293 char *param, int tpscnt,
5294 char *data, int tdscnt,
5295 int mdrcnt, int mprcnt,
5296 char **rdata, char **rparam,
5297 int *rdata_len, int *rparam_len)
5299 *rparam_len = 4;
5300 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5301 if (!*rparam) {
5302 return False;
5305 *rdata_len = 0;
5307 SSVAL(*rparam,0,NERR_notsupported);
5308 SSVAL(*rparam,2,0); /* converter word */
5310 DEBUG(3,("Unsupported API command\n"));
5312 return True;
5315 static const struct {
5316 const char *name;
5317 int id;
5318 bool (*fn)(connection_struct *, uint16,
5319 char *, int,
5320 char *, int,
5321 int,int,char **,char **,int *,int *);
5322 bool auth_user; /* Deny anonymous access? */
5323 } api_commands[] = {
5324 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5325 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5326 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5327 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5328 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5329 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5330 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5331 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5332 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5333 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5334 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5335 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5336 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5337 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5338 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5339 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5340 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5341 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5342 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5343 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5344 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5345 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5346 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5347 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5348 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5349 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5350 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5351 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5352 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5353 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5354 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5355 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5356 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5357 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5358 {NULL, -1, api_Unsupported}
5359 /* The following RAP calls are not implemented by Samba:
5361 RAP_WFileEnum2 - anon not OK
5366 /****************************************************************************
5367 Handle remote api calls.
5368 ****************************************************************************/
5370 void api_reply(connection_struct *conn, uint16 vuid,
5371 struct smb_request *req,
5372 char *data, char *params,
5373 int tdscnt, int tpscnt,
5374 int mdrcnt, int mprcnt)
5376 struct smbd_server_connection *sconn = smbd_server_conn;
5377 int api_command;
5378 char *rdata = NULL;
5379 char *rparam = NULL;
5380 const char *name1 = NULL;
5381 const char *name2 = NULL;
5382 int rdata_len = 0;
5383 int rparam_len = 0;
5384 bool reply=False;
5385 int i;
5387 if (!params) {
5388 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5389 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5390 return;
5393 if (tpscnt < 2) {
5394 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5395 return;
5397 api_command = SVAL(params,0);
5398 /* Is there a string at position params+2 ? */
5399 if (skip_string(params,tpscnt,params+2)) {
5400 name1 = params + 2;
5401 } else {
5402 name1 = "";
5404 name2 = skip_string(params,tpscnt,params+2);
5405 if (!name2) {
5406 name2 = "";
5409 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5410 api_command,
5411 name1,
5412 name2,
5413 tdscnt,tpscnt,mdrcnt,mprcnt));
5415 for (i=0;api_commands[i].name;i++) {
5416 if (api_commands[i].id == api_command && api_commands[i].fn) {
5417 DEBUG(3,("Doing %s\n",api_commands[i].name));
5418 break;
5422 /* Check whether this api call can be done anonymously */
5424 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5425 user_struct *user = get_valid_user_struct(sconn, vuid);
5427 if (!user || user->server_info->guest) {
5428 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5429 return;
5433 rdata = (char *)SMB_MALLOC(1024);
5434 if (rdata) {
5435 memset(rdata,'\0',1024);
5438 rparam = (char *)SMB_MALLOC(1024);
5439 if (rparam) {
5440 memset(rparam,'\0',1024);
5443 if(!rdata || !rparam) {
5444 DEBUG(0,("api_reply: malloc fail !\n"));
5445 SAFE_FREE(rdata);
5446 SAFE_FREE(rparam);
5447 reply_nterror(req, NT_STATUS_NO_MEMORY);
5448 return;
5451 reply = api_commands[i].fn(conn,
5452 vuid,
5453 params,tpscnt, /* params + length */
5454 data,tdscnt, /* data + length */
5455 mdrcnt,mprcnt,
5456 &rdata,&rparam,&rdata_len,&rparam_len);
5459 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5460 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5461 &rdata,&rparam,&rdata_len,&rparam_len);
5464 /* if we get False back then it's actually unsupported */
5465 if (!reply) {
5466 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5467 &rdata,&rparam,&rdata_len,&rparam_len);
5470 /* If api_Unsupported returns false we can't return anything. */
5471 if (reply) {
5472 send_trans_reply(conn, req, rparam, rparam_len,
5473 rdata, rdata_len, False);
5476 SAFE_FREE(rdata);
5477 SAFE_FREE(rparam);
5478 return;