s3: Call printer_list_parent_init in the parent
[Samba/gbeck.git] / source3 / smbd / lanman.c
blob2b01e89d6cbd23243acfbbec7f55516a5bb26f08
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"
40 #include "rpc_client/init_lsa.h"
41 #include "rpc_server/rpc_ncacn_np.h"
43 #ifdef CHECK_TYPES
44 #undef CHECK_TYPES
45 #endif
46 #define CHECK_TYPES 0
48 #define NERR_Success 0
49 #define NERR_badpass 86
50 #define NERR_notsupported 50
52 #define NERR_BASE (2100)
53 #define NERR_BufTooSmall (NERR_BASE+23)
54 #define NERR_JobNotFound (NERR_BASE+51)
55 #define NERR_DestNotFound (NERR_BASE+52)
57 #define ACCESS_READ 0x01
58 #define ACCESS_WRITE 0x02
59 #define ACCESS_CREATE 0x04
61 #define SHPWLEN 8 /* share password length */
63 /* Limit size of ipc replies */
65 static char *smb_realloc_limit(void *ptr, size_t size)
67 char *val;
69 size = MAX((size),4*1024);
70 val = (char *)SMB_REALLOC(ptr,size);
71 if (val) {
72 memset(val,'\0',size);
74 return val;
77 static bool api_Unsupported(struct smbd_server_connection *sconn,
78 connection_struct *conn, uint16 vuid,
79 char *param, int tpscnt,
80 char *data, int tdscnt,
81 int mdrcnt, int mprcnt,
82 char **rdata, char **rparam,
83 int *rdata_len, int *rparam_len);
85 static bool api_TooSmall(struct smbd_server_connection *sconn,
86 connection_struct *conn, uint16 vuid, char *param, char *data,
87 int mdrcnt, int mprcnt,
88 char **rdata, char **rparam,
89 int *rdata_len, int *rparam_len);
92 static int CopyExpanded(connection_struct *conn,
93 int snum, char **dst, char *src, int *p_space_remaining)
95 TALLOC_CTX *ctx = talloc_tos();
96 char *buf = NULL;
97 int l;
99 if (!src || !dst || !p_space_remaining || !(*dst) ||
100 *p_space_remaining <= 0) {
101 return 0;
104 buf = talloc_strdup(ctx, src);
105 if (!buf) {
106 *p_space_remaining = 0;
107 return 0;
109 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
110 if (!buf) {
111 *p_space_remaining = 0;
112 return 0;
114 buf = talloc_sub_advanced(ctx,
115 lp_servicename(SNUM(conn)),
116 conn->server_info->unix_name,
117 conn->connectpath,
118 conn->server_info->utok.gid,
119 conn->server_info->sanitized_username,
120 conn->server_info->info3->base.domain.string,
121 buf);
122 if (!buf) {
123 *p_space_remaining = 0;
124 return 0;
126 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
127 if (l == -1) {
128 return 0;
130 (*dst) += l;
131 (*p_space_remaining) -= l;
132 return l;
135 static int CopyAndAdvance(char **dst, char *src, int *n)
137 int l;
138 if (!src || !dst || !n || !(*dst)) {
139 return 0;
141 l = push_ascii(*dst,src,*n, STR_TERMINATE);
142 if (l == -1) {
143 return 0;
145 (*dst) += l;
146 (*n) -= l;
147 return l;
150 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
152 TALLOC_CTX *ctx = talloc_tos();
153 char *buf = NULL;
154 if (!s) {
155 return 0;
157 buf = talloc_strdup(ctx,s);
158 if (!buf) {
159 return 0;
161 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
162 if (!buf) {
163 return 0;
165 buf = talloc_sub_advanced(ctx,
166 lp_servicename(SNUM(conn)),
167 conn->server_info->unix_name,
168 conn->connectpath,
169 conn->server_info->utok.gid,
170 conn->server_info->sanitized_username,
171 conn->server_info->info3->base.domain.string,
172 buf);
173 if (!buf) {
174 return 0;
176 return strlen(buf) + 1;
179 /*******************************************************************
180 Check a API string for validity when we only need to check the prefix.
181 ******************************************************************/
183 static bool prefix_ok(const char *str, const char *prefix)
185 return(strncmp(str,prefix,strlen(prefix)) == 0);
188 struct pack_desc {
189 const char *format; /* formatstring for structure */
190 const char *subformat; /* subformat for structure */
191 char *base; /* baseaddress of buffer */
192 int buflen; /* remaining size for fixed part; on init: length of base */
193 int subcount; /* count of substructures */
194 char *structbuf; /* pointer into buffer for remaining fixed part */
195 int stringlen; /* remaining size for variable part */
196 char *stringbuf; /* pointer into buffer for remaining variable part */
197 int neededlen; /* total needed size */
198 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
199 const char *curpos; /* current position; pointer into format or subformat */
200 int errcode;
203 static int get_counter(const char **p)
205 int i, n;
206 if (!p || !(*p)) {
207 return 1;
209 if (!isdigit((int)**p)) {
210 return 1;
212 for (n = 0;;) {
213 i = **p;
214 if (isdigit(i)) {
215 n = 10 * n + (i - '0');
216 } else {
217 return n;
219 (*p)++;
223 static int getlen(const char *p)
225 int n = 0;
226 if (!p) {
227 return 0;
230 while (*p) {
231 switch( *p++ ) {
232 case 'W': /* word (2 byte) */
233 n += 2;
234 break;
235 case 'K': /* status word? (2 byte) */
236 n += 2;
237 break;
238 case 'N': /* count of substructures (word) at end */
239 n += 2;
240 break;
241 case 'D': /* double word (4 byte) */
242 case 'z': /* offset to zero terminated string (4 byte) */
243 case 'l': /* offset to user data (4 byte) */
244 n += 4;
245 break;
246 case 'b': /* offset to data (with counter) (4 byte) */
247 n += 4;
248 get_counter(&p);
249 break;
250 case 'B': /* byte (with optional counter) */
251 n += get_counter(&p);
252 break;
255 return n;
258 static bool init_package(struct pack_desc *p, int count, int subcount)
260 int n = p->buflen;
261 int i;
263 if (!p->format || !p->base) {
264 return False;
267 i = count * getlen(p->format);
268 if (p->subformat) {
269 i += subcount * getlen(p->subformat);
271 p->structbuf = p->base;
272 p->neededlen = 0;
273 p->usedlen = 0;
274 p->subcount = 0;
275 p->curpos = p->format;
276 if (i > n) {
277 p->neededlen = i;
278 i = n = 0;
279 #if 0
281 * This is the old error code we used. Aparently
282 * WinNT/2k systems return ERRbuftoosmall (2123) and
283 * OS/2 needs this. I'm leaving this here so we can revert
284 * if needed. JRA.
286 p->errcode = ERRmoredata;
287 #else
288 p->errcode = ERRbuftoosmall;
289 #endif
290 } else {
291 p->errcode = NERR_Success;
293 p->buflen = i;
294 n -= i;
295 p->stringbuf = p->base + i;
296 p->stringlen = n;
297 return (p->errcode == NERR_Success);
300 static int package(struct pack_desc *p, ...)
302 va_list args;
303 int needed=0, stringneeded;
304 const char *str=NULL;
305 int is_string=0, stringused;
306 int32 temp;
308 va_start(args,p);
310 if (!*p->curpos) {
311 if (!p->subcount) {
312 p->curpos = p->format;
313 } else {
314 p->curpos = p->subformat;
315 p->subcount--;
318 #if CHECK_TYPES
319 str = va_arg(args,char*);
320 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
321 #endif
322 stringneeded = -1;
324 if (!p->curpos) {
325 va_end(args);
326 return 0;
329 switch( *p->curpos++ ) {
330 case 'W': /* word (2 byte) */
331 needed = 2;
332 temp = va_arg(args,int);
333 if (p->buflen >= needed) {
334 SSVAL(p->structbuf,0,temp);
336 break;
337 case 'K': /* status word? (2 byte) */
338 needed = 2;
339 temp = va_arg(args,int);
340 if (p->buflen >= needed) {
341 SSVAL(p->structbuf,0,temp);
343 break;
344 case 'N': /* count of substructures (word) at end */
345 needed = 2;
346 p->subcount = va_arg(args,int);
347 if (p->buflen >= needed) {
348 SSVAL(p->structbuf,0,p->subcount);
350 break;
351 case 'D': /* double word (4 byte) */
352 needed = 4;
353 temp = va_arg(args,int);
354 if (p->buflen >= needed) {
355 SIVAL(p->structbuf,0,temp);
357 break;
358 case 'B': /* byte (with optional counter) */
359 needed = get_counter(&p->curpos);
361 char *s = va_arg(args,char*);
362 if (p->buflen >= needed) {
363 StrnCpy(p->structbuf,s?s:"",needed-1);
366 break;
367 case 'z': /* offset to zero terminated string (4 byte) */
368 str = va_arg(args,char*);
369 stringneeded = (str ? strlen(str)+1 : 0);
370 is_string = 1;
371 break;
372 case 'l': /* offset to user data (4 byte) */
373 str = va_arg(args,char*);
374 stringneeded = va_arg(args,int);
375 is_string = 0;
376 break;
377 case 'b': /* offset to data (with counter) (4 byte) */
378 str = va_arg(args,char*);
379 stringneeded = get_counter(&p->curpos);
380 is_string = 0;
381 break;
384 va_end(args);
385 if (stringneeded >= 0) {
386 needed = 4;
387 if (p->buflen >= needed) {
388 stringused = stringneeded;
389 if (stringused > p->stringlen) {
390 stringused = (is_string ? p->stringlen : 0);
391 if (p->errcode == NERR_Success) {
392 p->errcode = ERRmoredata;
395 if (!stringused) {
396 SIVAL(p->structbuf,0,0);
397 } else {
398 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
399 memcpy(p->stringbuf,str?str:"",stringused);
400 if (is_string) {
401 p->stringbuf[stringused-1] = '\0';
403 p->stringbuf += stringused;
404 p->stringlen -= stringused;
405 p->usedlen += stringused;
408 p->neededlen += stringneeded;
411 p->neededlen += needed;
412 if (p->buflen >= needed) {
413 p->structbuf += needed;
414 p->buflen -= needed;
415 p->usedlen += needed;
416 } else {
417 if (p->errcode == NERR_Success) {
418 p->errcode = ERRmoredata;
421 return 1;
424 #if CHECK_TYPES
425 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
426 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
427 #else
428 #define PACK(desc,t,v) package(desc,v)
429 #define PACKl(desc,t,v,l) package(desc,v,l)
430 #endif
432 static void PACKI(struct pack_desc* desc, const char *t,int v)
434 PACK(desc,t,v);
437 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
439 PACK(desc,t,v);
442 /****************************************************************************
443 Get a print queue.
444 ****************************************************************************/
446 static void PackDriverData(struct pack_desc* desc)
448 char drivdata[4+4+32];
449 SIVAL(drivdata,0,sizeof drivdata); /* cb */
450 SIVAL(drivdata,4,1000); /* lVersion */
451 memset(drivdata+8,0,32); /* szDeviceName */
452 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
453 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
456 static int check_printq_info(struct pack_desc* desc,
457 unsigned int uLevel, char *id1, char *id2)
459 desc->subformat = NULL;
460 switch( uLevel ) {
461 case 0:
462 desc->format = "B13";
463 break;
464 case 1:
465 desc->format = "B13BWWWzzzzzWW";
466 break;
467 case 2:
468 desc->format = "B13BWWWzzzzzWN";
469 desc->subformat = "WB21BB16B10zWWzDDz";
470 break;
471 case 3:
472 desc->format = "zWWWWzzzzWWzzl";
473 break;
474 case 4:
475 desc->format = "zWWWWzzzzWNzzl";
476 desc->subformat = "WWzWWDDzz";
477 break;
478 case 5:
479 desc->format = "z";
480 break;
481 case 51:
482 desc->format = "K";
483 break;
484 case 52:
485 desc->format = "WzzzzzzzzN";
486 desc->subformat = "z";
487 break;
488 default:
489 DEBUG(0,("check_printq_info: invalid level %d\n",
490 uLevel ));
491 return False;
493 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
494 DEBUG(0,("check_printq_info: invalid format %s\n",
495 id1 ? id1 : "<NULL>" ));
496 return False;
498 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
499 DEBUG(0,("check_printq_info: invalid subformat %s\n",
500 id2 ? id2 : "<NULL>" ));
501 return False;
503 return True;
507 #define RAP_JOB_STATUS_QUEUED 0
508 #define RAP_JOB_STATUS_PAUSED 1
509 #define RAP_JOB_STATUS_SPOOLING 2
510 #define RAP_JOB_STATUS_PRINTING 3
511 #define RAP_JOB_STATUS_PRINTED 4
513 #define RAP_QUEUE_STATUS_PAUSED 1
514 #define RAP_QUEUE_STATUS_ERROR 2
516 /* turn a print job status into a on the wire status
518 static int printj_spoolss_status(int v)
520 if (v == JOB_STATUS_QUEUED)
521 return RAP_JOB_STATUS_QUEUED;
522 if (v & JOB_STATUS_PAUSED)
523 return RAP_JOB_STATUS_PAUSED;
524 if (v & JOB_STATUS_SPOOLING)
525 return RAP_JOB_STATUS_SPOOLING;
526 if (v & JOB_STATUS_PRINTING)
527 return RAP_JOB_STATUS_PRINTING;
528 return 0;
531 /* turn a print queue status into a on the wire status
533 static int printq_spoolss_status(int v)
535 if (v == PRINTER_STATUS_OK)
536 return 0;
537 if (v & PRINTER_STATUS_PAUSED)
538 return RAP_QUEUE_STATUS_PAUSED;
539 return RAP_QUEUE_STATUS_ERROR;
542 static void fill_spoolss_printjob_info(int uLevel,
543 struct pack_desc *desc,
544 struct spoolss_JobInfo2 *info2,
545 int n)
547 time_t t = spoolss_Time_to_time_t(&info2->submitted);
549 /* the client expects localtime */
550 t -= get_time_zone(t);
552 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
553 if (uLevel == 1) {
554 PACKS(desc,"B21", info2->user_name); /* szUserName */
555 PACKS(desc,"B",""); /* pad */
556 PACKS(desc,"B16",""); /* szNotifyName */
557 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
558 PACKS(desc,"z",""); /* pszParms */
559 PACKI(desc,"W",n+1); /* uPosition */
560 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
561 PACKS(desc,"z",""); /* pszStatus */
562 PACKI(desc,"D", t); /* ulSubmitted */
563 PACKI(desc,"D", info2->size); /* ulSize */
564 PACKS(desc,"z", info2->document_name); /* pszComment */
566 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
567 PACKI(desc,"W", info2->priority); /* uPriority */
568 PACKS(desc,"z", info2->user_name); /* pszUserName */
569 PACKI(desc,"W",n+1); /* uPosition */
570 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
571 PACKI(desc,"D",t); /* ulSubmitted */
572 PACKI(desc,"D", info2->size); /* ulSize */
573 PACKS(desc,"z","Samba"); /* pszComment */
574 PACKS(desc,"z", info2->document_name); /* pszDocument */
575 if (uLevel == 3) {
576 PACKS(desc,"z",""); /* pszNotifyName */
577 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
578 PACKS(desc,"z",""); /* pszParms */
579 PACKS(desc,"z",""); /* pszStatus */
580 PACKS(desc,"z", info2->printer_name); /* pszQueue */
581 PACKS(desc,"z","lpd"); /* pszQProcName */
582 PACKS(desc,"z",""); /* pszQProcParms */
583 PACKS(desc,"z","NULL"); /* pszDriverName */
584 PackDriverData(desc); /* pDriverData */
585 PACKS(desc,"z",""); /* pszPrinterName */
586 } else if (uLevel == 4) { /* OS2 */
587 PACKS(desc,"z",""); /* pszSpoolFileName */
588 PACKS(desc,"z",""); /* pszPortName */
589 PACKS(desc,"z",""); /* pszStatus */
590 PACKI(desc,"D",0); /* ulPagesSpooled */
591 PACKI(desc,"D",0); /* ulPagesSent */
592 PACKI(desc,"D",0); /* ulPagesPrinted */
593 PACKI(desc,"D",0); /* ulTimePrinted */
594 PACKI(desc,"D",0); /* ulExtendJobStatus */
595 PACKI(desc,"D",0); /* ulStartPage */
596 PACKI(desc,"D",0); /* ulEndPage */
601 /********************************************************************
602 Respond to the DosPrintQInfo command with a level of 52
603 This is used to get printer driver information for Win9x clients
604 ********************************************************************/
605 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
606 struct pack_desc* desc, int count,
607 const char *printer_name)
609 int i;
610 fstring location;
611 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
612 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
613 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
615 PACKI(desc, "W", 0x0400); /* don't know */
616 PACKS(desc, "z", driver->driver_name); /* long printer name */
617 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
618 PACKS(desc, "z", driver->data_file); /* Datafile name */
619 PACKS(desc, "z", driver->monitor_name); /* language monitor */
621 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
622 standard_sub_basic( "", "", location, sizeof(location)-1 );
623 PACKS(desc,"z", location); /* share to retrieve files */
625 PACKS(desc,"z", driver->default_datatype); /* default data type */
626 PACKS(desc,"z", driver->help_file); /* helpfile name */
627 PACKS(desc,"z", driver->driver_path); /* driver name */
629 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
630 DEBUG(3,("Driver: %s:\n",driver->driver_path));
631 DEBUG(3,("Data File: %s:\n",driver->data_file));
632 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
633 DEBUG(3,("Driver Location: %s:\n",location));
634 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
635 DEBUG(3,("Help File: %s:\n",driver->help_file));
636 PACKI(desc,"N",count); /* number of files to copy */
638 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
640 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
641 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
642 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
645 /* sanity check */
646 if ( i != count )
647 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
648 count, i));
650 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
652 desc->errcode=NERR_Success;
656 static const char *strip_unc(const char *unc)
658 char *p;
660 if (unc == NULL) {
661 return NULL;
664 if ((p = strrchr(unc, '\\')) != NULL) {
665 return p+1;
668 return unc;
671 static void fill_printq_info(int uLevel,
672 struct pack_desc* desc,
673 int count,
674 union spoolss_JobInfo *job_info,
675 struct spoolss_DriverInfo3 *driver_info,
676 struct spoolss_PrinterInfo2 *printer_info)
678 switch (uLevel) {
679 case 0:
680 case 1:
681 case 2:
682 PACKS(desc,"B13", strip_unc(printer_info->printername));
683 break;
684 case 3:
685 case 4:
686 case 5:
687 PACKS(desc,"z", strip_unc(printer_info->printername));
688 break;
689 case 51:
690 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
691 break;
694 if (uLevel == 1 || uLevel == 2) {
695 PACKS(desc,"B",""); /* alignment */
696 PACKI(desc,"W",5); /* priority */
697 PACKI(desc,"W",0); /* start time */
698 PACKI(desc,"W",0); /* until time */
699 PACKS(desc,"z",""); /* pSepFile */
700 PACKS(desc,"z","lpd"); /* pPrProc */
701 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
702 PACKS(desc,"z",""); /* pParms */
703 if (printer_info->printername == NULL) {
704 PACKS(desc,"z","UNKNOWN PRINTER");
705 PACKI(desc,"W",LPSTAT_ERROR);
706 } else {
707 PACKS(desc,"z", printer_info->comment);
708 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
710 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
713 if (uLevel == 3 || uLevel == 4) {
714 PACKI(desc,"W",5); /* uPriority */
715 PACKI(desc,"W",0); /* uStarttime */
716 PACKI(desc,"W",0); /* uUntiltime */
717 PACKI(desc,"W",5); /* pad1 */
718 PACKS(desc,"z",""); /* pszSepFile */
719 PACKS(desc,"z","WinPrint"); /* pszPrProc */
720 PACKS(desc,"z",NULL); /* pszParms */
721 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
722 /* "don't ask" that it's done this way to fix corrupted
723 Win9X/ME printer comments. */
724 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
725 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
726 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
727 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
728 PackDriverData(desc); /* pDriverData */
731 if (uLevel == 2 || uLevel == 4) {
732 int i;
733 for (i = 0; i < count; i++) {
734 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
738 if (uLevel==52)
739 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
742 /* This function returns the number of files for a given driver */
743 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
745 int result = 0;
747 /* count the number of files */
748 while (driver->dependent_files && *driver->dependent_files[result])
749 result++;
751 return result;
754 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
755 connection_struct *conn, uint16 vuid,
756 char *param, int tpscnt,
757 char *data, int tdscnt,
758 int mdrcnt,int mprcnt,
759 char **rdata,char **rparam,
760 int *rdata_len,int *rparam_len)
762 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
763 char *str2 = skip_string(param,tpscnt,str1);
764 char *p = skip_string(param,tpscnt,str2);
765 char *QueueName = p;
766 unsigned int uLevel;
767 uint32_t count = 0;
768 char *str3;
769 struct pack_desc desc;
770 char* tmpdata=NULL;
772 WERROR werr = WERR_OK;
773 TALLOC_CTX *mem_ctx = talloc_tos();
774 NTSTATUS status;
775 struct rpc_pipe_client *cli = NULL;
776 struct policy_handle handle;
777 struct spoolss_DevmodeContainer devmode_ctr;
778 union spoolss_DriverInfo driver_info;
779 union spoolss_JobInfo *job_info = NULL;
780 union spoolss_PrinterInfo printer_info;
782 if (!str1 || !str2 || !p) {
783 return False;
785 memset((char *)&desc,'\0',sizeof(desc));
787 p = skip_string(param,tpscnt,p);
788 if (!p) {
789 return False;
791 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
792 str3 = get_safe_str_ptr(param,tpscnt,p,4);
793 /* str3 may be null here and is checked in check_printq_info(). */
795 /* remove any trailing username */
796 if ((p = strchr_m(QueueName,'%')))
797 *p = 0;
799 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
801 /* check it's a supported varient */
802 if (!prefix_ok(str1,"zWrLh"))
803 return False;
804 if (!check_printq_info(&desc,uLevel,str2,str3)) {
806 * Patch from Scott Moomaw <scott@bridgewater.edu>
807 * to return the 'invalid info level' error if an
808 * unknown level was requested.
810 *rdata_len = 0;
811 *rparam_len = 6;
812 *rparam = smb_realloc_limit(*rparam,*rparam_len);
813 if (!*rparam) {
814 return False;
816 SSVALS(*rparam,0,ERRunknownlevel);
817 SSVAL(*rparam,2,0);
818 SSVAL(*rparam,4,0);
819 return(True);
822 ZERO_STRUCT(handle);
824 if (QueueName == NULL || (strlen(QueueName) < 1)) {
825 desc.errcode = W_ERROR_V(WERR_INVALID_PARAM);
826 goto out;
829 status = rpc_pipe_open_interface(conn,
830 &ndr_table_spoolss.syntax_id,
831 conn->server_info,
832 &conn->sconn->client_id,
833 conn->sconn->msg_ctx,
834 &cli);
835 if (!NT_STATUS_IS_OK(status)) {
836 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
837 nt_errstr(status)));
838 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
839 goto out;
842 ZERO_STRUCT(devmode_ctr);
844 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
845 QueueName,
846 "RAW",
847 devmode_ctr,
848 PRINTER_ACCESS_USE,
849 &handle,
850 &werr);
851 if (!NT_STATUS_IS_OK(status)) {
852 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
853 goto out;
855 if (!W_ERROR_IS_OK(werr)) {
856 desc.errcode = W_ERROR_V(werr);
857 goto out;
860 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
861 &handle,
864 &printer_info);
865 if (!W_ERROR_IS_OK(werr)) {
866 desc.errcode = W_ERROR_V(werr);
867 goto out;
870 if (uLevel==52) {
871 uint32_t server_major_version;
872 uint32_t server_minor_version;
874 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
875 &handle,
876 "Windows 4.0",
877 3, /* level */
879 0, /* version */
881 &driver_info,
882 &server_major_version,
883 &server_minor_version);
884 if (!W_ERROR_IS_OK(werr)) {
885 desc.errcode = W_ERROR_V(werr);
886 goto out;
889 count = get_printerdrivernumber(&driver_info.info3);
890 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
891 } else {
892 uint32_t num_jobs;
893 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
894 &handle,
895 0, /* firstjob */
896 0xff, /* numjobs */
897 2, /* level */
898 0, /* offered */
899 &num_jobs,
900 &job_info);
901 if (!W_ERROR_IS_OK(werr)) {
902 desc.errcode = W_ERROR_V(werr);
903 goto out;
906 count = num_jobs;
909 if (mdrcnt > 0) {
910 *rdata = smb_realloc_limit(*rdata,mdrcnt);
911 if (!*rdata) {
912 return False;
914 desc.base = *rdata;
915 desc.buflen = mdrcnt;
916 } else {
918 * Don't return data but need to get correct length
919 * init_package will return wrong size if buflen=0
921 desc.buflen = getlen(desc.format);
922 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
925 if (init_package(&desc,1,count)) {
926 desc.subcount = count;
927 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
930 *rdata_len = desc.usedlen;
933 * We must set the return code to ERRbuftoosmall
934 * in order to support lanman style printing with Win NT/2k
935 * clients --jerry
937 if (!mdrcnt && lp_disable_spoolss())
938 desc.errcode = ERRbuftoosmall;
940 out:
941 if (cli && is_valid_policy_hnd(&handle)) {
942 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
945 *rdata_len = desc.usedlen;
946 *rparam_len = 6;
947 *rparam = smb_realloc_limit(*rparam,*rparam_len);
948 if (!*rparam) {
949 SAFE_FREE(tmpdata);
950 return False;
952 SSVALS(*rparam,0,desc.errcode);
953 SSVAL(*rparam,2,0);
954 SSVAL(*rparam,4,desc.neededlen);
956 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
958 SAFE_FREE(tmpdata);
960 return(True);
963 /****************************************************************************
964 View list of all print jobs on all queues.
965 ****************************************************************************/
967 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
968 connection_struct *conn, uint16 vuid,
969 char *param, int tpscnt,
970 char *data, int tdscnt,
971 int mdrcnt, int mprcnt,
972 char **rdata, char** rparam,
973 int *rdata_len, int *rparam_len)
975 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
976 char *output_format1 = skip_string(param,tpscnt,param_format);
977 char *p = skip_string(param,tpscnt,output_format1);
978 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
979 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
980 int i;
981 struct pack_desc desc;
982 int *subcntarr = NULL;
983 int queuecnt = 0, subcnt = 0, succnt = 0;
985 WERROR werr = WERR_OK;
986 TALLOC_CTX *mem_ctx = talloc_tos();
987 NTSTATUS status;
988 struct rpc_pipe_client *cli = NULL;
989 struct spoolss_DevmodeContainer devmode_ctr;
990 uint32_t num_printers;
991 union spoolss_PrinterInfo *printer_info;
992 union spoolss_DriverInfo *driver_info;
993 union spoolss_JobInfo **job_info;
995 if (!param_format || !output_format1 || !p) {
996 return False;
999 memset((char *)&desc,'\0',sizeof(desc));
1001 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
1003 if (!prefix_ok(param_format,"WrLeh")) {
1004 return False;
1006 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1008 * Patch from Scott Moomaw <scott@bridgewater.edu>
1009 * to return the 'invalid info level' error if an
1010 * unknown level was requested.
1012 *rdata_len = 0;
1013 *rparam_len = 6;
1014 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1015 if (!*rparam) {
1016 return False;
1018 SSVALS(*rparam,0,ERRunknownlevel);
1019 SSVAL(*rparam,2,0);
1020 SSVAL(*rparam,4,0);
1021 return(True);
1024 status = rpc_pipe_open_interface(conn,
1025 &ndr_table_spoolss.syntax_id,
1026 conn->server_info,
1027 &conn->sconn->client_id,
1028 conn->sconn->msg_ctx,
1029 &cli);
1030 if (!NT_STATUS_IS_OK(status)) {
1031 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1032 nt_errstr(status)));
1033 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1034 goto out;
1037 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1038 PRINTER_ENUM_LOCAL,
1039 cli->srv_name_slash,
1042 &num_printers,
1043 &printer_info);
1044 if (!W_ERROR_IS_OK(werr)) {
1045 desc.errcode = W_ERROR_V(werr);
1046 goto out;
1049 queuecnt = num_printers;
1051 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1052 if (job_info == NULL) {
1053 goto err;
1056 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1057 if (driver_info == NULL) {
1058 goto err;
1061 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1062 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1063 goto err;
1066 if (mdrcnt > 0) {
1067 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1068 if (!*rdata) {
1069 goto err;
1072 desc.base = *rdata;
1073 desc.buflen = mdrcnt;
1075 subcnt = 0;
1076 for (i = 0; i < num_printers; i++) {
1078 uint32_t num_jobs;
1079 struct policy_handle handle;
1080 const char *printername;
1082 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1083 if (printername == NULL) {
1084 goto err;
1087 ZERO_STRUCT(handle);
1088 ZERO_STRUCT(devmode_ctr);
1090 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1091 printername,
1092 "RAW",
1093 devmode_ctr,
1094 PRINTER_ACCESS_USE,
1095 &handle,
1096 &werr);
1097 if (!NT_STATUS_IS_OK(status)) {
1098 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1099 goto out;
1101 if (!W_ERROR_IS_OK(werr)) {
1102 desc.errcode = W_ERROR_V(werr);
1103 goto out;
1106 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1107 &handle,
1108 0, /* firstjob */
1109 0xff, /* numjobs */
1110 2, /* level */
1111 0, /* offered */
1112 &num_jobs,
1113 &job_info[i]);
1114 if (!W_ERROR_IS_OK(werr)) {
1115 desc.errcode = W_ERROR_V(werr);
1116 goto out;
1119 if (uLevel==52) {
1120 uint32_t server_major_version;
1121 uint32_t server_minor_version;
1123 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1124 &handle,
1125 "Windows 4.0",
1126 3, /* level */
1128 0, /* version */
1130 &driver_info[i],
1131 &server_major_version,
1132 &server_minor_version);
1133 if (!W_ERROR_IS_OK(werr)) {
1134 desc.errcode = W_ERROR_V(werr);
1135 goto out;
1139 subcntarr[i] = num_jobs;
1140 subcnt += subcntarr[i];
1142 if (cli && is_valid_policy_hnd(&handle)) {
1143 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1147 if (init_package(&desc,queuecnt,subcnt)) {
1148 for (i = 0; i < num_printers; i++) {
1149 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1150 if (desc.errcode == NERR_Success) {
1151 succnt = i;
1156 SAFE_FREE(subcntarr);
1157 out:
1158 *rdata_len = desc.usedlen;
1159 *rparam_len = 8;
1160 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1161 if (!*rparam) {
1162 goto err;
1164 SSVALS(*rparam,0,desc.errcode);
1165 SSVAL(*rparam,2,0);
1166 SSVAL(*rparam,4,succnt);
1167 SSVAL(*rparam,6,queuecnt);
1169 return True;
1171 err:
1173 SAFE_FREE(subcntarr);
1175 return False;
1178 /****************************************************************************
1179 Get info level for a server list query.
1180 ****************************************************************************/
1182 static bool check_server_info(int uLevel, char* id)
1184 switch( uLevel ) {
1185 case 0:
1186 if (strcmp(id,"B16") != 0) {
1187 return False;
1189 break;
1190 case 1:
1191 if (strcmp(id,"B16BBDz") != 0) {
1192 return False;
1194 break;
1195 default:
1196 return False;
1198 return True;
1201 struct srv_info_struct {
1202 fstring name;
1203 uint32 type;
1204 fstring comment;
1205 fstring domain;
1206 bool server_added;
1209 /*******************************************************************
1210 Get server info lists from the files saved by nmbd. Return the
1211 number of entries.
1212 ******************************************************************/
1214 static int get_server_info(uint32 servertype,
1215 struct srv_info_struct **servers,
1216 const char *domain)
1218 int count=0;
1219 int alloced=0;
1220 char **lines;
1221 bool local_list_only;
1222 int i;
1224 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1225 if (!lines) {
1226 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1227 return 0;
1230 /* request for everything is code for request all servers */
1231 if (servertype == SV_TYPE_ALL) {
1232 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1235 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1237 DEBUG(4,("Servertype search: %8x\n",servertype));
1239 for (i=0;lines[i];i++) {
1240 fstring stype;
1241 struct srv_info_struct *s;
1242 const char *ptr = lines[i];
1243 bool ok = True;
1244 TALLOC_CTX *frame = NULL;
1245 char *p;
1247 if (!*ptr) {
1248 continue;
1251 if (count == alloced) {
1252 alloced += 10;
1253 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1254 if (!*servers) {
1255 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1256 TALLOC_FREE(lines);
1257 return 0;
1259 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1261 s = &(*servers)[count];
1263 frame = talloc_stackframe();
1264 s->name[0] = '\0';
1265 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1266 TALLOC_FREE(frame);
1267 continue;
1269 fstrcpy(s->name, p);
1271 stype[0] = '\0';
1272 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1273 TALLOC_FREE(frame);
1274 continue;
1276 fstrcpy(stype, p);
1278 s->comment[0] = '\0';
1279 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1280 TALLOC_FREE(frame);
1281 continue;
1283 fstrcpy(s->comment, p);
1284 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1286 s->domain[0] = '\0';
1287 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1288 /* this allows us to cope with an old nmbd */
1289 fstrcpy(s->domain,lp_workgroup());
1290 } else {
1291 fstrcpy(s->domain, p);
1293 TALLOC_FREE(frame);
1295 if (sscanf(stype,"%X",&s->type) != 1) {
1296 DEBUG(4,("r:host file "));
1297 ok = False;
1300 /* Filter the servers/domains we return based on what was asked for. */
1302 /* Check to see if we are being asked for a local list only. */
1303 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1304 DEBUG(4,("r: local list only"));
1305 ok = False;
1308 /* doesn't match up: don't want it */
1309 if (!(servertype & s->type)) {
1310 DEBUG(4,("r:serv type "));
1311 ok = False;
1314 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1315 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1316 DEBUG(4,("s: dom mismatch "));
1317 ok = False;
1320 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1321 ok = False;
1324 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1325 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1327 if (ok) {
1328 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1329 s->name, s->type, s->comment, s->domain));
1330 s->server_added = True;
1331 count++;
1332 } else {
1333 DEBUG(4,("%20s %8x %25s %15s\n",
1334 s->name, s->type, s->comment, s->domain));
1338 TALLOC_FREE(lines);
1339 return count;
1342 /*******************************************************************
1343 Fill in a server info structure.
1344 ******************************************************************/
1346 static int fill_srv_info(struct srv_info_struct *service,
1347 int uLevel, char **buf, int *buflen,
1348 char **stringbuf, int *stringspace, char *baseaddr)
1350 int struct_len;
1351 char* p;
1352 char* p2;
1353 int l2;
1354 int len;
1356 switch (uLevel) {
1357 case 0:
1358 struct_len = 16;
1359 break;
1360 case 1:
1361 struct_len = 26;
1362 break;
1363 default:
1364 return -1;
1367 if (!buf) {
1368 len = 0;
1369 switch (uLevel) {
1370 case 1:
1371 len = strlen(service->comment)+1;
1372 break;
1375 *buflen = struct_len;
1376 *stringspace = len;
1377 return struct_len + len;
1380 len = struct_len;
1381 p = *buf;
1382 if (*buflen < struct_len) {
1383 return -1;
1385 if (stringbuf) {
1386 p2 = *stringbuf;
1387 l2 = *stringspace;
1388 } else {
1389 p2 = p + struct_len;
1390 l2 = *buflen - struct_len;
1392 if (!baseaddr) {
1393 baseaddr = p;
1396 switch (uLevel) {
1397 case 0:
1398 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1399 break;
1401 case 1:
1402 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1403 SIVAL(p,18,service->type);
1404 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1405 len += CopyAndAdvance(&p2,service->comment,&l2);
1406 break;
1409 if (stringbuf) {
1410 *buf = p + struct_len;
1411 *buflen -= struct_len;
1412 *stringbuf = p2;
1413 *stringspace = l2;
1414 } else {
1415 *buf = p2;
1416 *buflen -= len;
1418 return len;
1422 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1424 return StrCaseCmp(s1->name,s2->name);
1427 /****************************************************************************
1428 View list of servers available (or possibly domains). The info is
1429 extracted from lists saved by nmbd on the local host.
1430 ****************************************************************************/
1432 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1433 connection_struct *conn, uint16 vuid,
1434 char *param, int tpscnt,
1435 char *data, int tdscnt,
1436 int mdrcnt, int mprcnt, char **rdata,
1437 char **rparam, int *rdata_len, int *rparam_len)
1439 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1440 char *str2 = skip_string(param,tpscnt,str1);
1441 char *p = skip_string(param,tpscnt,str2);
1442 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1443 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1444 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1445 char *p2;
1446 int data_len, fixed_len, string_len;
1447 int f_len = 0, s_len = 0;
1448 struct srv_info_struct *servers=NULL;
1449 int counted=0,total=0;
1450 int i,missed;
1451 fstring domain;
1452 bool domain_request;
1453 bool local_request;
1455 if (!str1 || !str2 || !p) {
1456 return False;
1459 /* If someone sets all the bits they don't really mean to set
1460 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1461 known servers. */
1463 if (servertype == SV_TYPE_ALL) {
1464 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1467 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1468 any other bit (they may just set this bit on its own) they
1469 want all the locally seen servers. However this bit can be
1470 set on its own so set the requested servers to be
1471 ALL - DOMAIN_ENUM. */
1473 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1474 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1477 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1478 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1480 p += 8;
1482 if (!prefix_ok(str1,"WrLehD")) {
1483 return False;
1485 if (!check_server_info(uLevel,str2)) {
1486 return False;
1489 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1490 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1491 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1493 if (strcmp(str1, "WrLehDz") == 0) {
1494 if (skip_string(param,tpscnt,p) == NULL) {
1495 return False;
1497 pull_ascii_fstring(domain, p);
1498 } else {
1499 fstrcpy(domain, lp_workgroup());
1502 DEBUG(4, ("domain [%s]\n", domain));
1504 if (lp_browse_list()) {
1505 total = get_server_info(servertype,&servers,domain);
1508 data_len = fixed_len = string_len = 0;
1509 missed = 0;
1511 TYPESAFE_QSORT(servers, total, srv_comp);
1514 char *lastname=NULL;
1516 for (i=0;i<total;i++) {
1517 struct srv_info_struct *s = &servers[i];
1519 if (lastname && strequal(lastname,s->name)) {
1520 continue;
1522 lastname = s->name;
1523 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1524 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1525 i, s->name, s->type, s->comment, s->domain));
1527 if (data_len < buf_len) {
1528 counted++;
1529 fixed_len += f_len;
1530 string_len += s_len;
1531 } else {
1532 missed++;
1537 *rdata_len = fixed_len + string_len;
1538 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1539 if (!*rdata) {
1540 return False;
1543 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1544 p = *rdata;
1545 f_len = fixed_len;
1546 s_len = string_len;
1549 char *lastname=NULL;
1550 int count2 = counted;
1552 for (i = 0; i < total && count2;i++) {
1553 struct srv_info_struct *s = &servers[i];
1555 if (lastname && strequal(lastname,s->name)) {
1556 continue;
1558 lastname = s->name;
1559 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1560 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1561 i, s->name, s->type, s->comment, s->domain));
1562 count2--;
1566 *rparam_len = 8;
1567 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1568 if (!*rparam) {
1569 return False;
1571 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1572 SSVAL(*rparam,2,0);
1573 SSVAL(*rparam,4,counted);
1574 SSVAL(*rparam,6,counted+missed);
1576 SAFE_FREE(servers);
1578 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1579 domain,uLevel,counted,counted+missed));
1581 return True;
1584 static int srv_name_match(const char *n1, const char *n2)
1587 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1589 * In Windows, FirstNameToReturn need not be an exact match:
1590 * the server will return a list of servers that exist on
1591 * the network greater than or equal to the FirstNameToReturn.
1593 int ret = StrCaseCmp(n1, n2);
1595 if (ret <= 0) {
1596 return 0;
1599 return ret;
1602 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1603 connection_struct *conn, uint16 vuid,
1604 char *param, int tpscnt,
1605 char *data, int tdscnt,
1606 int mdrcnt, int mprcnt, char **rdata,
1607 char **rparam, int *rdata_len, int *rparam_len)
1609 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1610 char *str2 = skip_string(param,tpscnt,str1);
1611 char *p = skip_string(param,tpscnt,str2);
1612 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1613 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1614 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1615 char *p2;
1616 int data_len, fixed_len, string_len;
1617 int f_len = 0, s_len = 0;
1618 struct srv_info_struct *servers=NULL;
1619 int counted=0,first=0,total=0;
1620 int i,missed;
1621 fstring domain;
1622 fstring first_name;
1623 bool domain_request;
1624 bool local_request;
1626 if (!str1 || !str2 || !p) {
1627 return False;
1630 /* If someone sets all the bits they don't really mean to set
1631 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1632 known servers. */
1634 if (servertype == SV_TYPE_ALL) {
1635 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1638 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1639 any other bit (they may just set this bit on its own) they
1640 want all the locally seen servers. However this bit can be
1641 set on its own so set the requested servers to be
1642 ALL - DOMAIN_ENUM. */
1644 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1645 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1648 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1649 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1651 p += 8;
1653 if (strcmp(str1, "WrLehDzz") != 0) {
1654 return false;
1656 if (!check_server_info(uLevel,str2)) {
1657 return False;
1660 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1661 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1662 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1664 if (skip_string(param,tpscnt,p) == NULL) {
1665 return False;
1667 pull_ascii_fstring(domain, p);
1668 if (domain[0] == '\0') {
1669 fstrcpy(domain, lp_workgroup());
1671 p = skip_string(param,tpscnt,p);
1672 if (skip_string(param,tpscnt,p) == NULL) {
1673 return False;
1675 pull_ascii_fstring(first_name, p);
1677 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1678 domain, first_name));
1680 if (lp_browse_list()) {
1681 total = get_server_info(servertype,&servers,domain);
1684 data_len = fixed_len = string_len = 0;
1685 missed = 0;
1687 TYPESAFE_QSORT(servers, total, srv_comp);
1689 if (first_name[0] != '\0') {
1690 struct srv_info_struct *first_server = NULL;
1692 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1693 srv_name_match, first_server);
1694 if (first_server) {
1695 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1697 * The binary search may not find the exact match
1698 * so we need to search backward to find the first match
1700 * This implements the strange matching windows
1701 * implements. (see the comment in srv_name_match().
1703 for (;first > 0;) {
1704 int ret;
1705 ret = StrCaseCmp(first_name,
1706 servers[first-1].name);
1707 if (ret > 0) {
1708 break;
1710 first--;
1712 } else {
1713 /* we should return no entries */
1714 first = total;
1719 char *lastname=NULL;
1721 for (i=first;i<total;i++) {
1722 struct srv_info_struct *s = &servers[i];
1724 if (lastname && strequal(lastname,s->name)) {
1725 continue;
1727 lastname = s->name;
1728 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1729 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1730 i, s->name, s->type, s->comment, s->domain));
1732 if (data_len < buf_len) {
1733 counted++;
1734 fixed_len += f_len;
1735 string_len += s_len;
1736 } else {
1737 missed++;
1742 *rdata_len = fixed_len + string_len;
1743 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1744 if (!*rdata) {
1745 return False;
1748 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1749 p = *rdata;
1750 f_len = fixed_len;
1751 s_len = string_len;
1754 char *lastname=NULL;
1755 int count2 = counted;
1757 for (i = first; i < total && count2;i++) {
1758 struct srv_info_struct *s = &servers[i];
1760 if (lastname && strequal(lastname,s->name)) {
1761 continue;
1763 lastname = s->name;
1764 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1765 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1766 i, s->name, s->type, s->comment, s->domain));
1767 count2--;
1771 *rparam_len = 8;
1772 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1773 if (!*rparam) {
1774 return False;
1776 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1777 SSVAL(*rparam,2,0);
1778 SSVAL(*rparam,4,counted);
1779 SSVAL(*rparam,6,counted+missed);
1781 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1782 domain,uLevel,first,first_name,
1783 first < total ? servers[first].name : "",
1784 counted,counted+missed));
1786 SAFE_FREE(servers);
1788 return True;
1791 /****************************************************************************
1792 command 0x34 - suspected of being a "Lookup Names" stub api
1793 ****************************************************************************/
1795 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1796 connection_struct *conn, uint16 vuid,
1797 char *param, int tpscnt,
1798 char *data, int tdscnt,
1799 int mdrcnt, int mprcnt, char **rdata,
1800 char **rparam, int *rdata_len, int *rparam_len)
1802 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1803 char *str2 = skip_string(param,tpscnt,str1);
1804 char *p = skip_string(param,tpscnt,str2);
1805 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1806 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1807 int counted=0;
1808 int missed=0;
1810 if (!str1 || !str2 || !p) {
1811 return False;
1814 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1815 str1, str2, p, uLevel, buf_len));
1817 if (!prefix_ok(str1,"zWrLeh")) {
1818 return False;
1821 *rdata_len = 0;
1823 *rparam_len = 8;
1824 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1825 if (!*rparam) {
1826 return False;
1829 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1830 SSVAL(*rparam,2,0);
1831 SSVAL(*rparam,4,counted);
1832 SSVAL(*rparam,6,counted+missed);
1834 return True;
1837 /****************************************************************************
1838 get info about a share
1839 ****************************************************************************/
1841 static bool check_share_info(int uLevel, char* id)
1843 switch( uLevel ) {
1844 case 0:
1845 if (strcmp(id,"B13") != 0) {
1846 return False;
1848 break;
1849 case 1:
1850 /* Level-2 descriptor is allowed (and ignored) */
1851 if (strcmp(id,"B13BWz") != 0 &&
1852 strcmp(id,"B13BWzWWWzB9B") != 0) {
1853 return False;
1855 break;
1856 case 2:
1857 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1858 return False;
1860 break;
1861 case 91:
1862 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1863 return False;
1865 break;
1866 default:
1867 return False;
1869 return True;
1872 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1873 char** buf, int* buflen,
1874 char** stringbuf, int* stringspace, char* baseaddr)
1876 int struct_len;
1877 char* p;
1878 char* p2;
1879 int l2;
1880 int len;
1882 switch( uLevel ) {
1883 case 0:
1884 struct_len = 13;
1885 break;
1886 case 1:
1887 struct_len = 20;
1888 break;
1889 case 2:
1890 struct_len = 40;
1891 break;
1892 case 91:
1893 struct_len = 68;
1894 break;
1895 default:
1896 return -1;
1899 if (!buf) {
1900 len = 0;
1902 if (uLevel > 0) {
1903 len += StrlenExpanded(conn,snum,lp_comment(snum));
1905 if (uLevel > 1) {
1906 len += strlen(lp_pathname(snum)) + 1;
1908 if (buflen) {
1909 *buflen = struct_len;
1911 if (stringspace) {
1912 *stringspace = len;
1914 return struct_len + len;
1917 len = struct_len;
1918 p = *buf;
1919 if ((*buflen) < struct_len) {
1920 return -1;
1923 if (stringbuf) {
1924 p2 = *stringbuf;
1925 l2 = *stringspace;
1926 } else {
1927 p2 = p + struct_len;
1928 l2 = (*buflen) - struct_len;
1931 if (!baseaddr) {
1932 baseaddr = p;
1935 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1937 if (uLevel > 0) {
1938 int type;
1940 SCVAL(p,13,0);
1941 type = STYPE_DISKTREE;
1942 if (lp_print_ok(snum)) {
1943 type = STYPE_PRINTQ;
1945 if (strequal("IPC",lp_fstype(snum))) {
1946 type = STYPE_IPC;
1948 SSVAL(p,14,type); /* device type */
1949 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1950 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1953 if (uLevel > 1) {
1954 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1955 SSVALS(p,22,-1); /* max uses */
1956 SSVAL(p,24,1); /* current uses */
1957 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1958 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1959 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1962 if (uLevel > 2) {
1963 memset(p+40,0,SHPWLEN+2);
1964 SSVAL(p,50,0);
1965 SIVAL(p,52,0);
1966 SSVAL(p,56,0);
1967 SSVAL(p,58,0);
1968 SIVAL(p,60,0);
1969 SSVAL(p,64,0);
1970 SSVAL(p,66,0);
1973 if (stringbuf) {
1974 (*buf) = p + struct_len;
1975 (*buflen) -= struct_len;
1976 (*stringbuf) = p2;
1977 (*stringspace) = l2;
1978 } else {
1979 (*buf) = p2;
1980 (*buflen) -= len;
1983 return len;
1986 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
1987 connection_struct *conn,uint16 vuid,
1988 char *param, int tpscnt,
1989 char *data, int tdscnt,
1990 int mdrcnt,int mprcnt,
1991 char **rdata,char **rparam,
1992 int *rdata_len,int *rparam_len)
1994 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1995 char *str2 = skip_string(param,tpscnt,str1);
1996 char *netname = skip_string(param,tpscnt,str2);
1997 char *p = skip_string(param,tpscnt,netname);
1998 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1999 int snum;
2001 if (!str1 || !str2 || !netname || !p) {
2002 return False;
2005 snum = find_service(netname);
2006 if (snum < 0) {
2007 return False;
2010 /* check it's a supported varient */
2011 if (!prefix_ok(str1,"zWrLh")) {
2012 return False;
2014 if (!check_share_info(uLevel,str2)) {
2015 return False;
2018 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2019 if (!*rdata) {
2020 return False;
2022 p = *rdata;
2023 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2024 if (*rdata_len < 0) {
2025 return False;
2028 *rparam_len = 6;
2029 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2030 if (!*rparam) {
2031 return False;
2033 SSVAL(*rparam,0,NERR_Success);
2034 SSVAL(*rparam,2,0); /* converter word */
2035 SSVAL(*rparam,4,*rdata_len);
2037 return True;
2040 /****************************************************************************
2041 View the list of available shares.
2043 This function is the server side of the NetShareEnum() RAP call.
2044 It fills the return buffer with share names and share comments.
2045 Note that the return buffer normally (in all known cases) allows only
2046 twelve byte strings for share names (plus one for a nul terminator).
2047 Share names longer than 12 bytes must be skipped.
2048 ****************************************************************************/
2050 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2051 connection_struct *conn, uint16 vuid,
2052 char *param, int tpscnt,
2053 char *data, int tdscnt,
2054 int mdrcnt,
2055 int mprcnt,
2056 char **rdata,
2057 char **rparam,
2058 int *rdata_len,
2059 int *rparam_len )
2061 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2062 char *str2 = skip_string(param,tpscnt,str1);
2063 char *p = skip_string(param,tpscnt,str2);
2064 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2065 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2066 char *p2;
2067 int count = 0;
2068 int total=0,counted=0;
2069 bool missed = False;
2070 int i;
2071 int data_len, fixed_len, string_len;
2072 int f_len = 0, s_len = 0;
2074 if (!str1 || !str2 || !p) {
2075 return False;
2078 if (!prefix_ok(str1,"WrLeh")) {
2079 return False;
2081 if (!check_share_info(uLevel,str2)) {
2082 return False;
2085 /* Ensure all the usershares are loaded. */
2086 become_root();
2087 load_registry_shares();
2088 count = load_usershare_shares();
2089 unbecome_root();
2091 data_len = fixed_len = string_len = 0;
2092 for (i=0;i<count;i++) {
2093 fstring servicename_dos;
2094 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2095 continue;
2097 push_ascii_fstring(servicename_dos, lp_servicename(i));
2098 /* Maximum name length = 13. */
2099 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2100 total++;
2101 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2102 if (data_len < buf_len) {
2103 counted++;
2104 fixed_len += f_len;
2105 string_len += s_len;
2106 } else {
2107 missed = True;
2112 *rdata_len = fixed_len + string_len;
2113 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2114 if (!*rdata) {
2115 return False;
2118 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2119 p = *rdata;
2120 f_len = fixed_len;
2121 s_len = string_len;
2123 for( i = 0; i < count; i++ ) {
2124 fstring servicename_dos;
2125 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2126 continue;
2129 push_ascii_fstring(servicename_dos, lp_servicename(i));
2130 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2131 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2132 break;
2137 *rparam_len = 8;
2138 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2139 if (!*rparam) {
2140 return False;
2142 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2143 SSVAL(*rparam,2,0);
2144 SSVAL(*rparam,4,counted);
2145 SSVAL(*rparam,6,total);
2147 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2148 counted,total,uLevel,
2149 buf_len,*rdata_len,mdrcnt));
2151 return True;
2154 /****************************************************************************
2155 Add a share
2156 ****************************************************************************/
2158 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2159 connection_struct *conn,uint16 vuid,
2160 char *param, int tpscnt,
2161 char *data, int tdscnt,
2162 int mdrcnt,int mprcnt,
2163 char **rdata,char **rparam,
2164 int *rdata_len,int *rparam_len)
2166 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2167 char *str2 = skip_string(param,tpscnt,str1);
2168 char *p = skip_string(param,tpscnt,str2);
2169 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2170 fstring sharename;
2171 fstring comment;
2172 char *pathname = NULL;
2173 unsigned int offset;
2174 int res = ERRunsup;
2175 size_t converted_size;
2177 WERROR werr = WERR_OK;
2178 TALLOC_CTX *mem_ctx = talloc_tos();
2179 NTSTATUS status;
2180 struct rpc_pipe_client *cli = NULL;
2181 union srvsvc_NetShareInfo info;
2182 struct srvsvc_NetShareInfo2 info2;
2184 if (!str1 || !str2 || !p) {
2185 return False;
2188 /* check it's a supported varient */
2189 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2190 return False;
2192 if (!check_share_info(uLevel,str2)) {
2193 return False;
2195 if (uLevel != 2) {
2196 return False;
2199 /* Do we have a string ? */
2200 if (skip_string(data,mdrcnt,data) == NULL) {
2201 return False;
2203 pull_ascii_fstring(sharename,data);
2205 if (mdrcnt < 28) {
2206 return False;
2209 /* only support disk share adds */
2210 if (SVAL(data,14)!=STYPE_DISKTREE) {
2211 return False;
2214 offset = IVAL(data, 16);
2215 if (offset >= mdrcnt) {
2216 res = ERRinvalidparam;
2217 goto out;
2220 /* Do we have a string ? */
2221 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2222 return False;
2224 pull_ascii_fstring(comment, offset? (data+offset) : "");
2226 offset = IVAL(data, 26);
2228 if (offset >= mdrcnt) {
2229 res = ERRinvalidparam;
2230 goto out;
2233 /* Do we have a string ? */
2234 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2235 return False;
2238 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2239 offset ? (data+offset) : "", &converted_size))
2241 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2242 strerror(errno)));
2245 if (!pathname) {
2246 return false;
2249 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2250 conn->server_info,
2251 &conn->sconn->client_id,
2252 conn->sconn->msg_ctx,
2253 &cli);
2254 if (!NT_STATUS_IS_OK(status)) {
2255 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2256 nt_errstr(status)));
2257 res = W_ERROR_V(ntstatus_to_werror(status));
2258 goto out;
2261 info2.name = sharename;
2262 info2.type = STYPE_DISKTREE;
2263 info2.comment = comment;
2264 info2.permissions = 0;
2265 info2.max_users = 0;
2266 info2.current_users = 0;
2267 info2.path = pathname;
2268 info2.password = NULL;
2270 info.info2 = &info2;
2272 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2273 cli->srv_name_slash,
2275 &info,
2276 NULL,
2277 &werr);
2278 if (!NT_STATUS_IS_OK(status)) {
2279 res = W_ERROR_V(ntstatus_to_werror(status));
2280 goto out;
2282 if (!W_ERROR_IS_OK(werr)) {
2283 res = W_ERROR_V(werr);
2284 goto out;
2287 *rparam_len = 6;
2288 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2289 if (!*rparam) {
2290 return False;
2292 SSVAL(*rparam,0,NERR_Success);
2293 SSVAL(*rparam,2,0); /* converter word */
2294 SSVAL(*rparam,4,*rdata_len);
2295 *rdata_len = 0;
2297 return True;
2299 out:
2301 *rparam_len = 4;
2302 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2303 if (!*rparam) {
2304 return False;
2306 *rdata_len = 0;
2307 SSVAL(*rparam,0,res);
2308 SSVAL(*rparam,2,0);
2309 return True;
2312 /****************************************************************************
2313 view list of groups available
2314 ****************************************************************************/
2316 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2317 connection_struct *conn,uint16 vuid,
2318 char *param, int tpscnt,
2319 char *data, int tdscnt,
2320 int mdrcnt,int mprcnt,
2321 char **rdata,char **rparam,
2322 int *rdata_len,int *rparam_len)
2324 int i;
2325 int errflags=0;
2326 int resume_context, cli_buf_size;
2327 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2328 char *str2 = skip_string(param,tpscnt,str1);
2329 char *p = skip_string(param,tpscnt,str2);
2331 uint32_t num_groups;
2332 uint32_t resume_handle;
2333 struct rpc_pipe_client *samr_pipe;
2334 struct policy_handle samr_handle, domain_handle;
2335 NTSTATUS status;
2337 if (!str1 || !str2 || !p) {
2338 return False;
2341 if (strcmp(str1,"WrLeh") != 0) {
2342 return False;
2345 /* parameters
2346 * W-> resume context (number of users to skip)
2347 * r -> return parameter pointer to receive buffer
2348 * L -> length of receive buffer
2349 * e -> return parameter number of entries
2350 * h -> return parameter total number of users
2353 if (strcmp("B21",str2) != 0) {
2354 return False;
2357 status = rpc_pipe_open_internal(
2358 talloc_tos(), &ndr_table_samr.syntax_id,
2359 conn->server_info, &conn->sconn->client_id,
2360 conn->sconn->msg_ctx, &samr_pipe);
2361 if (!NT_STATUS_IS_OK(status)) {
2362 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2363 nt_errstr(status)));
2364 return false;
2367 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2368 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2369 if (!NT_STATUS_IS_OK(status)) {
2370 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2371 nt_errstr(status)));
2372 return false;
2375 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2376 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2377 get_global_sam_sid(), &domain_handle);
2378 if (!NT_STATUS_IS_OK(status)) {
2379 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2380 nt_errstr(status)));
2381 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2382 return false;
2385 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2386 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2387 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2388 "%d\n", resume_context, cli_buf_size));
2390 *rdata_len = cli_buf_size;
2391 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2392 if (!*rdata) {
2393 return False;
2396 p = *rdata;
2398 errflags = NERR_Success;
2399 num_groups = 0;
2400 resume_handle = 0;
2402 while (true) {
2403 struct samr_SamArray *sam_entries;
2404 uint32_t num_entries;
2406 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2407 &domain_handle,
2408 &resume_handle,
2409 &sam_entries, 1,
2410 &num_entries);
2411 if (!NT_STATUS_IS_OK(status)) {
2412 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2413 "%s\n", nt_errstr(status)));
2414 break;
2417 if (num_entries == 0) {
2418 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2419 "no entries -- done\n"));
2420 break;
2423 for(i=0; i<num_entries; i++) {
2424 const char *name;
2426 name = sam_entries->entries[i].name.string;
2428 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2429 /* set overflow error */
2430 DEBUG(3,("overflow on entry %d group %s\n", i,
2431 name));
2432 errflags=234;
2433 break;
2436 /* truncate the name at 21 chars. */
2437 memset(p, 0, 21);
2438 strlcpy(p, name, 21);
2439 DEBUG(10,("adding entry %d group %s\n", i, p));
2440 p += 21;
2441 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2442 * idea why... */
2443 num_groups += 1;
2446 if (errflags != NERR_Success) {
2447 break;
2450 TALLOC_FREE(sam_entries);
2453 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2454 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2456 *rdata_len = PTR_DIFF(p,*rdata);
2458 *rparam_len = 8;
2459 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2460 if (!*rparam) {
2461 return False;
2463 SSVAL(*rparam, 0, errflags);
2464 SSVAL(*rparam, 2, 0); /* converter word */
2465 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2466 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2468 return(True);
2471 /*******************************************************************
2472 Get groups that a user is a member of.
2473 ******************************************************************/
2475 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2476 connection_struct *conn,uint16 vuid,
2477 char *param, int tpscnt,
2478 char *data, int tdscnt,
2479 int mdrcnt,int mprcnt,
2480 char **rdata,char **rparam,
2481 int *rdata_len,int *rparam_len)
2483 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2484 char *str2 = skip_string(param,tpscnt,str1);
2485 char *UserName = skip_string(param,tpscnt,str2);
2486 char *p = skip_string(param,tpscnt,UserName);
2487 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2488 const char *level_string;
2489 int count=0;
2490 bool ret = False;
2491 uint32_t i;
2492 char *endp = NULL;
2494 struct rpc_pipe_client *samr_pipe;
2495 struct policy_handle samr_handle, domain_handle, user_handle;
2496 struct lsa_String name;
2497 struct lsa_Strings names;
2498 struct samr_Ids type, rid;
2499 struct samr_RidWithAttributeArray *rids;
2500 NTSTATUS status;
2502 if (!str1 || !str2 || !UserName || !p) {
2503 return False;
2506 *rparam_len = 8;
2507 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2508 if (!*rparam) {
2509 return False;
2512 /* check it's a supported varient */
2514 if ( strcmp(str1,"zWrLeh") != 0 )
2515 return False;
2517 switch( uLevel ) {
2518 case 0:
2519 level_string = "B21";
2520 break;
2521 default:
2522 return False;
2525 if (strcmp(level_string,str2) != 0)
2526 return False;
2528 *rdata_len = mdrcnt + 1024;
2529 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2530 if (!*rdata) {
2531 return False;
2534 SSVAL(*rparam,0,NERR_Success);
2535 SSVAL(*rparam,2,0); /* converter word */
2537 p = *rdata;
2538 endp = *rdata + *rdata_len;
2540 status = rpc_pipe_open_internal(
2541 talloc_tos(), &ndr_table_samr.syntax_id,
2542 conn->server_info, &conn->sconn->client_id,
2543 conn->sconn->msg_ctx, &samr_pipe);
2544 if (!NT_STATUS_IS_OK(status)) {
2545 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2546 nt_errstr(status)));
2547 return false;
2550 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2551 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2552 if (!NT_STATUS_IS_OK(status)) {
2553 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2554 nt_errstr(status)));
2555 return false;
2558 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2559 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2560 get_global_sam_sid(), &domain_handle);
2561 if (!NT_STATUS_IS_OK(status)) {
2562 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2563 nt_errstr(status)));
2564 goto close_sam;
2567 name.string = UserName;
2569 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2570 &domain_handle, 1, &name,
2571 &rid, &type);
2572 if (!NT_STATUS_IS_OK(status)) {
2573 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2574 nt_errstr(status)));
2575 goto close_domain;
2578 if (type.ids[0] != SID_NAME_USER) {
2579 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2580 sid_type_lookup(type.ids[0])));
2581 goto close_domain;
2584 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2585 &domain_handle,
2586 SAMR_USER_ACCESS_GET_GROUPS,
2587 rid.ids[0], &user_handle);
2588 if (!NT_STATUS_IS_OK(status)) {
2589 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2590 nt_errstr(status)));
2591 goto close_domain;
2594 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2595 &user_handle, &rids);
2596 if (!NT_STATUS_IS_OK(status)) {
2597 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2598 nt_errstr(status)));
2599 goto close_user;
2602 for (i=0; i<rids->count; i++) {
2604 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2605 &domain_handle,
2606 1, &rids->rids[i].rid,
2607 &names, &type);
2608 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2609 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2610 p += 21;
2611 count++;
2615 *rdata_len = PTR_DIFF(p,*rdata);
2617 SSVAL(*rparam,4,count); /* is this right?? */
2618 SSVAL(*rparam,6,count); /* is this right?? */
2620 ret = True;
2622 close_user:
2623 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2624 close_domain:
2625 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2626 close_sam:
2627 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2629 return ret;
2632 /*******************************************************************
2633 Get all users.
2634 ******************************************************************/
2636 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2637 connection_struct *conn, uint16 vuid,
2638 char *param, int tpscnt,
2639 char *data, int tdscnt,
2640 int mdrcnt,int mprcnt,
2641 char **rdata,char **rparam,
2642 int *rdata_len,int *rparam_len)
2644 int count_sent=0;
2645 int num_users=0;
2646 int errflags=0;
2647 int i, resume_context, cli_buf_size;
2648 uint32_t resume_handle;
2650 struct rpc_pipe_client *samr_pipe;
2651 struct policy_handle samr_handle, domain_handle;
2652 NTSTATUS status;
2654 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2655 char *str2 = skip_string(param,tpscnt,str1);
2656 char *p = skip_string(param,tpscnt,str2);
2657 char *endp = NULL;
2659 if (!str1 || !str2 || !p) {
2660 return False;
2663 if (strcmp(str1,"WrLeh") != 0)
2664 return False;
2665 /* parameters
2666 * W-> resume context (number of users to skip)
2667 * r -> return parameter pointer to receive buffer
2668 * L -> length of receive buffer
2669 * e -> return parameter number of entries
2670 * h -> return parameter total number of users
2673 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2674 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2675 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2676 resume_context, cli_buf_size));
2678 *rparam_len = 8;
2679 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2680 if (!*rparam) {
2681 return False;
2684 /* check it's a supported varient */
2685 if (strcmp("B21",str2) != 0)
2686 return False;
2688 *rdata_len = cli_buf_size;
2689 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2690 if (!*rdata) {
2691 return False;
2694 p = *rdata;
2695 endp = *rdata + *rdata_len;
2697 status = rpc_pipe_open_internal(
2698 talloc_tos(), &ndr_table_samr.syntax_id,
2699 conn->server_info, &conn->sconn->client_id,
2700 conn->sconn->msg_ctx, &samr_pipe);
2701 if (!NT_STATUS_IS_OK(status)) {
2702 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2703 nt_errstr(status)));
2704 return false;
2707 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2708 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2709 if (!NT_STATUS_IS_OK(status)) {
2710 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2711 nt_errstr(status)));
2712 return false;
2715 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2716 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2717 get_global_sam_sid(), &domain_handle);
2718 if (!NT_STATUS_IS_OK(status)) {
2719 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2720 nt_errstr(status)));
2721 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2722 return false;
2725 errflags=NERR_Success;
2727 resume_handle = 0;
2729 while (true) {
2730 struct samr_SamArray *sam_entries;
2731 uint32_t num_entries;
2733 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2734 &domain_handle,
2735 &resume_handle,
2736 0, &sam_entries, 1,
2737 &num_entries);
2739 if (!NT_STATUS_IS_OK(status)) {
2740 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2741 "%s\n", nt_errstr(status)));
2742 break;
2745 if (num_entries == 0) {
2746 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2747 "no entries -- done\n"));
2748 break;
2751 for (i=0; i<num_entries; i++) {
2752 const char *name;
2754 name = sam_entries->entries[i].name.string;
2756 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2757 &&(strlen(name)<=21)) {
2758 strlcpy(p,name,PTR_DIFF(endp,p));
2759 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2760 "username %s\n",count_sent,p));
2761 p += 21;
2762 count_sent++;
2763 } else {
2764 /* set overflow error */
2765 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2766 "username %s\n",count_sent,name));
2767 errflags=234;
2768 break;
2772 if (errflags != NERR_Success) {
2773 break;
2776 TALLOC_FREE(sam_entries);
2779 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2780 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2782 *rdata_len = PTR_DIFF(p,*rdata);
2784 SSVAL(*rparam,0,errflags);
2785 SSVAL(*rparam,2,0); /* converter word */
2786 SSVAL(*rparam,4,count_sent); /* is this right?? */
2787 SSVAL(*rparam,6,num_users); /* is this right?? */
2789 return True;
2792 /****************************************************************************
2793 Get the time of day info.
2794 ****************************************************************************/
2796 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2797 connection_struct *conn,uint16 vuid,
2798 char *param, int tpscnt,
2799 char *data, int tdscnt,
2800 int mdrcnt,int mprcnt,
2801 char **rdata,char **rparam,
2802 int *rdata_len,int *rparam_len)
2804 struct tm *t;
2805 time_t unixdate = time(NULL);
2806 char *p;
2808 *rparam_len = 4;
2809 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2810 if (!*rparam) {
2811 return False;
2814 *rdata_len = 21;
2815 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2816 if (!*rdata) {
2817 return False;
2820 SSVAL(*rparam,0,NERR_Success);
2821 SSVAL(*rparam,2,0); /* converter word */
2823 p = *rdata;
2825 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2826 by NT in a "net time" operation,
2827 it seems to ignore the one below */
2829 /* the client expects to get localtime, not GMT, in this bit
2830 (I think, this needs testing) */
2831 t = localtime(&unixdate);
2832 if (!t) {
2833 return False;
2836 SIVAL(p,4,0); /* msecs ? */
2837 SCVAL(p,8,t->tm_hour);
2838 SCVAL(p,9,t->tm_min);
2839 SCVAL(p,10,t->tm_sec);
2840 SCVAL(p,11,0); /* hundredths of seconds */
2841 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2842 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2843 SCVAL(p,16,t->tm_mday);
2844 SCVAL(p,17,t->tm_mon + 1);
2845 SSVAL(p,18,1900+t->tm_year);
2846 SCVAL(p,20,t->tm_wday);
2848 return True;
2851 /****************************************************************************
2852 Set the user password.
2853 *****************************************************************************/
2855 static bool api_SetUserPassword(struct smbd_server_connection *sconn,
2856 connection_struct *conn,uint16 vuid,
2857 char *param, int tpscnt,
2858 char *data, int tdscnt,
2859 int mdrcnt,int mprcnt,
2860 char **rdata,char **rparam,
2861 int *rdata_len,int *rparam_len)
2863 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2864 char *p = NULL;
2865 fstring user;
2866 fstring pass1,pass2;
2867 TALLOC_CTX *mem_ctx = talloc_tos();
2868 NTSTATUS status;
2869 struct rpc_pipe_client *cli = NULL;
2870 struct policy_handle connect_handle, domain_handle, user_handle;
2871 struct lsa_String domain_name;
2872 struct dom_sid2 *domain_sid;
2873 struct lsa_String names;
2874 struct samr_Ids rids;
2875 struct samr_Ids types;
2876 struct samr_Password old_lm_hash;
2877 struct samr_Password new_lm_hash;
2878 int errcode = NERR_badpass;
2879 uint32_t rid;
2880 int encrypted;
2881 int min_pwd_length;
2883 /* Skip 2 strings. */
2884 p = skip_string(param,tpscnt,np);
2885 p = skip_string(param,tpscnt,p);
2887 if (!np || !p) {
2888 return False;
2891 /* Do we have a string ? */
2892 if (skip_string(param,tpscnt,p) == NULL) {
2893 return False;
2895 pull_ascii_fstring(user,p);
2897 p = skip_string(param,tpscnt,p);
2898 if (!p) {
2899 return False;
2902 memset(pass1,'\0',sizeof(pass1));
2903 memset(pass2,'\0',sizeof(pass2));
2905 * We use 31 here not 32 as we're checking
2906 * the last byte we want to access is safe.
2908 if (!is_offset_safe(param,tpscnt,p,31)) {
2909 return False;
2911 memcpy(pass1,p,16);
2912 memcpy(pass2,p+16,16);
2914 encrypted = get_safe_SVAL(param,tpscnt,p+32,0,-1);
2915 if (encrypted == -1) {
2916 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2917 goto out;
2920 min_pwd_length = get_safe_SVAL(param,tpscnt,p+34,0,-1);
2921 if (min_pwd_length == -1) {
2922 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2923 goto out;
2926 *rparam_len = 4;
2927 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2928 if (!*rparam) {
2929 return False;
2932 *rdata_len = 0;
2934 DEBUG(3,("Set password for <%s> (encrypted: %d, min_pwd_length: %d)\n",
2935 user, encrypted, min_pwd_length));
2937 ZERO_STRUCT(connect_handle);
2938 ZERO_STRUCT(domain_handle);
2939 ZERO_STRUCT(user_handle);
2941 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
2942 conn->server_info,
2943 &conn->sconn->client_id,
2944 conn->sconn->msg_ctx,
2945 &cli);
2946 if (!NT_STATUS_IS_OK(status)) {
2947 DEBUG(0,("api_SetUserPassword: could not connect to samr: %s\n",
2948 nt_errstr(status)));
2949 errcode = W_ERROR_V(ntstatus_to_werror(status));
2950 goto out;
2953 status = rpccli_samr_Connect2(cli, mem_ctx,
2954 global_myname(),
2955 SAMR_ACCESS_CONNECT_TO_SERVER |
2956 SAMR_ACCESS_ENUM_DOMAINS |
2957 SAMR_ACCESS_LOOKUP_DOMAIN,
2958 &connect_handle);
2959 if (!NT_STATUS_IS_OK(status)) {
2960 errcode = W_ERROR_V(ntstatus_to_werror(status));
2961 goto out;
2964 init_lsa_String(&domain_name, get_global_sam_name());
2966 status = rpccli_samr_LookupDomain(cli, mem_ctx,
2967 &connect_handle,
2968 &domain_name,
2969 &domain_sid);
2970 if (!NT_STATUS_IS_OK(status)) {
2971 errcode = W_ERROR_V(ntstatus_to_werror(status));
2972 goto out;
2975 status = rpccli_samr_OpenDomain(cli, mem_ctx,
2976 &connect_handle,
2977 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2978 domain_sid,
2979 &domain_handle);
2980 if (!NT_STATUS_IS_OK(status)) {
2981 errcode = W_ERROR_V(ntstatus_to_werror(status));
2982 goto out;
2985 init_lsa_String(&names, user);
2987 status = rpccli_samr_LookupNames(cli, mem_ctx,
2988 &domain_handle,
2990 &names,
2991 &rids,
2992 &types);
2993 if (!NT_STATUS_IS_OK(status)) {
2994 errcode = W_ERROR_V(ntstatus_to_werror(status));
2995 goto out;
2998 if (rids.count != 1) {
2999 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
3000 goto out;
3002 if (rids.count != types.count) {
3003 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3004 goto out;
3006 if (types.ids[0] != SID_NAME_USER) {
3007 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3008 goto out;
3011 rid = rids.ids[0];
3013 status = rpccli_samr_OpenUser(cli, mem_ctx,
3014 &domain_handle,
3015 SAMR_USER_ACCESS_CHANGE_PASSWORD,
3016 rid,
3017 &user_handle);
3018 if (!NT_STATUS_IS_OK(status)) {
3019 errcode = W_ERROR_V(ntstatus_to_werror(status));
3020 goto out;
3023 if (encrypted == 0) {
3024 E_deshash(pass1, old_lm_hash.hash);
3025 E_deshash(pass2, new_lm_hash.hash);
3026 } else {
3027 ZERO_STRUCT(old_lm_hash);
3028 ZERO_STRUCT(new_lm_hash);
3029 memcpy(old_lm_hash.hash, pass1, MIN(strlen(pass1), 16));
3030 memcpy(new_lm_hash.hash, pass1, MIN(strlen(pass2), 16));
3033 status = rpccli_samr_ChangePasswordUser(cli, mem_ctx,
3034 &user_handle,
3035 true, /* lm_present */
3036 &old_lm_hash,
3037 &new_lm_hash,
3038 false, /* nt_present */
3039 NULL, /* old_nt_crypted */
3040 NULL, /* new_nt_crypted */
3041 false, /* cross1_present */
3042 NULL, /* nt_cross */
3043 false, /* cross2_present */
3044 NULL); /* lm_cross */
3045 if (!NT_STATUS_IS_OK(status)) {
3046 errcode = W_ERROR_V(ntstatus_to_werror(status));
3047 goto out;
3050 errcode = NERR_Success;
3051 out:
3053 if (cli && is_valid_policy_hnd(&user_handle)) {
3054 rpccli_samr_Close(cli, mem_ctx, &user_handle);
3056 if (cli && is_valid_policy_hnd(&domain_handle)) {
3057 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
3059 if (cli && is_valid_policy_hnd(&connect_handle)) {
3060 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
3063 memset((char *)pass1,'\0',sizeof(fstring));
3064 memset((char *)pass2,'\0',sizeof(fstring));
3066 SSVAL(*rparam,0,errcode);
3067 SSVAL(*rparam,2,0); /* converter word */
3068 return(True);
3071 /****************************************************************************
3072 Set the user password (SamOEM version - gets plaintext).
3073 ****************************************************************************/
3075 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
3076 connection_struct *conn,uint16 vuid,
3077 char *param, int tpscnt,
3078 char *data, int tdscnt,
3079 int mdrcnt,int mprcnt,
3080 char **rdata,char **rparam,
3081 int *rdata_len,int *rparam_len)
3083 fstring user;
3084 char *p = get_safe_str_ptr(param,tpscnt,param,2);
3086 TALLOC_CTX *mem_ctx = talloc_tos();
3087 NTSTATUS status;
3088 struct rpc_pipe_client *cli = NULL;
3089 struct lsa_AsciiString server, account;
3090 struct samr_CryptPassword password;
3091 struct samr_Password hash;
3092 int errcode = NERR_badpass;
3093 int bufsize;
3095 *rparam_len = 4;
3096 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3097 if (!*rparam) {
3098 return False;
3101 if (!p) {
3102 return False;
3104 *rdata_len = 0;
3106 SSVAL(*rparam,0,NERR_badpass);
3109 * Check the parameter definition is correct.
3112 /* Do we have a string ? */
3113 if (skip_string(param,tpscnt,p) == 0) {
3114 return False;
3116 if(!strequal(p, "zsT")) {
3117 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3118 return False;
3120 p = skip_string(param, tpscnt, p);
3121 if (!p) {
3122 return False;
3125 /* Do we have a string ? */
3126 if (skip_string(param,tpscnt,p) == 0) {
3127 return False;
3129 if(!strequal(p, "B516B16")) {
3130 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3131 return False;
3133 p = skip_string(param,tpscnt,p);
3134 if (!p) {
3135 return False;
3137 /* Do we have a string ? */
3138 if (skip_string(param,tpscnt,p) == 0) {
3139 return False;
3141 p += pull_ascii_fstring(user,p);
3143 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3145 if (tdscnt != 532) {
3146 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3147 goto out;
3150 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3151 if (bufsize != 532) {
3152 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3153 goto out;
3156 memcpy(password.data, data, 516);
3157 memcpy(hash.hash, data+516, 16);
3159 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3160 conn->server_info,
3161 &conn->sconn->client_id,
3162 conn->sconn->msg_ctx,
3163 &cli);
3164 if (!NT_STATUS_IS_OK(status)) {
3165 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3166 nt_errstr(status)));
3167 errcode = W_ERROR_V(ntstatus_to_werror(status));
3168 goto out;
3171 init_lsa_AsciiString(&server, global_myname());
3172 init_lsa_AsciiString(&account, user);
3174 status = rpccli_samr_OemChangePasswordUser2(cli, mem_ctx,
3175 &server,
3176 &account,
3177 &password,
3178 &hash);
3179 if (!NT_STATUS_IS_OK(status)) {
3180 errcode = W_ERROR_V(ntstatus_to_werror(status));
3181 goto out;
3184 errcode = NERR_Success;
3185 out:
3186 SSVAL(*rparam,0,errcode);
3187 SSVAL(*rparam,2,0); /* converter word */
3189 return(True);
3192 /****************************************************************************
3193 delete a print job
3194 Form: <W> <>
3195 ****************************************************************************/
3197 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3198 connection_struct *conn,uint16 vuid,
3199 char *param, int tpscnt,
3200 char *data, int tdscnt,
3201 int mdrcnt,int mprcnt,
3202 char **rdata,char **rparam,
3203 int *rdata_len,int *rparam_len)
3205 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3206 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3207 char *str2 = skip_string(param,tpscnt,str1);
3208 char *p = skip_string(param,tpscnt,str2);
3209 uint32 jobid;
3210 fstring sharename;
3211 int errcode;
3212 WERROR werr = WERR_OK;
3214 TALLOC_CTX *mem_ctx = talloc_tos();
3215 NTSTATUS status;
3216 struct rpc_pipe_client *cli = NULL;
3217 struct policy_handle handle;
3218 struct spoolss_DevmodeContainer devmode_ctr;
3219 enum spoolss_JobControl command;
3221 if (!str1 || !str2 || !p) {
3222 return False;
3225 * We use 1 here not 2 as we're checking
3226 * the last byte we want to access is safe.
3228 if (!is_offset_safe(param,tpscnt,p,1)) {
3229 return False;
3231 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3232 return False;
3234 /* check it's a supported varient */
3235 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3236 return(False);
3238 *rparam_len = 4;
3239 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3240 if (!*rparam) {
3241 return False;
3243 *rdata_len = 0;
3245 ZERO_STRUCT(handle);
3247 status = rpc_pipe_open_interface(conn,
3248 &ndr_table_spoolss.syntax_id,
3249 conn->server_info,
3250 &conn->sconn->client_id,
3251 conn->sconn->msg_ctx,
3252 &cli);
3253 if (!NT_STATUS_IS_OK(status)) {
3254 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3255 nt_errstr(status)));
3256 errcode = W_ERROR_V(ntstatus_to_werror(status));
3257 goto out;
3260 ZERO_STRUCT(devmode_ctr);
3262 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3263 sharename,
3264 "RAW",
3265 devmode_ctr,
3266 JOB_ACCESS_ADMINISTER,
3267 &handle,
3268 &werr);
3269 if (!NT_STATUS_IS_OK(status)) {
3270 errcode = W_ERROR_V(ntstatus_to_werror(status));
3271 goto out;
3273 if (!W_ERROR_IS_OK(werr)) {
3274 errcode = W_ERROR_V(werr);
3275 goto out;
3278 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3279 * and NERR_DestNotFound if share did not exist */
3281 errcode = NERR_Success;
3283 switch (function) {
3284 case 81: /* delete */
3285 command = SPOOLSS_JOB_CONTROL_DELETE;
3286 break;
3287 case 82: /* pause */
3288 command = SPOOLSS_JOB_CONTROL_PAUSE;
3289 break;
3290 case 83: /* resume */
3291 command = SPOOLSS_JOB_CONTROL_RESUME;
3292 break;
3293 default:
3294 errcode = NERR_notsupported;
3295 goto out;
3298 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3299 &handle,
3300 jobid,
3301 NULL, /* unique ptr ctr */
3302 command,
3303 &werr);
3304 if (!NT_STATUS_IS_OK(status)) {
3305 errcode = W_ERROR_V(ntstatus_to_werror(status));
3306 goto out;
3308 if (!W_ERROR_IS_OK(werr)) {
3309 errcode = W_ERROR_V(werr);
3310 goto out;
3313 out:
3314 if (cli && is_valid_policy_hnd(&handle)) {
3315 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3318 SSVAL(*rparam,0,errcode);
3319 SSVAL(*rparam,2,0); /* converter word */
3321 return(True);
3324 /****************************************************************************
3325 Purge a print queue - or pause or resume it.
3326 ****************************************************************************/
3328 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3329 connection_struct *conn,uint16 vuid,
3330 char *param, int tpscnt,
3331 char *data, int tdscnt,
3332 int mdrcnt,int mprcnt,
3333 char **rdata,char **rparam,
3334 int *rdata_len,int *rparam_len)
3336 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3337 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3338 char *str2 = skip_string(param,tpscnt,str1);
3339 char *QueueName = skip_string(param,tpscnt,str2);
3340 int errcode = NERR_notsupported;
3341 WERROR werr = WERR_OK;
3342 NTSTATUS status;
3344 TALLOC_CTX *mem_ctx = talloc_tos();
3345 struct rpc_pipe_client *cli = NULL;
3346 struct policy_handle handle;
3347 struct spoolss_SetPrinterInfoCtr info_ctr;
3348 struct spoolss_DevmodeContainer devmode_ctr;
3349 struct sec_desc_buf secdesc_ctr;
3350 enum spoolss_PrinterControl command;
3352 if (!str1 || !str2 || !QueueName) {
3353 return False;
3356 /* check it's a supported varient */
3357 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3358 return(False);
3360 *rparam_len = 4;
3361 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3362 if (!*rparam) {
3363 return False;
3365 *rdata_len = 0;
3367 if (skip_string(param,tpscnt,QueueName) == NULL) {
3368 return False;
3371 ZERO_STRUCT(handle);
3373 status = rpc_pipe_open_interface(conn,
3374 &ndr_table_spoolss.syntax_id,
3375 conn->server_info,
3376 &conn->sconn->client_id,
3377 conn->sconn->msg_ctx,
3378 &cli);
3379 if (!NT_STATUS_IS_OK(status)) {
3380 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3381 nt_errstr(status)));
3382 errcode = W_ERROR_V(ntstatus_to_werror(status));
3383 goto out;
3386 ZERO_STRUCT(devmode_ctr);
3388 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3389 QueueName,
3390 NULL,
3391 devmode_ctr,
3392 SEC_FLAG_MAXIMUM_ALLOWED,
3393 &handle,
3394 &werr);
3395 if (!NT_STATUS_IS_OK(status)) {
3396 errcode = W_ERROR_V(ntstatus_to_werror(status));
3397 goto out;
3399 if (!W_ERROR_IS_OK(werr)) {
3400 errcode = W_ERROR_V(werr);
3401 goto out;
3404 switch (function) {
3405 case 74: /* Pause queue */
3406 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3407 break;
3408 case 75: /* Resume queue */
3409 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3410 break;
3411 case 103: /* Purge */
3412 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3413 break;
3414 default:
3415 werr = WERR_NOT_SUPPORTED;
3416 break;
3419 if (!W_ERROR_IS_OK(werr)) {
3420 errcode = W_ERROR_V(werr);
3421 goto out;
3424 ZERO_STRUCT(info_ctr);
3425 ZERO_STRUCT(secdesc_ctr);
3427 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3428 &handle,
3429 &info_ctr,
3430 &devmode_ctr,
3431 &secdesc_ctr,
3432 command,
3433 &werr);
3434 if (!NT_STATUS_IS_OK(status)) {
3435 errcode = W_ERROR_V(ntstatus_to_werror(status));
3436 goto out;
3438 if (!W_ERROR_IS_OK(werr)) {
3439 errcode = W_ERROR_V(werr);
3440 goto out;
3443 errcode = W_ERROR_V(werr);
3445 out:
3447 if (cli && is_valid_policy_hnd(&handle)) {
3448 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3451 SSVAL(*rparam,0,errcode);
3452 SSVAL(*rparam,2,0); /* converter word */
3454 return(True);
3457 /****************************************************************************
3458 set the property of a print job (undocumented?)
3459 ? function = 0xb -> set name of print job
3460 ? function = 0x6 -> move print job up/down
3461 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3462 or <WWsTP> <WB21BB16B10zWWzDDz>
3463 ****************************************************************************/
3465 static int check_printjob_info(struct pack_desc* desc,
3466 int uLevel, char* id)
3468 desc->subformat = NULL;
3469 switch( uLevel ) {
3470 case 0: desc->format = "W"; break;
3471 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3472 case 2: desc->format = "WWzWWDDzz"; break;
3473 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3474 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3475 default:
3476 DEBUG(0,("check_printjob_info: invalid level %d\n",
3477 uLevel ));
3478 return False;
3480 if (id == NULL || strcmp(desc->format,id) != 0) {
3481 DEBUG(0,("check_printjob_info: invalid format %s\n",
3482 id ? id : "<NULL>" ));
3483 return False;
3485 return True;
3488 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3489 connection_struct *conn, uint16 vuid,
3490 char *param, int tpscnt,
3491 char *data, int tdscnt,
3492 int mdrcnt,int mprcnt,
3493 char **rdata,char **rparam,
3494 int *rdata_len,int *rparam_len)
3496 struct pack_desc desc;
3497 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3498 char *str2 = skip_string(param,tpscnt,str1);
3499 char *p = skip_string(param,tpscnt,str2);
3500 uint32 jobid;
3501 fstring sharename;
3502 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3503 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3504 int errcode;
3506 TALLOC_CTX *mem_ctx = talloc_tos();
3507 WERROR werr;
3508 NTSTATUS status;
3509 struct rpc_pipe_client *cli = NULL;
3510 struct policy_handle handle;
3511 struct spoolss_DevmodeContainer devmode_ctr;
3512 struct spoolss_JobInfoContainer ctr;
3513 union spoolss_JobInfo info;
3514 struct spoolss_SetJobInfo1 info1;
3516 if (!str1 || !str2 || !p) {
3517 return False;
3520 * We use 1 here not 2 as we're checking
3521 * the last byte we want to access is safe.
3523 if (!is_offset_safe(param,tpscnt,p,1)) {
3524 return False;
3526 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3527 return False;
3528 *rparam_len = 4;
3529 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3530 if (!*rparam) {
3531 return False;
3534 *rdata_len = 0;
3536 /* check it's a supported varient */
3537 if ((strcmp(str1,"WWsTP")) ||
3538 (!check_printjob_info(&desc,uLevel,str2)))
3539 return(False);
3541 errcode = NERR_notsupported;
3543 switch (function) {
3544 case 0xb:
3545 /* change print job name, data gives the name */
3546 break;
3547 default:
3548 goto out;
3551 ZERO_STRUCT(handle);
3553 status = rpc_pipe_open_interface(conn,
3554 &ndr_table_spoolss.syntax_id,
3555 conn->server_info,
3556 &conn->sconn->client_id,
3557 conn->sconn->msg_ctx,
3558 &cli);
3559 if (!NT_STATUS_IS_OK(status)) {
3560 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3561 nt_errstr(status)));
3562 errcode = W_ERROR_V(ntstatus_to_werror(status));
3563 goto out;
3566 ZERO_STRUCT(devmode_ctr);
3568 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3569 sharename,
3570 "RAW",
3571 devmode_ctr,
3572 PRINTER_ACCESS_USE,
3573 &handle,
3574 &werr);
3575 if (!NT_STATUS_IS_OK(status)) {
3576 errcode = W_ERROR_V(ntstatus_to_werror(status));
3577 goto out;
3579 if (!W_ERROR_IS_OK(werr)) {
3580 errcode = W_ERROR_V(werr);
3581 goto out;
3584 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3585 &handle,
3586 jobid,
3587 1, /* level */
3588 0, /* offered */
3589 &info);
3590 if (!W_ERROR_IS_OK(werr)) {
3591 errcode = W_ERROR_V(werr);
3592 goto out;
3595 ZERO_STRUCT(ctr);
3597 info1.job_id = info.info1.job_id;
3598 info1.printer_name = info.info1.printer_name;
3599 info1.user_name = info.info1.user_name;
3600 info1.document_name = data;
3601 info1.data_type = info.info1.data_type;
3602 info1.text_status = info.info1.text_status;
3603 info1.status = info.info1.status;
3604 info1.priority = info.info1.priority;
3605 info1.position = info.info1.position;
3606 info1.total_pages = info.info1.total_pages;
3607 info1.pages_printed = info.info1.pages_printed;
3608 info1.submitted = info.info1.submitted;
3610 ctr.level = 1;
3611 ctr.info.info1 = &info1;
3613 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3614 &handle,
3615 jobid,
3616 &ctr,
3618 &werr);
3619 if (!NT_STATUS_IS_OK(status)) {
3620 errcode = W_ERROR_V(ntstatus_to_werror(status));
3621 goto out;
3623 if (!W_ERROR_IS_OK(werr)) {
3624 errcode = W_ERROR_V(werr);
3625 goto out;
3628 errcode = NERR_Success;
3629 out:
3631 if (cli && is_valid_policy_hnd(&handle)) {
3632 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3635 SSVALS(*rparam,0,errcode);
3636 SSVAL(*rparam,2,0); /* converter word */
3638 return(True);
3642 /****************************************************************************
3643 Get info about the server.
3644 ****************************************************************************/
3646 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3647 connection_struct *conn,uint16 vuid,
3648 char *param, int tpscnt,
3649 char *data, int tdscnt,
3650 int mdrcnt,int mprcnt,
3651 char **rdata,char **rparam,
3652 int *rdata_len,int *rparam_len)
3654 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3655 char *str2 = skip_string(param,tpscnt,str1);
3656 char *p = skip_string(param,tpscnt,str2);
3657 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3658 char *p2;
3659 int struct_len;
3661 NTSTATUS status;
3662 WERROR werr;
3663 TALLOC_CTX *mem_ctx = talloc_tos();
3664 struct rpc_pipe_client *cli = NULL;
3665 union srvsvc_NetSrvInfo info;
3666 int errcode;
3668 if (!str1 || !str2 || !p) {
3669 return False;
3672 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3674 /* check it's a supported varient */
3675 if (!prefix_ok(str1,"WrLh")) {
3676 return False;
3679 switch( uLevel ) {
3680 case 0:
3681 if (strcmp(str2,"B16") != 0) {
3682 return False;
3684 struct_len = 16;
3685 break;
3686 case 1:
3687 if (strcmp(str2,"B16BBDz") != 0) {
3688 return False;
3690 struct_len = 26;
3691 break;
3692 case 2:
3693 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3694 return False;
3696 struct_len = 134;
3697 break;
3698 case 3:
3699 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3700 return False;
3702 struct_len = 144;
3703 break;
3704 case 20:
3705 if (strcmp(str2,"DN") != 0) {
3706 return False;
3708 struct_len = 6;
3709 break;
3710 case 50:
3711 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3712 return False;
3714 struct_len = 42;
3715 break;
3716 default:
3717 return False;
3720 *rdata_len = mdrcnt;
3721 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3722 if (!*rdata) {
3723 return False;
3726 p = *rdata;
3727 p2 = p + struct_len;
3729 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3730 conn->server_info,
3731 &conn->sconn->client_id,
3732 conn->sconn->msg_ctx,
3733 &cli);
3734 if (!NT_STATUS_IS_OK(status)) {
3735 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3736 nt_errstr(status)));
3737 errcode = W_ERROR_V(ntstatus_to_werror(status));
3738 goto out;
3741 status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3742 NULL,
3743 101,
3744 &info,
3745 &werr);
3746 if (!NT_STATUS_IS_OK(status)) {
3747 errcode = W_ERROR_V(ntstatus_to_werror(status));
3748 goto out;
3750 if (!W_ERROR_IS_OK(werr)) {
3751 errcode = W_ERROR_V(werr);
3752 goto out;
3755 if (info.info101 == NULL) {
3756 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3757 goto out;
3760 if (uLevel != 20) {
3761 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3762 STR_ASCII|STR_UPPER|STR_TERMINATE);
3764 p += 16;
3765 if (uLevel > 0) {
3766 SCVAL(p,0,info.info101->version_major);
3767 SCVAL(p,1,info.info101->version_minor);
3768 SIVAL(p,2,info.info101->server_type);
3770 if (mdrcnt == struct_len) {
3771 SIVAL(p,6,0);
3772 } else {
3773 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3774 if (mdrcnt - struct_len <= 0) {
3775 return false;
3777 push_ascii(p2,
3778 info.info101->comment,
3779 MIN(mdrcnt - struct_len,
3780 MAX_SERVER_STRING_LENGTH),
3781 STR_TERMINATE);
3782 p2 = skip_string(*rdata,*rdata_len,p2);
3783 if (!p2) {
3784 return False;
3789 if (uLevel > 1) {
3790 return False; /* not yet implemented */
3793 errcode = NERR_Success;
3795 out:
3797 *rdata_len = PTR_DIFF(p2,*rdata);
3799 *rparam_len = 6;
3800 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3801 if (!*rparam) {
3802 return False;
3804 SSVAL(*rparam,0,errcode);
3805 SSVAL(*rparam,2,0); /* converter word */
3806 SSVAL(*rparam,4,*rdata_len);
3808 return True;
3811 /****************************************************************************
3812 Get info about the server.
3813 ****************************************************************************/
3815 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3816 connection_struct *conn,uint16 vuid,
3817 char *param, int tpscnt,
3818 char *data, int tdscnt,
3819 int mdrcnt,int mprcnt,
3820 char **rdata,char **rparam,
3821 int *rdata_len,int *rparam_len)
3823 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3824 char *str2 = skip_string(param,tpscnt,str1);
3825 char *p = skip_string(param,tpscnt,str2);
3826 char *p2;
3827 char *endp;
3828 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3830 if (!str1 || !str2 || !p) {
3831 return False;
3834 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3836 *rparam_len = 6;
3837 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3838 if (!*rparam) {
3839 return False;
3842 /* check it's a supported varient */
3843 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3844 return False;
3847 *rdata_len = mdrcnt + 1024;
3848 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3849 if (!*rdata) {
3850 return False;
3853 SSVAL(*rparam,0,NERR_Success);
3854 SSVAL(*rparam,2,0); /* converter word */
3856 p = *rdata;
3857 endp = *rdata + *rdata_len;
3859 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3860 if (!p2) {
3861 return False;
3864 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3865 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3866 strupper_m(p2);
3867 p2 = skip_string(*rdata,*rdata_len,p2);
3868 if (!p2) {
3869 return False;
3871 p += 4;
3873 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3874 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3875 p2 = skip_string(*rdata,*rdata_len,p2);
3876 if (!p2) {
3877 return False;
3879 p += 4;
3881 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3882 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3883 strupper_m(p2);
3884 p2 = skip_string(*rdata,*rdata_len,p2);
3885 if (!p2) {
3886 return False;
3888 p += 4;
3890 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3891 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3892 p += 2;
3894 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3895 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3896 p2 = skip_string(*rdata,*rdata_len,p2);
3897 if (!p2) {
3898 return False;
3900 p += 4;
3902 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3903 strlcpy(p2,"",PTR_DIFF(endp,p2));
3904 p2 = skip_string(*rdata,*rdata_len,p2);
3905 if (!p2) {
3906 return False;
3908 p += 4;
3910 *rdata_len = PTR_DIFF(p2,*rdata);
3912 SSVAL(*rparam,4,*rdata_len);
3914 return True;
3917 /****************************************************************************
3918 get info about a user
3920 struct user_info_11 {
3921 char usri11_name[21]; 0-20
3922 char usri11_pad; 21
3923 char *usri11_comment; 22-25
3924 char *usri11_usr_comment; 26-29
3925 unsigned short usri11_priv; 30-31
3926 unsigned long usri11_auth_flags; 32-35
3927 long usri11_password_age; 36-39
3928 char *usri11_homedir; 40-43
3929 char *usri11_parms; 44-47
3930 long usri11_last_logon; 48-51
3931 long usri11_last_logoff; 52-55
3932 unsigned short usri11_bad_pw_count; 56-57
3933 unsigned short usri11_num_logons; 58-59
3934 char *usri11_logon_server; 60-63
3935 unsigned short usri11_country_code; 64-65
3936 char *usri11_workstations; 66-69
3937 unsigned long usri11_max_storage; 70-73
3938 unsigned short usri11_units_per_week; 74-75
3939 unsigned char *usri11_logon_hours; 76-79
3940 unsigned short usri11_code_page; 80-81
3943 where:
3945 usri11_name specifies the user name for which information is retrieved
3947 usri11_pad aligns the next data structure element to a word boundary
3949 usri11_comment is a null terminated ASCII comment
3951 usri11_user_comment is a null terminated ASCII comment about the user
3953 usri11_priv specifies the level of the privilege assigned to the user.
3954 The possible values are:
3956 Name Value Description
3957 USER_PRIV_GUEST 0 Guest privilege
3958 USER_PRIV_USER 1 User privilege
3959 USER_PRV_ADMIN 2 Administrator privilege
3961 usri11_auth_flags specifies the account operator privileges. The
3962 possible values are:
3964 Name Value Description
3965 AF_OP_PRINT 0 Print operator
3968 Leach, Naik [Page 28]
3972 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3975 AF_OP_COMM 1 Communications operator
3976 AF_OP_SERVER 2 Server operator
3977 AF_OP_ACCOUNTS 3 Accounts operator
3980 usri11_password_age specifies how many seconds have elapsed since the
3981 password was last changed.
3983 usri11_home_dir points to a null terminated ASCII string that contains
3984 the path name of the user's home directory.
3986 usri11_parms points to a null terminated ASCII string that is set
3987 aside for use by applications.
3989 usri11_last_logon specifies the time when the user last logged on.
3990 This value is stored as the number of seconds elapsed since
3991 00:00:00, January 1, 1970.
3993 usri11_last_logoff specifies the time when the user last logged off.
3994 This value is stored as the number of seconds elapsed since
3995 00:00:00, January 1, 1970. A value of 0 means the last logoff
3996 time is unknown.
3998 usri11_bad_pw_count specifies the number of incorrect passwords
3999 entered since the last successful logon.
4001 usri11_log1_num_logons specifies the number of times this user has
4002 logged on. A value of -1 means the number of logons is unknown.
4004 usri11_logon_server points to a null terminated ASCII string that
4005 contains the name of the server to which logon requests are sent.
4006 A null string indicates logon requests should be sent to the
4007 domain controller.
4009 usri11_country_code specifies the country code for the user's language
4010 of choice.
4012 usri11_workstations points to a null terminated ASCII string that
4013 contains the names of workstations the user may log on from.
4014 There may be up to 8 workstations, with the names separated by
4015 commas. A null strings indicates there are no restrictions.
4017 usri11_max_storage specifies the maximum amount of disk space the user
4018 can occupy. A value of 0xffffffff indicates there are no
4019 restrictions.
4021 usri11_units_per_week specifies the equal number of time units into
4022 which a week is divided. This value must be equal to 168.
4024 usri11_logon_hours points to a 21 byte (168 bits) string that
4025 specifies the time during which the user can log on. Each bit
4026 represents one unique hour in a week. The first bit (bit 0, word
4027 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
4031 Leach, Naik [Page 29]
4035 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4038 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
4039 are no restrictions.
4041 usri11_code_page specifies the code page for the user's language of
4042 choice
4044 All of the pointers in this data structure need to be treated
4045 specially. The pointer is a 32 bit pointer. The higher 16 bits need
4046 to be ignored. The converter word returned in the parameters section
4047 needs to be subtracted from the lower 16 bits to calculate an offset
4048 into the return buffer where this ASCII string resides.
4050 There is no auxiliary data in the response.
4052 ****************************************************************************/
4054 #define usri11_name 0
4055 #define usri11_pad 21
4056 #define usri11_comment 22
4057 #define usri11_usr_comment 26
4058 #define usri11_full_name 30
4059 #define usri11_priv 34
4060 #define usri11_auth_flags 36
4061 #define usri11_password_age 40
4062 #define usri11_homedir 44
4063 #define usri11_parms 48
4064 #define usri11_last_logon 52
4065 #define usri11_last_logoff 56
4066 #define usri11_bad_pw_count 60
4067 #define usri11_num_logons 62
4068 #define usri11_logon_server 64
4069 #define usri11_country_code 68
4070 #define usri11_workstations 70
4071 #define usri11_max_storage 74
4072 #define usri11_units_per_week 78
4073 #define usri11_logon_hours 80
4074 #define usri11_code_page 84
4075 #define usri11_end 86
4077 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4078 connection_struct *conn, uint16 vuid,
4079 char *param, int tpscnt,
4080 char *data, int tdscnt,
4081 int mdrcnt,int mprcnt,
4082 char **rdata,char **rparam,
4083 int *rdata_len,int *rparam_len)
4085 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4086 char *str2 = skip_string(param,tpscnt,str1);
4087 char *UserName = skip_string(param,tpscnt,str2);
4088 char *p = skip_string(param,tpscnt,UserName);
4089 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4090 char *p2;
4091 char *endp;
4092 const char *level_string;
4094 TALLOC_CTX *mem_ctx = talloc_tos();
4095 NTSTATUS status;
4096 struct rpc_pipe_client *cli = NULL;
4097 struct policy_handle connect_handle, domain_handle, user_handle;
4098 struct lsa_String domain_name;
4099 struct dom_sid2 *domain_sid;
4100 struct lsa_String names;
4101 struct samr_Ids rids;
4102 struct samr_Ids types;
4103 int errcode = W_ERROR_V(WERR_USER_NOT_FOUND);
4104 uint32_t rid;
4105 union samr_UserInfo *info;
4107 if (!str1 || !str2 || !UserName || !p) {
4108 return False;
4111 *rparam_len = 6;
4112 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4113 if (!*rparam) {
4114 return False;
4117 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4119 /* check it's a supported variant */
4120 if (strcmp(str1,"zWrLh") != 0) {
4121 return False;
4123 switch( uLevel ) {
4124 case 0: level_string = "B21"; break;
4125 case 1: level_string = "B21BB16DWzzWz"; break;
4126 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4127 case 10: level_string = "B21Bzzz"; break;
4128 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4129 default: return False;
4132 if (strcmp(level_string,str2) != 0) {
4133 return False;
4136 *rdata_len = mdrcnt + 1024;
4137 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4138 if (!*rdata) {
4139 return False;
4142 p = *rdata;
4143 endp = *rdata + *rdata_len;
4144 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4145 if (!p2) {
4146 return False;
4149 ZERO_STRUCT(connect_handle);
4150 ZERO_STRUCT(domain_handle);
4151 ZERO_STRUCT(user_handle);
4153 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
4154 conn->server_info,
4155 &conn->sconn->client_id,
4156 conn->sconn->msg_ctx,
4157 &cli);
4158 if (!NT_STATUS_IS_OK(status)) {
4159 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4160 nt_errstr(status)));
4161 errcode = W_ERROR_V(ntstatus_to_werror(status));
4162 goto out;
4165 status = rpccli_samr_Connect2(cli, mem_ctx,
4166 global_myname(),
4167 SAMR_ACCESS_CONNECT_TO_SERVER |
4168 SAMR_ACCESS_ENUM_DOMAINS |
4169 SAMR_ACCESS_LOOKUP_DOMAIN,
4170 &connect_handle);
4171 if (!NT_STATUS_IS_OK(status)) {
4172 errcode = W_ERROR_V(ntstatus_to_werror(status));
4173 goto out;
4176 init_lsa_String(&domain_name, get_global_sam_name());
4178 status = rpccli_samr_LookupDomain(cli, mem_ctx,
4179 &connect_handle,
4180 &domain_name,
4181 &domain_sid);
4182 if (!NT_STATUS_IS_OK(status)) {
4183 errcode = W_ERROR_V(ntstatus_to_werror(status));
4184 goto out;
4187 status = rpccli_samr_OpenDomain(cli, mem_ctx,
4188 &connect_handle,
4189 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4190 domain_sid,
4191 &domain_handle);
4192 if (!NT_STATUS_IS_OK(status)) {
4193 errcode = W_ERROR_V(ntstatus_to_werror(status));
4194 goto out;
4197 init_lsa_String(&names, UserName);
4199 status = rpccli_samr_LookupNames(cli, mem_ctx,
4200 &domain_handle,
4202 &names,
4203 &rids,
4204 &types);
4205 if (!NT_STATUS_IS_OK(status)) {
4206 errcode = W_ERROR_V(ntstatus_to_werror(status));
4207 goto out;
4210 if (rids.count != 1) {
4211 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4212 goto out;
4214 if (rids.count != types.count) {
4215 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4216 goto out;
4218 if (types.ids[0] != SID_NAME_USER) {
4219 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4220 goto out;
4223 rid = rids.ids[0];
4225 status = rpccli_samr_OpenUser(cli, mem_ctx,
4226 &domain_handle,
4227 SAMR_USER_ACCESS_GET_LOCALE |
4228 SAMR_USER_ACCESS_GET_LOGONINFO |
4229 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4230 SAMR_USER_ACCESS_GET_GROUPS |
4231 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4232 SEC_STD_READ_CONTROL,
4233 rid,
4234 &user_handle);
4235 if (!NT_STATUS_IS_OK(status)) {
4236 errcode = W_ERROR_V(ntstatus_to_werror(status));
4237 goto out;
4240 status = rpccli_samr_QueryUserInfo2(cli, mem_ctx,
4241 &user_handle,
4242 UserAllInformation,
4243 &info);
4244 if (!NT_STATUS_IS_OK(status)) {
4245 errcode = W_ERROR_V(ntstatus_to_werror(status));
4246 goto out;
4249 memset(p,0,21);
4250 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4252 if (uLevel > 0) {
4253 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4254 *p2 = 0;
4257 if (uLevel >= 10) {
4258 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4259 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4260 p2 = skip_string(*rdata,*rdata_len,p2);
4261 if (!p2) {
4262 return False;
4265 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4266 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4267 p2 = skip_string(*rdata,*rdata_len,p2);
4268 if (!p2) {
4269 return False;
4272 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4273 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4274 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4275 p2 = skip_string(*rdata,*rdata_len,p2);
4276 if (!p2) {
4277 return False;
4281 if (uLevel == 11) {
4282 const char *homedir = info->info21.home_directory.string;
4283 /* modelled after NTAS 3.51 reply */
4284 SSVAL(p,usri11_priv,
4285 (get_current_uid(conn) == sec_initial_uid())?
4286 USER_PRIV_ADMIN:USER_PRIV_USER);
4287 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4288 SIVALS(p,usri11_password_age,-1); /* password age */
4289 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4290 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4291 p2 = skip_string(*rdata,*rdata_len,p2);
4292 if (!p2) {
4293 return False;
4295 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4296 strlcpy(p2,"",PTR_DIFF(endp,p2));
4297 p2 = skip_string(*rdata,*rdata_len,p2);
4298 if (!p2) {
4299 return False;
4301 SIVAL(p,usri11_last_logon,0); /* last logon */
4302 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4303 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4304 SSVALS(p,usri11_num_logons,-1); /* num logons */
4305 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4306 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4307 p2 = skip_string(*rdata,*rdata_len,p2);
4308 if (!p2) {
4309 return False;
4311 SSVAL(p,usri11_country_code,0); /* country code */
4313 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4314 strlcpy(p2,"",PTR_DIFF(endp,p2));
4315 p2 = skip_string(*rdata,*rdata_len,p2);
4316 if (!p2) {
4317 return False;
4320 SIVALS(p,usri11_max_storage,-1); /* max storage */
4321 SSVAL(p,usri11_units_per_week,168); /* units per week */
4322 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4324 /* a simple way to get logon hours at all times. */
4325 memset(p2,0xff,21);
4326 SCVAL(p2,21,0); /* fix zero termination */
4327 p2 = skip_string(*rdata,*rdata_len,p2);
4328 if (!p2) {
4329 return False;
4332 SSVAL(p,usri11_code_page,0); /* code page */
4335 if (uLevel == 1 || uLevel == 2) {
4336 memset(p+22,' ',16); /* password */
4337 SIVALS(p,38,-1); /* password age */
4338 SSVAL(p,42,
4339 (get_current_uid(conn) == sec_initial_uid())?
4340 USER_PRIV_ADMIN:USER_PRIV_USER);
4341 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4342 strlcpy(p2, info->info21.home_directory.string,
4343 PTR_DIFF(endp,p2));
4344 p2 = skip_string(*rdata,*rdata_len,p2);
4345 if (!p2) {
4346 return False;
4348 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4349 *p2++ = 0;
4350 SSVAL(p,52,0); /* flags */
4351 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4352 strlcpy(p2, info->info21.logon_script.string,
4353 PTR_DIFF(endp,p2));
4354 p2 = skip_string(*rdata,*rdata_len,p2);
4355 if (!p2) {
4356 return False;
4358 if (uLevel == 2) {
4359 SIVAL(p,58,0); /* auth_flags */
4360 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4361 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4362 p2 = skip_string(*rdata,*rdata_len,p2);
4363 if (!p2) {
4364 return False;
4366 SIVAL(p,66,0); /* urs_comment */
4367 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4368 strlcpy(p2,"",PTR_DIFF(endp,p2));
4369 p2 = skip_string(*rdata,*rdata_len,p2);
4370 if (!p2) {
4371 return False;
4373 SIVAL(p,74,0); /* workstations */
4374 SIVAL(p,78,0); /* last_logon */
4375 SIVAL(p,82,0); /* last_logoff */
4376 SIVALS(p,86,-1); /* acct_expires */
4377 SIVALS(p,90,-1); /* max_storage */
4378 SSVAL(p,94,168); /* units_per_week */
4379 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4380 memset(p2,-1,21);
4381 p2 += 21;
4382 SSVALS(p,100,-1); /* bad_pw_count */
4383 SSVALS(p,102,-1); /* num_logons */
4384 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4386 TALLOC_CTX *ctx = talloc_tos();
4387 int space_rem = *rdata_len - (p2 - *rdata);
4388 char *tmp;
4390 if (space_rem <= 0) {
4391 return false;
4393 tmp = talloc_strdup(ctx, "\\\\%L");
4394 if (!tmp) {
4395 return false;
4397 tmp = talloc_sub_basic(ctx,
4400 tmp);
4401 if (!tmp) {
4402 return false;
4405 push_ascii(p2,
4406 tmp,
4407 space_rem,
4408 STR_TERMINATE);
4410 p2 = skip_string(*rdata,*rdata_len,p2);
4411 if (!p2) {
4412 return False;
4414 SSVAL(p,108,49); /* country_code */
4415 SSVAL(p,110,860); /* code page */
4419 errcode = NERR_Success;
4421 out:
4422 *rdata_len = PTR_DIFF(p2,*rdata);
4424 if (cli && is_valid_policy_hnd(&user_handle)) {
4425 rpccli_samr_Close(cli, mem_ctx, &user_handle);
4427 if (cli && is_valid_policy_hnd(&domain_handle)) {
4428 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
4430 if (cli && is_valid_policy_hnd(&connect_handle)) {
4431 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
4434 SSVAL(*rparam,0,errcode);
4435 SSVAL(*rparam,2,0); /* converter word */
4436 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4438 return(True);
4441 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4442 connection_struct *conn,uint16 vuid,
4443 char *param, int tpscnt,
4444 char *data, int tdscnt,
4445 int mdrcnt,int mprcnt,
4446 char **rdata,char **rparam,
4447 int *rdata_len,int *rparam_len)
4449 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4450 char *str2 = skip_string(param,tpscnt,str1);
4451 char *p = skip_string(param,tpscnt,str2);
4452 int uLevel;
4453 struct pack_desc desc;
4454 char* name;
4455 /* With share level security vuid will always be zero.
4456 Don't depend on vuser being non-null !!. JRA */
4457 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4459 if (!str1 || !str2 || !p) {
4460 return False;
4463 if(vuser != NULL) {
4464 DEBUG(3,(" Username of UID %d is %s\n",
4465 (int)vuser->server_info->utok.uid,
4466 vuser->server_info->unix_name));
4469 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4470 name = get_safe_str_ptr(param,tpscnt,p,2);
4471 if (!name) {
4472 return False;
4475 memset((char *)&desc,'\0',sizeof(desc));
4477 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4479 /* check it's a supported varient */
4480 if (strcmp(str1,"OOWb54WrLh") != 0) {
4481 return False;
4483 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4484 return False;
4486 if (mdrcnt > 0) {
4487 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4488 if (!*rdata) {
4489 return False;
4493 desc.base = *rdata;
4494 desc.buflen = mdrcnt;
4495 desc.subformat = NULL;
4496 desc.format = str2;
4498 if (init_package(&desc,1,0)) {
4499 PACKI(&desc,"W",0); /* code */
4500 PACKS(&desc,"B21",name); /* eff. name */
4501 PACKS(&desc,"B",""); /* pad */
4502 PACKI(&desc,"W",
4503 (get_current_uid(conn) == sec_initial_uid())?
4504 USER_PRIV_ADMIN:USER_PRIV_USER);
4505 PACKI(&desc,"D",0); /* auth flags XXX */
4506 PACKI(&desc,"W",0); /* num logons */
4507 PACKI(&desc,"W",0); /* bad pw count */
4508 PACKI(&desc,"D",0); /* last logon */
4509 PACKI(&desc,"D",-1); /* last logoff */
4510 PACKI(&desc,"D",-1); /* logoff time */
4511 PACKI(&desc,"D",-1); /* kickoff time */
4512 PACKI(&desc,"D",0); /* password age */
4513 PACKI(&desc,"D",0); /* password can change */
4514 PACKI(&desc,"D",-1); /* password must change */
4517 fstring mypath;
4518 fstrcpy(mypath,"\\\\");
4519 fstrcat(mypath,get_local_machine_name());
4520 strupper_m(mypath);
4521 PACKS(&desc,"z",mypath); /* computer */
4524 PACKS(&desc,"z",lp_workgroup());/* domain */
4525 PACKS(&desc,"z", vuser ?
4526 vuser->server_info->info3->base.logon_script.string
4527 : ""); /* script path */
4528 PACKI(&desc,"D",0x00000000); /* reserved */
4531 *rdata_len = desc.usedlen;
4532 *rparam_len = 6;
4533 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4534 if (!*rparam) {
4535 return False;
4537 SSVALS(*rparam,0,desc.errcode);
4538 SSVAL(*rparam,2,0);
4539 SSVAL(*rparam,4,desc.neededlen);
4541 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4543 return True;
4546 /****************************************************************************
4547 api_WAccessGetUserPerms
4548 ****************************************************************************/
4550 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4551 connection_struct *conn,uint16 vuid,
4552 char *param, int tpscnt,
4553 char *data, int tdscnt,
4554 int mdrcnt,int mprcnt,
4555 char **rdata,char **rparam,
4556 int *rdata_len,int *rparam_len)
4558 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4559 char *str2 = skip_string(param,tpscnt,str1);
4560 char *user = skip_string(param,tpscnt,str2);
4561 char *resource = skip_string(param,tpscnt,user);
4563 if (!str1 || !str2 || !user || !resource) {
4564 return False;
4567 if (skip_string(param,tpscnt,resource) == NULL) {
4568 return False;
4570 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4572 /* check it's a supported varient */
4573 if (strcmp(str1,"zzh") != 0) {
4574 return False;
4576 if (strcmp(str2,"") != 0) {
4577 return False;
4580 *rparam_len = 6;
4581 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4582 if (!*rparam) {
4583 return False;
4585 SSVALS(*rparam,0,0); /* errorcode */
4586 SSVAL(*rparam,2,0); /* converter word */
4587 SSVAL(*rparam,4,0x7f); /* permission flags */
4589 return True;
4592 /****************************************************************************
4593 api_WPrintJobEnumerate
4594 ****************************************************************************/
4596 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4597 connection_struct *conn, uint16 vuid,
4598 char *param, int tpscnt,
4599 char *data, int tdscnt,
4600 int mdrcnt,int mprcnt,
4601 char **rdata,char **rparam,
4602 int *rdata_len,int *rparam_len)
4604 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4605 char *str2 = skip_string(param,tpscnt,str1);
4606 char *p = skip_string(param,tpscnt,str2);
4607 int uLevel;
4608 fstring sharename;
4609 uint32 jobid;
4610 struct pack_desc desc;
4611 char *tmpdata=NULL;
4613 TALLOC_CTX *mem_ctx = talloc_tos();
4614 WERROR werr;
4615 NTSTATUS status;
4616 struct rpc_pipe_client *cli = NULL;
4617 struct policy_handle handle;
4618 struct spoolss_DevmodeContainer devmode_ctr;
4619 union spoolss_JobInfo info;
4621 if (!str1 || !str2 || !p) {
4622 return False;
4625 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4627 memset((char *)&desc,'\0',sizeof(desc));
4628 memset((char *)&status,'\0',sizeof(status));
4630 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4632 /* check it's a supported varient */
4633 if (strcmp(str1,"WWrLh") != 0) {
4634 return False;
4636 if (!check_printjob_info(&desc,uLevel,str2)) {
4637 return False;
4640 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4641 return False;
4644 ZERO_STRUCT(handle);
4646 status = rpc_pipe_open_interface(conn,
4647 &ndr_table_spoolss.syntax_id,
4648 conn->server_info,
4649 &conn->sconn->client_id,
4650 conn->sconn->msg_ctx,
4651 &cli);
4652 if (!NT_STATUS_IS_OK(status)) {
4653 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4654 nt_errstr(status)));
4655 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4656 goto out;
4659 ZERO_STRUCT(devmode_ctr);
4661 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4662 sharename,
4663 "RAW",
4664 devmode_ctr,
4665 PRINTER_ACCESS_USE,
4666 &handle,
4667 &werr);
4668 if (!NT_STATUS_IS_OK(status)) {
4669 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4670 goto out;
4672 if (!W_ERROR_IS_OK(werr)) {
4673 desc.errcode = W_ERROR_V(werr);
4674 goto out;
4677 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4678 &handle,
4679 jobid,
4680 2, /* level */
4681 0, /* offered */
4682 &info);
4683 if (!W_ERROR_IS_OK(werr)) {
4684 desc.errcode = W_ERROR_V(werr);
4685 goto out;
4688 if (mdrcnt > 0) {
4689 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4690 if (!*rdata) {
4691 return False;
4693 desc.base = *rdata;
4694 desc.buflen = mdrcnt;
4695 } else {
4697 * Don't return data but need to get correct length
4698 * init_package will return wrong size if buflen=0
4700 desc.buflen = getlen(desc.format);
4701 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4704 if (init_package(&desc,1,0)) {
4705 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4706 *rdata_len = desc.usedlen;
4707 } else {
4708 desc.errcode = NERR_JobNotFound;
4709 *rdata_len = 0;
4711 out:
4712 if (cli && is_valid_policy_hnd(&handle)) {
4713 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4716 *rparam_len = 6;
4717 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4718 if (!*rparam) {
4719 return False;
4721 SSVALS(*rparam,0,desc.errcode);
4722 SSVAL(*rparam,2,0);
4723 SSVAL(*rparam,4,desc.neededlen);
4725 SAFE_FREE(tmpdata);
4727 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4729 return True;
4732 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4733 connection_struct *conn, uint16 vuid,
4734 char *param, int tpscnt,
4735 char *data, int tdscnt,
4736 int mdrcnt,int mprcnt,
4737 char **rdata,char **rparam,
4738 int *rdata_len,int *rparam_len)
4740 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4741 char *str2 = skip_string(param,tpscnt,str1);
4742 char *p = skip_string(param,tpscnt,str2);
4743 char *name = p;
4744 int uLevel;
4745 int i, succnt=0;
4746 struct pack_desc desc;
4748 TALLOC_CTX *mem_ctx = talloc_tos();
4749 WERROR werr;
4750 NTSTATUS status;
4751 struct rpc_pipe_client *cli = NULL;
4752 struct policy_handle handle;
4753 struct spoolss_DevmodeContainer devmode_ctr;
4754 uint32_t count = 0;
4755 union spoolss_JobInfo *info;
4757 if (!str1 || !str2 || !p) {
4758 return False;
4761 memset((char *)&desc,'\0',sizeof(desc));
4763 p = skip_string(param,tpscnt,p);
4764 if (!p) {
4765 return False;
4767 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4769 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4771 /* check it's a supported variant */
4772 if (strcmp(str1,"zWrLeh") != 0) {
4773 return False;
4776 if (uLevel > 2) {
4777 return False; /* defined only for uLevel 0,1,2 */
4780 if (!check_printjob_info(&desc,uLevel,str2)) {
4781 return False;
4784 ZERO_STRUCT(handle);
4786 status = rpc_pipe_open_interface(conn,
4787 &ndr_table_spoolss.syntax_id,
4788 conn->server_info,
4789 &conn->sconn->client_id,
4790 conn->sconn->msg_ctx,
4791 &cli);
4792 if (!NT_STATUS_IS_OK(status)) {
4793 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4794 nt_errstr(status)));
4795 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4796 goto out;
4799 ZERO_STRUCT(devmode_ctr);
4801 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4802 name,
4803 NULL,
4804 devmode_ctr,
4805 SEC_FLAG_MAXIMUM_ALLOWED,
4806 &handle,
4807 &werr);
4808 if (!NT_STATUS_IS_OK(status)) {
4809 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4810 goto out;
4812 if (!W_ERROR_IS_OK(werr)) {
4813 desc.errcode = W_ERROR_V(werr);
4814 goto out;
4817 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4818 &handle,
4819 0, /* firstjob */
4820 0xff, /* numjobs */
4821 2, /* level */
4822 0, /* offered */
4823 &count,
4824 &info);
4825 if (!W_ERROR_IS_OK(werr)) {
4826 desc.errcode = W_ERROR_V(werr);
4827 goto out;
4830 if (mdrcnt > 0) {
4831 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4832 if (!*rdata) {
4833 return False;
4836 desc.base = *rdata;
4837 desc.buflen = mdrcnt;
4839 if (init_package(&desc,count,0)) {
4840 succnt = 0;
4841 for (i = 0; i < count; i++) {
4842 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4843 if (desc.errcode == NERR_Success) {
4844 succnt = i+1;
4848 out:
4849 if (cli && is_valid_policy_hnd(&handle)) {
4850 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4853 *rdata_len = desc.usedlen;
4855 *rparam_len = 8;
4856 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4857 if (!*rparam) {
4858 return False;
4860 SSVALS(*rparam,0,desc.errcode);
4861 SSVAL(*rparam,2,0);
4862 SSVAL(*rparam,4,succnt);
4863 SSVAL(*rparam,6,count);
4865 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4867 return True;
4870 static int check_printdest_info(struct pack_desc* desc,
4871 int uLevel, char* id)
4873 desc->subformat = NULL;
4874 switch( uLevel ) {
4875 case 0:
4876 desc->format = "B9";
4877 break;
4878 case 1:
4879 desc->format = "B9B21WWzW";
4880 break;
4881 case 2:
4882 desc->format = "z";
4883 break;
4884 case 3:
4885 desc->format = "zzzWWzzzWW";
4886 break;
4887 default:
4888 DEBUG(0,("check_printdest_info: invalid level %d\n",
4889 uLevel));
4890 return False;
4892 if (id == NULL || strcmp(desc->format,id) != 0) {
4893 DEBUG(0,("check_printdest_info: invalid string %s\n",
4894 id ? id : "<NULL>" ));
4895 return False;
4897 return True;
4900 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4901 struct pack_desc* desc)
4903 char buf[100];
4905 strncpy(buf, info2->printername, sizeof(buf)-1);
4906 buf[sizeof(buf)-1] = 0;
4907 strupper_m(buf);
4909 if (uLevel <= 1) {
4910 PACKS(desc,"B9",buf); /* szName */
4911 if (uLevel == 1) {
4912 PACKS(desc,"B21",""); /* szUserName */
4913 PACKI(desc,"W",0); /* uJobId */
4914 PACKI(desc,"W",0); /* fsStatus */
4915 PACKS(desc,"z",""); /* pszStatus */
4916 PACKI(desc,"W",0); /* time */
4920 if (uLevel == 2 || uLevel == 3) {
4921 PACKS(desc,"z",buf); /* pszPrinterName */
4922 if (uLevel == 3) {
4923 PACKS(desc,"z",""); /* pszUserName */
4924 PACKS(desc,"z",""); /* pszLogAddr */
4925 PACKI(desc,"W",0); /* uJobId */
4926 PACKI(desc,"W",0); /* fsStatus */
4927 PACKS(desc,"z",""); /* pszStatus */
4928 PACKS(desc,"z",""); /* pszComment */
4929 PACKS(desc,"z","NULL"); /* pszDrivers */
4930 PACKI(desc,"W",0); /* time */
4931 PACKI(desc,"W",0); /* pad1 */
4936 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4937 connection_struct *conn, uint16 vuid,
4938 char *param, int tpscnt,
4939 char *data, int tdscnt,
4940 int mdrcnt,int mprcnt,
4941 char **rdata,char **rparam,
4942 int *rdata_len,int *rparam_len)
4944 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4945 char *str2 = skip_string(param,tpscnt,str1);
4946 char *p = skip_string(param,tpscnt,str2);
4947 char* PrinterName = p;
4948 int uLevel;
4949 struct pack_desc desc;
4950 char *tmpdata=NULL;
4952 TALLOC_CTX *mem_ctx = talloc_tos();
4953 WERROR werr;
4954 NTSTATUS status;
4955 struct rpc_pipe_client *cli = NULL;
4956 struct policy_handle handle;
4957 struct spoolss_DevmodeContainer devmode_ctr;
4958 union spoolss_PrinterInfo info;
4960 if (!str1 || !str2 || !p) {
4961 return False;
4964 memset((char *)&desc,'\0',sizeof(desc));
4966 p = skip_string(param,tpscnt,p);
4967 if (!p) {
4968 return False;
4970 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4972 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4974 /* check it's a supported varient */
4975 if (strcmp(str1,"zWrLh") != 0) {
4976 return False;
4978 if (!check_printdest_info(&desc,uLevel,str2)) {
4979 return False;
4982 ZERO_STRUCT(handle);
4984 status = rpc_pipe_open_interface(conn,
4985 &ndr_table_spoolss.syntax_id,
4986 conn->server_info,
4987 &conn->sconn->client_id,
4988 conn->sconn->msg_ctx,
4989 &cli);
4990 if (!NT_STATUS_IS_OK(status)) {
4991 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4992 nt_errstr(status)));
4993 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4994 goto out;
4997 ZERO_STRUCT(devmode_ctr);
4999 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
5000 PrinterName,
5001 NULL,
5002 devmode_ctr,
5003 SEC_FLAG_MAXIMUM_ALLOWED,
5004 &handle,
5005 &werr);
5006 if (!NT_STATUS_IS_OK(status)) {
5007 *rdata_len = 0;
5008 desc.errcode = NERR_DestNotFound;
5009 desc.neededlen = 0;
5010 goto out;
5012 if (!W_ERROR_IS_OK(werr)) {
5013 *rdata_len = 0;
5014 desc.errcode = NERR_DestNotFound;
5015 desc.neededlen = 0;
5016 goto out;
5019 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
5020 &handle,
5023 &info);
5024 if (!W_ERROR_IS_OK(werr)) {
5025 *rdata_len = 0;
5026 desc.errcode = NERR_DestNotFound;
5027 desc.neededlen = 0;
5028 goto out;
5031 if (mdrcnt > 0) {
5032 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5033 if (!*rdata) {
5034 return False;
5036 desc.base = *rdata;
5037 desc.buflen = mdrcnt;
5038 } else {
5040 * Don't return data but need to get correct length
5041 * init_package will return wrong size if buflen=0
5043 desc.buflen = getlen(desc.format);
5044 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
5046 if (init_package(&desc,1,0)) {
5047 fill_printdest_info(&info.info2, uLevel,&desc);
5050 out:
5051 if (cli && is_valid_policy_hnd(&handle)) {
5052 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
5055 *rdata_len = desc.usedlen;
5057 *rparam_len = 6;
5058 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5059 if (!*rparam) {
5060 return False;
5062 SSVALS(*rparam,0,desc.errcode);
5063 SSVAL(*rparam,2,0);
5064 SSVAL(*rparam,4,desc.neededlen);
5066 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5067 SAFE_FREE(tmpdata);
5069 return True;
5072 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5073 connection_struct *conn, uint16 vuid,
5074 char *param, int tpscnt,
5075 char *data, int tdscnt,
5076 int mdrcnt,int mprcnt,
5077 char **rdata,char **rparam,
5078 int *rdata_len,int *rparam_len)
5080 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5081 char *str2 = skip_string(param,tpscnt,str1);
5082 char *p = skip_string(param,tpscnt,str2);
5083 int uLevel;
5084 int queuecnt;
5085 int i, n, succnt=0;
5086 struct pack_desc desc;
5088 TALLOC_CTX *mem_ctx = talloc_tos();
5089 WERROR werr;
5090 NTSTATUS status;
5091 struct rpc_pipe_client *cli = NULL;
5092 union spoolss_PrinterInfo *info;
5093 uint32_t count;
5095 if (!str1 || !str2 || !p) {
5096 return False;
5099 memset((char *)&desc,'\0',sizeof(desc));
5101 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5103 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5105 /* check it's a supported varient */
5106 if (strcmp(str1,"WrLeh") != 0) {
5107 return False;
5109 if (!check_printdest_info(&desc,uLevel,str2)) {
5110 return False;
5113 queuecnt = 0;
5115 status = rpc_pipe_open_interface(conn,
5116 &ndr_table_spoolss.syntax_id,
5117 conn->server_info,
5118 &conn->sconn->client_id,
5119 conn->sconn->msg_ctx,
5120 &cli);
5121 if (!NT_STATUS_IS_OK(status)) {
5122 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5123 nt_errstr(status)));
5124 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5125 goto out;
5128 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5129 PRINTER_ENUM_LOCAL,
5130 cli->srv_name_slash,
5133 &count,
5134 &info);
5135 if (!W_ERROR_IS_OK(werr)) {
5136 desc.errcode = W_ERROR_V(werr);
5137 *rdata_len = 0;
5138 desc.errcode = NERR_DestNotFound;
5139 desc.neededlen = 0;
5140 goto out;
5143 queuecnt = count;
5145 if (mdrcnt > 0) {
5146 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5147 if (!*rdata) {
5148 return False;
5152 desc.base = *rdata;
5153 desc.buflen = mdrcnt;
5154 if (init_package(&desc,queuecnt,0)) {
5155 succnt = 0;
5156 n = 0;
5157 for (i = 0; i < count; i++) {
5158 fill_printdest_info(&info[i].info2, uLevel,&desc);
5159 n++;
5160 if (desc.errcode == NERR_Success) {
5161 succnt = n;
5165 out:
5166 *rdata_len = desc.usedlen;
5168 *rparam_len = 8;
5169 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5170 if (!*rparam) {
5171 return False;
5173 SSVALS(*rparam,0,desc.errcode);
5174 SSVAL(*rparam,2,0);
5175 SSVAL(*rparam,4,succnt);
5176 SSVAL(*rparam,6,queuecnt);
5178 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5180 return True;
5183 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5184 connection_struct *conn, uint16 vuid,
5185 char *param, int tpscnt,
5186 char *data, int tdscnt,
5187 int mdrcnt,int mprcnt,
5188 char **rdata,char **rparam,
5189 int *rdata_len,int *rparam_len)
5191 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5192 char *str2 = skip_string(param,tpscnt,str1);
5193 char *p = skip_string(param,tpscnt,str2);
5194 int uLevel;
5195 int succnt;
5196 struct pack_desc desc;
5198 if (!str1 || !str2 || !p) {
5199 return False;
5202 memset((char *)&desc,'\0',sizeof(desc));
5204 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5206 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5208 /* check it's a supported varient */
5209 if (strcmp(str1,"WrLeh") != 0) {
5210 return False;
5212 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5213 return False;
5216 if (mdrcnt > 0) {
5217 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5218 if (!*rdata) {
5219 return False;
5222 desc.base = *rdata;
5223 desc.buflen = mdrcnt;
5224 if (init_package(&desc,1,0)) {
5225 PACKS(&desc,"B41","NULL");
5228 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5230 *rdata_len = desc.usedlen;
5232 *rparam_len = 8;
5233 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5234 if (!*rparam) {
5235 return False;
5237 SSVALS(*rparam,0,desc.errcode);
5238 SSVAL(*rparam,2,0);
5239 SSVAL(*rparam,4,succnt);
5240 SSVAL(*rparam,6,1);
5242 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5244 return True;
5247 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5248 connection_struct *conn, uint16 vuid,
5249 char *param, int tpscnt,
5250 char *data, int tdscnt,
5251 int mdrcnt,int mprcnt,
5252 char **rdata,char **rparam,
5253 int *rdata_len,int *rparam_len)
5255 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5256 char *str2 = skip_string(param,tpscnt,str1);
5257 char *p = skip_string(param,tpscnt,str2);
5258 int uLevel;
5259 int succnt;
5260 struct pack_desc desc;
5262 if (!str1 || !str2 || !p) {
5263 return False;
5265 memset((char *)&desc,'\0',sizeof(desc));
5267 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5269 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5271 /* check it's a supported varient */
5272 if (strcmp(str1,"WrLeh") != 0) {
5273 return False;
5275 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5276 return False;
5279 if (mdrcnt > 0) {
5280 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5281 if (!*rdata) {
5282 return False;
5285 desc.base = *rdata;
5286 desc.buflen = mdrcnt;
5287 desc.format = str2;
5288 if (init_package(&desc,1,0)) {
5289 PACKS(&desc,"B13","lpd");
5292 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5294 *rdata_len = desc.usedlen;
5296 *rparam_len = 8;
5297 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5298 if (!*rparam) {
5299 return False;
5301 SSVALS(*rparam,0,desc.errcode);
5302 SSVAL(*rparam,2,0);
5303 SSVAL(*rparam,4,succnt);
5304 SSVAL(*rparam,6,1);
5306 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5308 return True;
5311 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5312 connection_struct *conn, uint16 vuid,
5313 char *param, int tpscnt,
5314 char *data, int tdscnt,
5315 int mdrcnt,int mprcnt,
5316 char **rdata,char **rparam,
5317 int *rdata_len,int *rparam_len)
5319 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5320 char *str2 = skip_string(param,tpscnt,str1);
5321 char *p = skip_string(param,tpscnt,str2);
5322 int uLevel;
5323 int succnt;
5324 struct pack_desc desc;
5326 if (!str1 || !str2 || !p) {
5327 return False;
5330 memset((char *)&desc,'\0',sizeof(desc));
5332 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5334 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5336 /* check it's a supported varient */
5337 if (strcmp(str1,"WrLeh") != 0) {
5338 return False;
5340 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5341 return False;
5344 if (mdrcnt > 0) {
5345 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5346 if (!*rdata) {
5347 return False;
5350 memset((char *)&desc,'\0',sizeof(desc));
5351 desc.base = *rdata;
5352 desc.buflen = mdrcnt;
5353 desc.format = str2;
5354 if (init_package(&desc,1,0)) {
5355 PACKS(&desc,"B13","lp0");
5358 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5360 *rdata_len = desc.usedlen;
5362 *rparam_len = 8;
5363 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5364 if (!*rparam) {
5365 return False;
5367 SSVALS(*rparam,0,desc.errcode);
5368 SSVAL(*rparam,2,0);
5369 SSVAL(*rparam,4,succnt);
5370 SSVAL(*rparam,6,1);
5372 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5374 return True;
5377 /****************************************************************************
5378 List open sessions
5379 ****************************************************************************/
5381 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5382 connection_struct *conn, uint16 vuid,
5383 char *param, int tpscnt,
5384 char *data, int tdscnt,
5385 int mdrcnt,int mprcnt,
5386 char **rdata,char **rparam,
5387 int *rdata_len,int *rparam_len)
5390 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5391 char *str2 = skip_string(param,tpscnt,str1);
5392 char *p = skip_string(param,tpscnt,str2);
5393 int uLevel;
5394 struct pack_desc desc;
5395 struct sessionid *session_list;
5396 int i, num_sessions;
5398 if (!str1 || !str2 || !p) {
5399 return False;
5402 memset((char *)&desc,'\0',sizeof(desc));
5404 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5406 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5407 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5408 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5410 /* check it's a supported varient */
5411 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5412 return False;
5414 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5415 return False;
5418 num_sessions = list_sessions(talloc_tos(), &session_list);
5420 if (mdrcnt > 0) {
5421 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5422 if (!*rdata) {
5423 return False;
5426 memset((char *)&desc,'\0',sizeof(desc));
5427 desc.base = *rdata;
5428 desc.buflen = mdrcnt;
5429 desc.format = str2;
5430 if (!init_package(&desc,num_sessions,0)) {
5431 return False;
5434 for(i=0; i<num_sessions; i++) {
5435 PACKS(&desc, "z", session_list[i].remote_machine);
5436 PACKS(&desc, "z", session_list[i].username);
5437 PACKI(&desc, "W", 1); /* num conns */
5438 PACKI(&desc, "W", 0); /* num opens */
5439 PACKI(&desc, "W", 1); /* num users */
5440 PACKI(&desc, "D", 0); /* session time */
5441 PACKI(&desc, "D", 0); /* idle time */
5442 PACKI(&desc, "D", 0); /* flags */
5443 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5446 *rdata_len = desc.usedlen;
5448 *rparam_len = 8;
5449 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5450 if (!*rparam) {
5451 return False;
5453 SSVALS(*rparam,0,desc.errcode);
5454 SSVAL(*rparam,2,0); /* converter */
5455 SSVAL(*rparam,4,num_sessions); /* count */
5457 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5459 return True;
5463 /****************************************************************************
5464 The buffer was too small.
5465 ****************************************************************************/
5467 static bool api_TooSmall(struct smbd_server_connection *sconn,
5468 connection_struct *conn,uint16 vuid, char *param, char *data,
5469 int mdrcnt, int mprcnt,
5470 char **rdata, char **rparam,
5471 int *rdata_len, int *rparam_len)
5473 *rparam_len = MIN(*rparam_len,mprcnt);
5474 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5475 if (!*rparam) {
5476 return False;
5479 *rdata_len = 0;
5481 SSVAL(*rparam,0,NERR_BufTooSmall);
5483 DEBUG(3,("Supplied buffer too small in API command\n"));
5485 return True;
5488 /****************************************************************************
5489 The request is not supported.
5490 ****************************************************************************/
5492 static bool api_Unsupported(struct smbd_server_connection *sconn,
5493 connection_struct *conn, uint16 vuid,
5494 char *param, int tpscnt,
5495 char *data, int tdscnt,
5496 int mdrcnt, int mprcnt,
5497 char **rdata, char **rparam,
5498 int *rdata_len, int *rparam_len)
5500 *rparam_len = 4;
5501 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5502 if (!*rparam) {
5503 return False;
5506 *rdata_len = 0;
5508 SSVAL(*rparam,0,NERR_notsupported);
5509 SSVAL(*rparam,2,0); /* converter word */
5511 DEBUG(3,("Unsupported API command\n"));
5513 return True;
5516 static const struct {
5517 const char *name;
5518 int id;
5519 bool (*fn)(struct smbd_server_connection *sconn,
5520 connection_struct *, uint16,
5521 char *, int,
5522 char *, int,
5523 int,int,char **,char **,int *,int *);
5524 bool auth_user; /* Deny anonymous access? */
5525 } api_commands[] = {
5526 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5527 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5528 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5529 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5530 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5531 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5532 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5533 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5534 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5535 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5536 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5537 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5538 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5539 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5540 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5541 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5542 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5543 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5544 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5545 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5546 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5547 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5548 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5549 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5550 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5551 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5552 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5553 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5554 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5555 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5556 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5557 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5558 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5559 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5560 {NULL, -1, api_Unsupported}
5561 /* The following RAP calls are not implemented by Samba:
5563 RAP_WFileEnum2 - anon not OK
5568 /****************************************************************************
5569 Handle remote api calls.
5570 ****************************************************************************/
5572 void api_reply(connection_struct *conn, uint16 vuid,
5573 struct smb_request *req,
5574 char *data, char *params,
5575 int tdscnt, int tpscnt,
5576 int mdrcnt, int mprcnt)
5578 int api_command;
5579 char *rdata = NULL;
5580 char *rparam = NULL;
5581 const char *name1 = NULL;
5582 const char *name2 = NULL;
5583 int rdata_len = 0;
5584 int rparam_len = 0;
5585 bool reply=False;
5586 int i;
5588 if (!params) {
5589 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5590 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5591 return;
5594 if (tpscnt < 2) {
5595 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5596 return;
5598 api_command = SVAL(params,0);
5599 /* Is there a string at position params+2 ? */
5600 if (skip_string(params,tpscnt,params+2)) {
5601 name1 = params + 2;
5602 } else {
5603 name1 = "";
5605 name2 = skip_string(params,tpscnt,params+2);
5606 if (!name2) {
5607 name2 = "";
5610 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5611 api_command,
5612 name1,
5613 name2,
5614 tdscnt,tpscnt,mdrcnt,mprcnt));
5616 for (i=0;api_commands[i].name;i++) {
5617 if (api_commands[i].id == api_command && api_commands[i].fn) {
5618 DEBUG(3,("Doing %s\n",api_commands[i].name));
5619 break;
5623 /* Check whether this api call can be done anonymously */
5625 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5626 user_struct *user = get_valid_user_struct(req->sconn, vuid);
5628 if (!user || user->server_info->guest) {
5629 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5630 return;
5634 rdata = (char *)SMB_MALLOC(1024);
5635 if (rdata) {
5636 memset(rdata,'\0',1024);
5639 rparam = (char *)SMB_MALLOC(1024);
5640 if (rparam) {
5641 memset(rparam,'\0',1024);
5644 if(!rdata || !rparam) {
5645 DEBUG(0,("api_reply: malloc fail !\n"));
5646 SAFE_FREE(rdata);
5647 SAFE_FREE(rparam);
5648 reply_nterror(req, NT_STATUS_NO_MEMORY);
5649 return;
5652 reply = api_commands[i].fn(req->sconn, conn,
5653 vuid,
5654 params,tpscnt, /* params + length */
5655 data,tdscnt, /* data + length */
5656 mdrcnt,mprcnt,
5657 &rdata,&rparam,&rdata_len,&rparam_len);
5660 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5661 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5662 mdrcnt,mprcnt,
5663 &rdata,&rparam,&rdata_len,&rparam_len);
5666 /* if we get False back then it's actually unsupported */
5667 if (!reply) {
5668 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5669 data,
5670 tdscnt,mdrcnt,mprcnt,
5671 &rdata,&rparam,&rdata_len,&rparam_len);
5674 /* If api_Unsupported returns false we can't return anything. */
5675 if (reply) {
5676 send_trans_reply(conn, req, rparam, rparam_len,
5677 rdata, rdata_len, False);
5680 SAFE_FREE(rdata);
5681 SAFE_FREE(rparam);
5682 return;