s4-smbtorture: remove another incarnation of test_ClosePrinter.
[Samba.git] / source3 / smbd / lanman.c
blob6c94a88b61226c7d988c4eec6689e31adffdea61
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 conn->server_info->info3->base.domain.string,
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 conn->server_info->info3->base.domain.string,
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 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4021 char *str2 = skip_string(param,tpscnt,str1);
4022 char *UserName = skip_string(param,tpscnt,str2);
4023 char *p = skip_string(param,tpscnt,UserName);
4024 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4025 char *p2;
4026 char *endp;
4027 const char *level_string;
4029 TALLOC_CTX *mem_ctx = talloc_tos();
4030 NTSTATUS status;
4031 struct rpc_pipe_client *cli = NULL;
4032 struct policy_handle connect_handle, domain_handle, user_handle;
4033 struct lsa_String domain_name;
4034 struct dom_sid2 *domain_sid;
4035 struct lsa_String names;
4036 struct samr_Ids rids;
4037 struct samr_Ids types;
4038 int errcode = W_ERROR_V(WERR_USER_NOT_FOUND);
4039 uint32_t rid;
4040 union samr_UserInfo *info;
4042 if (!str1 || !str2 || !UserName || !p) {
4043 return False;
4046 *rparam_len = 6;
4047 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4048 if (!*rparam) {
4049 return False;
4052 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4054 /* check it's a supported variant */
4055 if (strcmp(str1,"zWrLh") != 0) {
4056 return False;
4058 switch( uLevel ) {
4059 case 0: level_string = "B21"; break;
4060 case 1: level_string = "B21BB16DWzzWz"; break;
4061 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4062 case 10: level_string = "B21Bzzz"; break;
4063 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4064 default: return False;
4067 if (strcmp(level_string,str2) != 0) {
4068 return False;
4071 *rdata_len = mdrcnt + 1024;
4072 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4073 if (!*rdata) {
4074 return False;
4077 p = *rdata;
4078 endp = *rdata + *rdata_len;
4079 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4080 if (!p2) {
4081 return False;
4084 ZERO_STRUCT(connect_handle);
4085 ZERO_STRUCT(domain_handle);
4086 ZERO_STRUCT(user_handle);
4088 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
4089 rpc_samr_dispatch, conn->server_info,
4090 &cli);
4091 if (!NT_STATUS_IS_OK(status)) {
4092 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4093 nt_errstr(status)));
4094 errcode = W_ERROR_V(ntstatus_to_werror(status));
4095 goto out;
4098 status = rpccli_samr_Connect2(cli, mem_ctx,
4099 global_myname(),
4100 SAMR_ACCESS_CONNECT_TO_SERVER |
4101 SAMR_ACCESS_ENUM_DOMAINS |
4102 SAMR_ACCESS_LOOKUP_DOMAIN,
4103 &connect_handle);
4104 if (!NT_STATUS_IS_OK(status)) {
4105 errcode = W_ERROR_V(ntstatus_to_werror(status));
4106 goto out;
4109 init_lsa_String(&domain_name, get_global_sam_name());
4111 status = rpccli_samr_LookupDomain(cli, mem_ctx,
4112 &connect_handle,
4113 &domain_name,
4114 &domain_sid);
4115 if (!NT_STATUS_IS_OK(status)) {
4116 errcode = W_ERROR_V(ntstatus_to_werror(status));
4117 goto out;
4120 status = rpccli_samr_OpenDomain(cli, mem_ctx,
4121 &connect_handle,
4122 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4123 domain_sid,
4124 &domain_handle);
4125 if (!NT_STATUS_IS_OK(status)) {
4126 errcode = W_ERROR_V(ntstatus_to_werror(status));
4127 goto out;
4130 init_lsa_String(&names, UserName);
4132 status = rpccli_samr_LookupNames(cli, mem_ctx,
4133 &domain_handle,
4135 &names,
4136 &rids,
4137 &types);
4138 if (!NT_STATUS_IS_OK(status)) {
4139 errcode = W_ERROR_V(ntstatus_to_werror(status));
4140 goto out;
4143 if (rids.count != 1) {
4144 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4145 goto out;
4147 if (rids.count != types.count) {
4148 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4149 goto out;
4151 if (types.ids[0] != SID_NAME_USER) {
4152 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4153 goto out;
4156 rid = rids.ids[0];
4158 status = rpccli_samr_OpenUser(cli, mem_ctx,
4159 &domain_handle,
4160 SAMR_USER_ACCESS_GET_LOCALE |
4161 SAMR_USER_ACCESS_GET_LOGONINFO |
4162 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4163 SAMR_USER_ACCESS_GET_GROUPS |
4164 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4165 SEC_STD_READ_CONTROL,
4166 rid,
4167 &user_handle);
4168 if (!NT_STATUS_IS_OK(status)) {
4169 errcode = W_ERROR_V(ntstatus_to_werror(status));
4170 goto out;
4173 status = rpccli_samr_QueryUserInfo2(cli, mem_ctx,
4174 &user_handle,
4175 UserAllInformation,
4176 &info);
4177 if (!NT_STATUS_IS_OK(status)) {
4178 errcode = W_ERROR_V(ntstatus_to_werror(status));
4179 goto out;
4182 memset(p,0,21);
4183 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4185 if (uLevel > 0) {
4186 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4187 *p2 = 0;
4190 if (uLevel >= 10) {
4191 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4192 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4193 p2 = skip_string(*rdata,*rdata_len,p2);
4194 if (!p2) {
4195 return False;
4198 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4199 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4200 p2 = skip_string(*rdata,*rdata_len,p2);
4201 if (!p2) {
4202 return False;
4205 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4206 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4207 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4208 p2 = skip_string(*rdata,*rdata_len,p2);
4209 if (!p2) {
4210 return False;
4214 if (uLevel == 11) {
4215 const char *homedir = info->info21.home_directory.string;
4216 /* modelled after NTAS 3.51 reply */
4217 SSVAL(p,usri11_priv,
4218 (get_current_uid(conn) == sec_initial_uid())?
4219 USER_PRIV_ADMIN:USER_PRIV_USER);
4220 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4221 SIVALS(p,usri11_password_age,-1); /* password age */
4222 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4223 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4224 p2 = skip_string(*rdata,*rdata_len,p2);
4225 if (!p2) {
4226 return False;
4228 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4229 strlcpy(p2,"",PTR_DIFF(endp,p2));
4230 p2 = skip_string(*rdata,*rdata_len,p2);
4231 if (!p2) {
4232 return False;
4234 SIVAL(p,usri11_last_logon,0); /* last logon */
4235 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4236 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4237 SSVALS(p,usri11_num_logons,-1); /* num logons */
4238 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4239 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4240 p2 = skip_string(*rdata,*rdata_len,p2);
4241 if (!p2) {
4242 return False;
4244 SSVAL(p,usri11_country_code,0); /* country code */
4246 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4247 strlcpy(p2,"",PTR_DIFF(endp,p2));
4248 p2 = skip_string(*rdata,*rdata_len,p2);
4249 if (!p2) {
4250 return False;
4253 SIVALS(p,usri11_max_storage,-1); /* max storage */
4254 SSVAL(p,usri11_units_per_week,168); /* units per week */
4255 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4257 /* a simple way to get logon hours at all times. */
4258 memset(p2,0xff,21);
4259 SCVAL(p2,21,0); /* fix zero termination */
4260 p2 = skip_string(*rdata,*rdata_len,p2);
4261 if (!p2) {
4262 return False;
4265 SSVAL(p,usri11_code_page,0); /* code page */
4268 if (uLevel == 1 || uLevel == 2) {
4269 memset(p+22,' ',16); /* password */
4270 SIVALS(p,38,-1); /* password age */
4271 SSVAL(p,42,
4272 (get_current_uid(conn) == sec_initial_uid())?
4273 USER_PRIV_ADMIN:USER_PRIV_USER);
4274 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4275 strlcpy(p2, info->info21.home_directory.string,
4276 PTR_DIFF(endp,p2));
4277 p2 = skip_string(*rdata,*rdata_len,p2);
4278 if (!p2) {
4279 return False;
4281 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4282 *p2++ = 0;
4283 SSVAL(p,52,0); /* flags */
4284 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4285 strlcpy(p2, info->info21.logon_script.string,
4286 PTR_DIFF(endp,p2));
4287 p2 = skip_string(*rdata,*rdata_len,p2);
4288 if (!p2) {
4289 return False;
4291 if (uLevel == 2) {
4292 SIVAL(p,58,0); /* auth_flags */
4293 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4294 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4295 p2 = skip_string(*rdata,*rdata_len,p2);
4296 if (!p2) {
4297 return False;
4299 SIVAL(p,66,0); /* urs_comment */
4300 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4301 strlcpy(p2,"",PTR_DIFF(endp,p2));
4302 p2 = skip_string(*rdata,*rdata_len,p2);
4303 if (!p2) {
4304 return False;
4306 SIVAL(p,74,0); /* workstations */
4307 SIVAL(p,78,0); /* last_logon */
4308 SIVAL(p,82,0); /* last_logoff */
4309 SIVALS(p,86,-1); /* acct_expires */
4310 SIVALS(p,90,-1); /* max_storage */
4311 SSVAL(p,94,168); /* units_per_week */
4312 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4313 memset(p2,-1,21);
4314 p2 += 21;
4315 SSVALS(p,100,-1); /* bad_pw_count */
4316 SSVALS(p,102,-1); /* num_logons */
4317 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4319 TALLOC_CTX *ctx = talloc_tos();
4320 int space_rem = *rdata_len - (p2 - *rdata);
4321 char *tmp;
4323 if (space_rem <= 0) {
4324 return false;
4326 tmp = talloc_strdup(ctx, "\\\\%L");
4327 if (!tmp) {
4328 return false;
4330 tmp = talloc_sub_basic(ctx,
4333 tmp);
4334 if (!tmp) {
4335 return false;
4338 push_ascii(p2,
4339 tmp,
4340 space_rem,
4341 STR_TERMINATE);
4343 p2 = skip_string(*rdata,*rdata_len,p2);
4344 if (!p2) {
4345 return False;
4347 SSVAL(p,108,49); /* country_code */
4348 SSVAL(p,110,860); /* code page */
4352 errcode = NERR_Success;
4354 out:
4355 *rdata_len = PTR_DIFF(p2,*rdata);
4357 if (cli && is_valid_policy_hnd(&user_handle)) {
4358 rpccli_samr_Close(cli, mem_ctx, &user_handle);
4360 if (cli && is_valid_policy_hnd(&domain_handle)) {
4361 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
4363 if (cli && is_valid_policy_hnd(&connect_handle)) {
4364 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
4367 SSVAL(*rparam,0,errcode);
4368 SSVAL(*rparam,2,0); /* converter word */
4369 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4371 return(True);
4374 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4375 char *param, int tpscnt,
4376 char *data, int tdscnt,
4377 int mdrcnt,int mprcnt,
4378 char **rdata,char **rparam,
4379 int *rdata_len,int *rparam_len)
4381 struct smbd_server_connection *sconn = smbd_server_conn;
4382 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4383 char *str2 = skip_string(param,tpscnt,str1);
4384 char *p = skip_string(param,tpscnt,str2);
4385 int uLevel;
4386 struct pack_desc desc;
4387 char* name;
4388 /* With share level security vuid will always be zero.
4389 Don't depend on vuser being non-null !!. JRA */
4390 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4392 if (!str1 || !str2 || !p) {
4393 return False;
4396 if(vuser != NULL) {
4397 DEBUG(3,(" Username of UID %d is %s\n",
4398 (int)vuser->server_info->utok.uid,
4399 vuser->server_info->unix_name));
4402 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4403 name = get_safe_str_ptr(param,tpscnt,p,2);
4404 if (!name) {
4405 return False;
4408 memset((char *)&desc,'\0',sizeof(desc));
4410 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4412 /* check it's a supported varient */
4413 if (strcmp(str1,"OOWb54WrLh") != 0) {
4414 return False;
4416 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4417 return False;
4419 if (mdrcnt > 0) {
4420 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4421 if (!*rdata) {
4422 return False;
4426 desc.base = *rdata;
4427 desc.buflen = mdrcnt;
4428 desc.subformat = NULL;
4429 desc.format = str2;
4431 if (init_package(&desc,1,0)) {
4432 PACKI(&desc,"W",0); /* code */
4433 PACKS(&desc,"B21",name); /* eff. name */
4434 PACKS(&desc,"B",""); /* pad */
4435 PACKI(&desc,"W",
4436 (get_current_uid(conn) == sec_initial_uid())?
4437 USER_PRIV_ADMIN:USER_PRIV_USER);
4438 PACKI(&desc,"D",0); /* auth flags XXX */
4439 PACKI(&desc,"W",0); /* num logons */
4440 PACKI(&desc,"W",0); /* bad pw count */
4441 PACKI(&desc,"D",0); /* last logon */
4442 PACKI(&desc,"D",-1); /* last logoff */
4443 PACKI(&desc,"D",-1); /* logoff time */
4444 PACKI(&desc,"D",-1); /* kickoff time */
4445 PACKI(&desc,"D",0); /* password age */
4446 PACKI(&desc,"D",0); /* password can change */
4447 PACKI(&desc,"D",-1); /* password must change */
4450 fstring mypath;
4451 fstrcpy(mypath,"\\\\");
4452 fstrcat(mypath,get_local_machine_name());
4453 strupper_m(mypath);
4454 PACKS(&desc,"z",mypath); /* computer */
4457 PACKS(&desc,"z",lp_workgroup());/* domain */
4458 PACKS(&desc,"z", vuser ?
4459 vuser->server_info->info3->base.logon_script.string
4460 : ""); /* script path */
4461 PACKI(&desc,"D",0x00000000); /* reserved */
4464 *rdata_len = desc.usedlen;
4465 *rparam_len = 6;
4466 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4467 if (!*rparam) {
4468 return False;
4470 SSVALS(*rparam,0,desc.errcode);
4471 SSVAL(*rparam,2,0);
4472 SSVAL(*rparam,4,desc.neededlen);
4474 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4476 return True;
4479 /****************************************************************************
4480 api_WAccessGetUserPerms
4481 ****************************************************************************/
4483 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4484 char *param, int tpscnt,
4485 char *data, int tdscnt,
4486 int mdrcnt,int mprcnt,
4487 char **rdata,char **rparam,
4488 int *rdata_len,int *rparam_len)
4490 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4491 char *str2 = skip_string(param,tpscnt,str1);
4492 char *user = skip_string(param,tpscnt,str2);
4493 char *resource = skip_string(param,tpscnt,user);
4495 if (!str1 || !str2 || !user || !resource) {
4496 return False;
4499 if (skip_string(param,tpscnt,resource) == NULL) {
4500 return False;
4502 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4504 /* check it's a supported varient */
4505 if (strcmp(str1,"zzh") != 0) {
4506 return False;
4508 if (strcmp(str2,"") != 0) {
4509 return False;
4512 *rparam_len = 6;
4513 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4514 if (!*rparam) {
4515 return False;
4517 SSVALS(*rparam,0,0); /* errorcode */
4518 SSVAL(*rparam,2,0); /* converter word */
4519 SSVAL(*rparam,4,0x7f); /* permission flags */
4521 return True;
4524 /****************************************************************************
4525 api_WPrintJobEnumerate
4526 ****************************************************************************/
4528 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4529 char *param, int tpscnt,
4530 char *data, int tdscnt,
4531 int mdrcnt,int mprcnt,
4532 char **rdata,char **rparam,
4533 int *rdata_len,int *rparam_len)
4535 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4536 char *str2 = skip_string(param,tpscnt,str1);
4537 char *p = skip_string(param,tpscnt,str2);
4538 int uLevel;
4539 fstring sharename;
4540 uint32 jobid;
4541 struct pack_desc desc;
4542 char *tmpdata=NULL;
4544 TALLOC_CTX *mem_ctx = talloc_tos();
4545 WERROR werr;
4546 NTSTATUS status;
4547 struct rpc_pipe_client *cli = NULL;
4548 struct policy_handle handle;
4549 struct spoolss_DevmodeContainer devmode_ctr;
4550 union spoolss_JobInfo info;
4552 if (!str1 || !str2 || !p) {
4553 return False;
4556 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4558 memset((char *)&desc,'\0',sizeof(desc));
4559 memset((char *)&status,'\0',sizeof(status));
4561 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4563 /* check it's a supported varient */
4564 if (strcmp(str1,"WWrLh") != 0) {
4565 return False;
4567 if (!check_printjob_info(&desc,uLevel,str2)) {
4568 return False;
4571 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4572 return False;
4575 ZERO_STRUCT(handle);
4577 status = rpc_connect_spoolss_pipe(conn, &cli);
4578 if (!NT_STATUS_IS_OK(status)) {
4579 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4580 nt_errstr(status)));
4581 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4582 goto out;
4585 ZERO_STRUCT(devmode_ctr);
4587 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4588 sharename,
4589 "RAW",
4590 devmode_ctr,
4591 PRINTER_ACCESS_USE,
4592 &handle,
4593 &werr);
4594 if (!NT_STATUS_IS_OK(status)) {
4595 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4596 goto out;
4598 if (!W_ERROR_IS_OK(werr)) {
4599 desc.errcode = W_ERROR_V(werr);
4600 goto out;
4603 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4604 &handle,
4605 jobid,
4606 2, /* level */
4607 0, /* offered */
4608 &info);
4609 if (!W_ERROR_IS_OK(werr)) {
4610 desc.errcode = W_ERROR_V(werr);
4611 goto out;
4614 if (mdrcnt > 0) {
4615 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4616 if (!*rdata) {
4617 return False;
4619 desc.base = *rdata;
4620 desc.buflen = mdrcnt;
4621 } else {
4623 * Don't return data but need to get correct length
4624 * init_package will return wrong size if buflen=0
4626 desc.buflen = getlen(desc.format);
4627 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4630 if (init_package(&desc,1,0)) {
4631 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4632 *rdata_len = desc.usedlen;
4633 } else {
4634 desc.errcode = NERR_JobNotFound;
4635 *rdata_len = 0;
4637 out:
4638 if (cli && is_valid_policy_hnd(&handle)) {
4639 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4642 *rparam_len = 6;
4643 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4644 if (!*rparam) {
4645 return False;
4647 SSVALS(*rparam,0,desc.errcode);
4648 SSVAL(*rparam,2,0);
4649 SSVAL(*rparam,4,desc.neededlen);
4651 SAFE_FREE(tmpdata);
4653 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4655 return True;
4658 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4659 char *param, int tpscnt,
4660 char *data, int tdscnt,
4661 int mdrcnt,int mprcnt,
4662 char **rdata,char **rparam,
4663 int *rdata_len,int *rparam_len)
4665 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4666 char *str2 = skip_string(param,tpscnt,str1);
4667 char *p = skip_string(param,tpscnt,str2);
4668 char *name = p;
4669 int uLevel;
4670 int i, succnt=0;
4671 struct pack_desc desc;
4673 TALLOC_CTX *mem_ctx = talloc_tos();
4674 WERROR werr;
4675 NTSTATUS status;
4676 struct rpc_pipe_client *cli = NULL;
4677 struct policy_handle handle;
4678 struct spoolss_DevmodeContainer devmode_ctr;
4679 uint32_t count;
4680 union spoolss_JobInfo *info;
4682 if (!str1 || !str2 || !p) {
4683 return False;
4686 memset((char *)&desc,'\0',sizeof(desc));
4688 p = skip_string(param,tpscnt,p);
4689 if (!p) {
4690 return False;
4692 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4694 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4696 /* check it's a supported variant */
4697 if (strcmp(str1,"zWrLeh") != 0) {
4698 return False;
4701 if (uLevel > 2) {
4702 return False; /* defined only for uLevel 0,1,2 */
4705 if (!check_printjob_info(&desc,uLevel,str2)) {
4706 return False;
4709 ZERO_STRUCT(handle);
4711 status = rpc_connect_spoolss_pipe(conn, &cli);
4712 if (!NT_STATUS_IS_OK(status)) {
4713 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4714 nt_errstr(status)));
4715 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4716 goto out;
4719 ZERO_STRUCT(devmode_ctr);
4721 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4722 name,
4723 NULL,
4724 devmode_ctr,
4725 SEC_FLAG_MAXIMUM_ALLOWED,
4726 &handle,
4727 &werr);
4728 if (!NT_STATUS_IS_OK(status)) {
4729 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4730 goto out;
4732 if (!W_ERROR_IS_OK(werr)) {
4733 desc.errcode = W_ERROR_V(werr);
4734 goto out;
4737 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4738 &handle,
4739 0, /* firstjob */
4740 0xff, /* numjobs */
4741 2, /* level */
4742 0, /* offered */
4743 &count,
4744 &info);
4745 if (!W_ERROR_IS_OK(werr)) {
4746 desc.errcode = W_ERROR_V(werr);
4747 goto out;
4750 if (mdrcnt > 0) {
4751 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4752 if (!*rdata) {
4753 return False;
4756 desc.base = *rdata;
4757 desc.buflen = mdrcnt;
4759 if (init_package(&desc,count,0)) {
4760 succnt = 0;
4761 for (i = 0; i < count; i++) {
4762 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4763 if (desc.errcode == NERR_Success) {
4764 succnt = i+1;
4768 out:
4769 if (cli && is_valid_policy_hnd(&handle)) {
4770 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4773 *rdata_len = desc.usedlen;
4775 *rparam_len = 8;
4776 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4777 if (!*rparam) {
4778 return False;
4780 SSVALS(*rparam,0,desc.errcode);
4781 SSVAL(*rparam,2,0);
4782 SSVAL(*rparam,4,succnt);
4783 SSVAL(*rparam,6,count);
4785 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4787 return True;
4790 static int check_printdest_info(struct pack_desc* desc,
4791 int uLevel, char* id)
4793 desc->subformat = NULL;
4794 switch( uLevel ) {
4795 case 0:
4796 desc->format = "B9";
4797 break;
4798 case 1:
4799 desc->format = "B9B21WWzW";
4800 break;
4801 case 2:
4802 desc->format = "z";
4803 break;
4804 case 3:
4805 desc->format = "zzzWWzzzWW";
4806 break;
4807 default:
4808 DEBUG(0,("check_printdest_info: invalid level %d\n",
4809 uLevel));
4810 return False;
4812 if (id == NULL || strcmp(desc->format,id) != 0) {
4813 DEBUG(0,("check_printdest_info: invalid string %s\n",
4814 id ? id : "<NULL>" ));
4815 return False;
4817 return True;
4820 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4821 struct pack_desc* desc)
4823 char buf[100];
4825 strncpy(buf, info2->printername, sizeof(buf)-1);
4826 buf[sizeof(buf)-1] = 0;
4827 strupper_m(buf);
4829 if (uLevel <= 1) {
4830 PACKS(desc,"B9",buf); /* szName */
4831 if (uLevel == 1) {
4832 PACKS(desc,"B21",""); /* szUserName */
4833 PACKI(desc,"W",0); /* uJobId */
4834 PACKI(desc,"W",0); /* fsStatus */
4835 PACKS(desc,"z",""); /* pszStatus */
4836 PACKI(desc,"W",0); /* time */
4840 if (uLevel == 2 || uLevel == 3) {
4841 PACKS(desc,"z",buf); /* pszPrinterName */
4842 if (uLevel == 3) {
4843 PACKS(desc,"z",""); /* pszUserName */
4844 PACKS(desc,"z",""); /* pszLogAddr */
4845 PACKI(desc,"W",0); /* uJobId */
4846 PACKI(desc,"W",0); /* fsStatus */
4847 PACKS(desc,"z",""); /* pszStatus */
4848 PACKS(desc,"z",""); /* pszComment */
4849 PACKS(desc,"z","NULL"); /* pszDrivers */
4850 PACKI(desc,"W",0); /* time */
4851 PACKI(desc,"W",0); /* pad1 */
4856 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4857 char *param, int tpscnt,
4858 char *data, int tdscnt,
4859 int mdrcnt,int mprcnt,
4860 char **rdata,char **rparam,
4861 int *rdata_len,int *rparam_len)
4863 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4864 char *str2 = skip_string(param,tpscnt,str1);
4865 char *p = skip_string(param,tpscnt,str2);
4866 char* PrinterName = p;
4867 int uLevel;
4868 struct pack_desc desc;
4869 char *tmpdata=NULL;
4871 TALLOC_CTX *mem_ctx = talloc_tos();
4872 WERROR werr;
4873 NTSTATUS status;
4874 struct rpc_pipe_client *cli = NULL;
4875 struct policy_handle handle;
4876 struct spoolss_DevmodeContainer devmode_ctr;
4877 union spoolss_PrinterInfo info;
4879 if (!str1 || !str2 || !p) {
4880 return False;
4883 memset((char *)&desc,'\0',sizeof(desc));
4885 p = skip_string(param,tpscnt,p);
4886 if (!p) {
4887 return False;
4889 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4891 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4893 /* check it's a supported varient */
4894 if (strcmp(str1,"zWrLh") != 0) {
4895 return False;
4897 if (!check_printdest_info(&desc,uLevel,str2)) {
4898 return False;
4901 ZERO_STRUCT(handle);
4903 status = rpc_connect_spoolss_pipe(conn, &cli);
4904 if (!NT_STATUS_IS_OK(status)) {
4905 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4906 nt_errstr(status)));
4907 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4908 goto out;
4911 ZERO_STRUCT(devmode_ctr);
4913 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4914 PrinterName,
4915 NULL,
4916 devmode_ctr,
4917 SEC_FLAG_MAXIMUM_ALLOWED,
4918 &handle,
4919 &werr);
4920 if (!NT_STATUS_IS_OK(status)) {
4921 *rdata_len = 0;
4922 desc.errcode = NERR_DestNotFound;
4923 desc.neededlen = 0;
4924 goto out;
4926 if (!W_ERROR_IS_OK(werr)) {
4927 *rdata_len = 0;
4928 desc.errcode = NERR_DestNotFound;
4929 desc.neededlen = 0;
4930 goto out;
4933 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4934 &handle,
4937 &info);
4938 if (!W_ERROR_IS_OK(werr)) {
4939 *rdata_len = 0;
4940 desc.errcode = NERR_DestNotFound;
4941 desc.neededlen = 0;
4942 goto out;
4945 if (mdrcnt > 0) {
4946 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4947 if (!*rdata) {
4948 return False;
4950 desc.base = *rdata;
4951 desc.buflen = mdrcnt;
4952 } else {
4954 * Don't return data but need to get correct length
4955 * init_package will return wrong size if buflen=0
4957 desc.buflen = getlen(desc.format);
4958 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4960 if (init_package(&desc,1,0)) {
4961 fill_printdest_info(&info.info2, uLevel,&desc);
4964 out:
4965 if (cli && is_valid_policy_hnd(&handle)) {
4966 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4969 *rdata_len = desc.usedlen;
4971 *rparam_len = 6;
4972 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4973 if (!*rparam) {
4974 return False;
4976 SSVALS(*rparam,0,desc.errcode);
4977 SSVAL(*rparam,2,0);
4978 SSVAL(*rparam,4,desc.neededlen);
4980 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4981 SAFE_FREE(tmpdata);
4983 return True;
4986 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4987 char *param, int tpscnt,
4988 char *data, int tdscnt,
4989 int mdrcnt,int mprcnt,
4990 char **rdata,char **rparam,
4991 int *rdata_len,int *rparam_len)
4993 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4994 char *str2 = skip_string(param,tpscnt,str1);
4995 char *p = skip_string(param,tpscnt,str2);
4996 int uLevel;
4997 int queuecnt;
4998 int i, n, succnt=0;
4999 struct pack_desc desc;
5001 TALLOC_CTX *mem_ctx = talloc_tos();
5002 WERROR werr;
5003 NTSTATUS status;
5004 struct rpc_pipe_client *cli = NULL;
5005 union spoolss_PrinterInfo *info;
5006 uint32_t count;
5008 if (!str1 || !str2 || !p) {
5009 return False;
5012 memset((char *)&desc,'\0',sizeof(desc));
5014 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5016 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5018 /* check it's a supported varient */
5019 if (strcmp(str1,"WrLeh") != 0) {
5020 return False;
5022 if (!check_printdest_info(&desc,uLevel,str2)) {
5023 return False;
5026 queuecnt = 0;
5028 status = rpc_connect_spoolss_pipe(conn, &cli);
5029 if (!NT_STATUS_IS_OK(status)) {
5030 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5031 nt_errstr(status)));
5032 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5033 goto out;
5036 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5037 PRINTER_ENUM_LOCAL,
5038 cli->srv_name_slash,
5041 &count,
5042 &info);
5043 if (!W_ERROR_IS_OK(werr)) {
5044 desc.errcode = W_ERROR_V(werr);
5045 *rdata_len = 0;
5046 desc.errcode = NERR_DestNotFound;
5047 desc.neededlen = 0;
5048 goto out;
5051 queuecnt = count;
5053 if (mdrcnt > 0) {
5054 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5055 if (!*rdata) {
5056 return False;
5060 desc.base = *rdata;
5061 desc.buflen = mdrcnt;
5062 if (init_package(&desc,queuecnt,0)) {
5063 succnt = 0;
5064 n = 0;
5065 for (i = 0; i < count; i++) {
5066 fill_printdest_info(&info[i].info2, uLevel,&desc);
5067 n++;
5068 if (desc.errcode == NERR_Success) {
5069 succnt = n;
5073 out:
5074 *rdata_len = desc.usedlen;
5076 *rparam_len = 8;
5077 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5078 if (!*rparam) {
5079 return False;
5081 SSVALS(*rparam,0,desc.errcode);
5082 SSVAL(*rparam,2,0);
5083 SSVAL(*rparam,4,succnt);
5084 SSVAL(*rparam,6,queuecnt);
5086 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5088 return True;
5091 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
5092 char *param, int tpscnt,
5093 char *data, int tdscnt,
5094 int mdrcnt,int mprcnt,
5095 char **rdata,char **rparam,
5096 int *rdata_len,int *rparam_len)
5098 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5099 char *str2 = skip_string(param,tpscnt,str1);
5100 char *p = skip_string(param,tpscnt,str2);
5101 int uLevel;
5102 int succnt;
5103 struct pack_desc desc;
5105 if (!str1 || !str2 || !p) {
5106 return False;
5109 memset((char *)&desc,'\0',sizeof(desc));
5111 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5113 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5115 /* check it's a supported varient */
5116 if (strcmp(str1,"WrLeh") != 0) {
5117 return False;
5119 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5120 return False;
5123 if (mdrcnt > 0) {
5124 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5125 if (!*rdata) {
5126 return False;
5129 desc.base = *rdata;
5130 desc.buflen = mdrcnt;
5131 if (init_package(&desc,1,0)) {
5132 PACKS(&desc,"B41","NULL");
5135 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5137 *rdata_len = desc.usedlen;
5139 *rparam_len = 8;
5140 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5141 if (!*rparam) {
5142 return False;
5144 SSVALS(*rparam,0,desc.errcode);
5145 SSVAL(*rparam,2,0);
5146 SSVAL(*rparam,4,succnt);
5147 SSVAL(*rparam,6,1);
5149 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5151 return True;
5154 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
5155 char *param, int tpscnt,
5156 char *data, int tdscnt,
5157 int mdrcnt,int mprcnt,
5158 char **rdata,char **rparam,
5159 int *rdata_len,int *rparam_len)
5161 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5162 char *str2 = skip_string(param,tpscnt,str1);
5163 char *p = skip_string(param,tpscnt,str2);
5164 int uLevel;
5165 int succnt;
5166 struct pack_desc desc;
5168 if (!str1 || !str2 || !p) {
5169 return False;
5171 memset((char *)&desc,'\0',sizeof(desc));
5173 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5175 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5177 /* check it's a supported varient */
5178 if (strcmp(str1,"WrLeh") != 0) {
5179 return False;
5181 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5182 return False;
5185 if (mdrcnt > 0) {
5186 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5187 if (!*rdata) {
5188 return False;
5191 desc.base = *rdata;
5192 desc.buflen = mdrcnt;
5193 desc.format = str2;
5194 if (init_package(&desc,1,0)) {
5195 PACKS(&desc,"B13","lpd");
5198 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5200 *rdata_len = desc.usedlen;
5202 *rparam_len = 8;
5203 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5204 if (!*rparam) {
5205 return False;
5207 SSVALS(*rparam,0,desc.errcode);
5208 SSVAL(*rparam,2,0);
5209 SSVAL(*rparam,4,succnt);
5210 SSVAL(*rparam,6,1);
5212 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5214 return True;
5217 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
5218 char *param, int tpscnt,
5219 char *data, int tdscnt,
5220 int mdrcnt,int mprcnt,
5221 char **rdata,char **rparam,
5222 int *rdata_len,int *rparam_len)
5224 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5225 char *str2 = skip_string(param,tpscnt,str1);
5226 char *p = skip_string(param,tpscnt,str2);
5227 int uLevel;
5228 int succnt;
5229 struct pack_desc desc;
5231 if (!str1 || !str2 || !p) {
5232 return False;
5235 memset((char *)&desc,'\0',sizeof(desc));
5237 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5239 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5241 /* check it's a supported varient */
5242 if (strcmp(str1,"WrLeh") != 0) {
5243 return False;
5245 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5246 return False;
5249 if (mdrcnt > 0) {
5250 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5251 if (!*rdata) {
5252 return False;
5255 memset((char *)&desc,'\0',sizeof(desc));
5256 desc.base = *rdata;
5257 desc.buflen = mdrcnt;
5258 desc.format = str2;
5259 if (init_package(&desc,1,0)) {
5260 PACKS(&desc,"B13","lp0");
5263 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5265 *rdata_len = desc.usedlen;
5267 *rparam_len = 8;
5268 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5269 if (!*rparam) {
5270 return False;
5272 SSVALS(*rparam,0,desc.errcode);
5273 SSVAL(*rparam,2,0);
5274 SSVAL(*rparam,4,succnt);
5275 SSVAL(*rparam,6,1);
5277 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5279 return True;
5282 /****************************************************************************
5283 List open sessions
5284 ****************************************************************************/
5286 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
5287 char *param, int tpscnt,
5288 char *data, int tdscnt,
5289 int mdrcnt,int mprcnt,
5290 char **rdata,char **rparam,
5291 int *rdata_len,int *rparam_len)
5294 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5295 char *str2 = skip_string(param,tpscnt,str1);
5296 char *p = skip_string(param,tpscnt,str2);
5297 int uLevel;
5298 struct pack_desc desc;
5299 struct sessionid *session_list;
5300 int i, num_sessions;
5302 if (!str1 || !str2 || !p) {
5303 return False;
5306 memset((char *)&desc,'\0',sizeof(desc));
5308 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5310 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5311 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5312 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5314 /* check it's a supported varient */
5315 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5316 return False;
5318 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5319 return False;
5322 num_sessions = list_sessions(talloc_tos(), &session_list);
5324 if (mdrcnt > 0) {
5325 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5326 if (!*rdata) {
5327 return False;
5330 memset((char *)&desc,'\0',sizeof(desc));
5331 desc.base = *rdata;
5332 desc.buflen = mdrcnt;
5333 desc.format = str2;
5334 if (!init_package(&desc,num_sessions,0)) {
5335 return False;
5338 for(i=0; i<num_sessions; i++) {
5339 PACKS(&desc, "z", session_list[i].remote_machine);
5340 PACKS(&desc, "z", session_list[i].username);
5341 PACKI(&desc, "W", 1); /* num conns */
5342 PACKI(&desc, "W", 0); /* num opens */
5343 PACKI(&desc, "W", 1); /* num users */
5344 PACKI(&desc, "D", 0); /* session time */
5345 PACKI(&desc, "D", 0); /* idle time */
5346 PACKI(&desc, "D", 0); /* flags */
5347 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5350 *rdata_len = desc.usedlen;
5352 *rparam_len = 8;
5353 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5354 if (!*rparam) {
5355 return False;
5357 SSVALS(*rparam,0,desc.errcode);
5358 SSVAL(*rparam,2,0); /* converter */
5359 SSVAL(*rparam,4,num_sessions); /* count */
5361 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5363 return True;
5367 /****************************************************************************
5368 The buffer was too small.
5369 ****************************************************************************/
5371 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5372 int mdrcnt, int mprcnt,
5373 char **rdata, char **rparam,
5374 int *rdata_len, int *rparam_len)
5376 *rparam_len = MIN(*rparam_len,mprcnt);
5377 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5378 if (!*rparam) {
5379 return False;
5382 *rdata_len = 0;
5384 SSVAL(*rparam,0,NERR_BufTooSmall);
5386 DEBUG(3,("Supplied buffer too small in API command\n"));
5388 return True;
5391 /****************************************************************************
5392 The request is not supported.
5393 ****************************************************************************/
5395 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5396 char *param, int tpscnt,
5397 char *data, int tdscnt,
5398 int mdrcnt, int mprcnt,
5399 char **rdata, char **rparam,
5400 int *rdata_len, int *rparam_len)
5402 *rparam_len = 4;
5403 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5404 if (!*rparam) {
5405 return False;
5408 *rdata_len = 0;
5410 SSVAL(*rparam,0,NERR_notsupported);
5411 SSVAL(*rparam,2,0); /* converter word */
5413 DEBUG(3,("Unsupported API command\n"));
5415 return True;
5418 static const struct {
5419 const char *name;
5420 int id;
5421 bool (*fn)(connection_struct *, uint16,
5422 char *, int,
5423 char *, int,
5424 int,int,char **,char **,int *,int *);
5425 bool auth_user; /* Deny anonymous access? */
5426 } api_commands[] = {
5427 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5428 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5429 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5430 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5431 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5432 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5433 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5434 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5435 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5436 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5437 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5438 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5439 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5440 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5441 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5442 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5443 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5444 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5445 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5446 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5447 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5448 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5449 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5450 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5451 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5452 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5453 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5454 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5455 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5456 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5457 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5458 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5459 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5460 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5461 {NULL, -1, api_Unsupported}
5462 /* The following RAP calls are not implemented by Samba:
5464 RAP_WFileEnum2 - anon not OK
5469 /****************************************************************************
5470 Handle remote api calls.
5471 ****************************************************************************/
5473 void api_reply(connection_struct *conn, uint16 vuid,
5474 struct smb_request *req,
5475 char *data, char *params,
5476 int tdscnt, int tpscnt,
5477 int mdrcnt, int mprcnt)
5479 struct smbd_server_connection *sconn = smbd_server_conn;
5480 int api_command;
5481 char *rdata = NULL;
5482 char *rparam = NULL;
5483 const char *name1 = NULL;
5484 const char *name2 = NULL;
5485 int rdata_len = 0;
5486 int rparam_len = 0;
5487 bool reply=False;
5488 int i;
5490 if (!params) {
5491 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5492 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5493 return;
5496 if (tpscnt < 2) {
5497 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5498 return;
5500 api_command = SVAL(params,0);
5501 /* Is there a string at position params+2 ? */
5502 if (skip_string(params,tpscnt,params+2)) {
5503 name1 = params + 2;
5504 } else {
5505 name1 = "";
5507 name2 = skip_string(params,tpscnt,params+2);
5508 if (!name2) {
5509 name2 = "";
5512 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5513 api_command,
5514 name1,
5515 name2,
5516 tdscnt,tpscnt,mdrcnt,mprcnt));
5518 for (i=0;api_commands[i].name;i++) {
5519 if (api_commands[i].id == api_command && api_commands[i].fn) {
5520 DEBUG(3,("Doing %s\n",api_commands[i].name));
5521 break;
5525 /* Check whether this api call can be done anonymously */
5527 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5528 user_struct *user = get_valid_user_struct(sconn, vuid);
5530 if (!user || user->server_info->guest) {
5531 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5532 return;
5536 rdata = (char *)SMB_MALLOC(1024);
5537 if (rdata) {
5538 memset(rdata,'\0',1024);
5541 rparam = (char *)SMB_MALLOC(1024);
5542 if (rparam) {
5543 memset(rparam,'\0',1024);
5546 if(!rdata || !rparam) {
5547 DEBUG(0,("api_reply: malloc fail !\n"));
5548 SAFE_FREE(rdata);
5549 SAFE_FREE(rparam);
5550 reply_nterror(req, NT_STATUS_NO_MEMORY);
5551 return;
5554 reply = api_commands[i].fn(conn,
5555 vuid,
5556 params,tpscnt, /* params + length */
5557 data,tdscnt, /* data + length */
5558 mdrcnt,mprcnt,
5559 &rdata,&rparam,&rdata_len,&rparam_len);
5562 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5563 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5564 &rdata,&rparam,&rdata_len,&rparam_len);
5567 /* if we get False back then it's actually unsupported */
5568 if (!reply) {
5569 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5570 &rdata,&rparam,&rdata_len,&rparam_len);
5573 /* If api_Unsupported returns false we can't return anything. */
5574 if (reply) {
5575 send_trans_reply(conn, req, rparam, rparam_len,
5576 rdata, rdata_len, False);
5579 SAFE_FREE(rdata);
5580 SAFE_FREE(rparam);
5581 return;