s3: async cli_list
[Samba/gbeck.git] / source3 / smbd / lanman.c
blob493a8ec3c621799ac41b612bf9804c72c9757235
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007.
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
29 #include "smbd/globals.h"
30 #include "../librpc/gen_ndr/cli_samr.h"
31 #include "../librpc/gen_ndr/cli_spoolss.h"
32 #include "rpc_client/cli_spoolss.h"
33 #include "rpc_client/init_spoolss.h"
34 #include "../librpc/gen_ndr/cli_srvsvc.h"
35 #include "../librpc/gen_ndr/srv_samr.h"
36 #include "../librpc/gen_ndr/srv_srvsvc.h"
37 #include "../librpc/gen_ndr/rap.h"
38 #include "../lib/util/binsearch.h"
39 #include "../libcli/auth/libcli_auth.h"
41 #ifdef CHECK_TYPES
42 #undef CHECK_TYPES
43 #endif
44 #define CHECK_TYPES 0
46 #define NERR_Success 0
47 #define NERR_badpass 86
48 #define NERR_notsupported 50
50 #define NERR_BASE (2100)
51 #define NERR_BufTooSmall (NERR_BASE+23)
52 #define NERR_JobNotFound (NERR_BASE+51)
53 #define NERR_DestNotFound (NERR_BASE+52)
55 #define ACCESS_READ 0x01
56 #define ACCESS_WRITE 0x02
57 #define ACCESS_CREATE 0x04
59 #define SHPWLEN 8 /* share password length */
61 /* Limit size of ipc replies */
63 static char *smb_realloc_limit(void *ptr, size_t size)
65 char *val;
67 size = MAX((size),4*1024);
68 val = (char *)SMB_REALLOC(ptr,size);
69 if (val) {
70 memset(val,'\0',size);
72 return val;
75 static bool api_Unsupported(struct smbd_server_connection *sconn,
76 connection_struct *conn, uint16 vuid,
77 char *param, int tpscnt,
78 char *data, int tdscnt,
79 int mdrcnt, int mprcnt,
80 char **rdata, char **rparam,
81 int *rdata_len, int *rparam_len);
83 static bool api_TooSmall(struct smbd_server_connection *sconn,
84 connection_struct *conn, uint16 vuid, char *param, char *data,
85 int mdrcnt, int mprcnt,
86 char **rdata, char **rparam,
87 int *rdata_len, int *rparam_len);
90 static int CopyExpanded(connection_struct *conn,
91 int snum, char **dst, char *src, int *p_space_remaining)
93 TALLOC_CTX *ctx = talloc_tos();
94 char *buf = NULL;
95 int l;
97 if (!src || !dst || !p_space_remaining || !(*dst) ||
98 *p_space_remaining <= 0) {
99 return 0;
102 buf = talloc_strdup(ctx, src);
103 if (!buf) {
104 *p_space_remaining = 0;
105 return 0;
107 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
108 if (!buf) {
109 *p_space_remaining = 0;
110 return 0;
112 buf = talloc_sub_advanced(ctx,
113 lp_servicename(SNUM(conn)),
114 conn->server_info->unix_name,
115 conn->connectpath,
116 conn->server_info->utok.gid,
117 conn->server_info->sanitized_username,
118 conn->server_info->info3->base.domain.string,
119 buf);
120 if (!buf) {
121 *p_space_remaining = 0;
122 return 0;
124 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
125 if (l == -1) {
126 return 0;
128 (*dst) += l;
129 (*p_space_remaining) -= l;
130 return l;
133 static int CopyAndAdvance(char **dst, char *src, int *n)
135 int l;
136 if (!src || !dst || !n || !(*dst)) {
137 return 0;
139 l = push_ascii(*dst,src,*n, STR_TERMINATE);
140 if (l == -1) {
141 return 0;
143 (*dst) += l;
144 (*n) -= l;
145 return l;
148 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
150 TALLOC_CTX *ctx = talloc_tos();
151 char *buf = NULL;
152 if (!s) {
153 return 0;
155 buf = talloc_strdup(ctx,s);
156 if (!buf) {
157 return 0;
159 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
160 if (!buf) {
161 return 0;
163 buf = talloc_sub_advanced(ctx,
164 lp_servicename(SNUM(conn)),
165 conn->server_info->unix_name,
166 conn->connectpath,
167 conn->server_info->utok.gid,
168 conn->server_info->sanitized_username,
169 conn->server_info->info3->base.domain.string,
170 buf);
171 if (!buf) {
172 return 0;
174 return strlen(buf) + 1;
177 /*******************************************************************
178 Check a API string for validity when we only need to check the prefix.
179 ******************************************************************/
181 static bool prefix_ok(const char *str, const char *prefix)
183 return(strncmp(str,prefix,strlen(prefix)) == 0);
186 struct pack_desc {
187 const char *format; /* formatstring for structure */
188 const char *subformat; /* subformat for structure */
189 char *base; /* baseaddress of buffer */
190 int buflen; /* remaining size for fixed part; on init: length of base */
191 int subcount; /* count of substructures */
192 char *structbuf; /* pointer into buffer for remaining fixed part */
193 int stringlen; /* remaining size for variable part */
194 char *stringbuf; /* pointer into buffer for remaining variable part */
195 int neededlen; /* total needed size */
196 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
197 const char *curpos; /* current position; pointer into format or subformat */
198 int errcode;
201 static int get_counter(const char **p)
203 int i, n;
204 if (!p || !(*p)) {
205 return 1;
207 if (!isdigit((int)**p)) {
208 return 1;
210 for (n = 0;;) {
211 i = **p;
212 if (isdigit(i)) {
213 n = 10 * n + (i - '0');
214 } else {
215 return n;
217 (*p)++;
221 static int getlen(const char *p)
223 int n = 0;
224 if (!p) {
225 return 0;
228 while (*p) {
229 switch( *p++ ) {
230 case 'W': /* word (2 byte) */
231 n += 2;
232 break;
233 case 'K': /* status word? (2 byte) */
234 n += 2;
235 break;
236 case 'N': /* count of substructures (word) at end */
237 n += 2;
238 break;
239 case 'D': /* double word (4 byte) */
240 case 'z': /* offset to zero terminated string (4 byte) */
241 case 'l': /* offset to user data (4 byte) */
242 n += 4;
243 break;
244 case 'b': /* offset to data (with counter) (4 byte) */
245 n += 4;
246 get_counter(&p);
247 break;
248 case 'B': /* byte (with optional counter) */
249 n += get_counter(&p);
250 break;
253 return n;
256 static bool init_package(struct pack_desc *p, int count, int subcount)
258 int n = p->buflen;
259 int i;
261 if (!p->format || !p->base) {
262 return False;
265 i = count * getlen(p->format);
266 if (p->subformat) {
267 i += subcount * getlen(p->subformat);
269 p->structbuf = p->base;
270 p->neededlen = 0;
271 p->usedlen = 0;
272 p->subcount = 0;
273 p->curpos = p->format;
274 if (i > n) {
275 p->neededlen = i;
276 i = n = 0;
277 #if 0
279 * This is the old error code we used. Aparently
280 * WinNT/2k systems return ERRbuftoosmall (2123) and
281 * OS/2 needs this. I'm leaving this here so we can revert
282 * if needed. JRA.
284 p->errcode = ERRmoredata;
285 #else
286 p->errcode = ERRbuftoosmall;
287 #endif
288 } else {
289 p->errcode = NERR_Success;
291 p->buflen = i;
292 n -= i;
293 p->stringbuf = p->base + i;
294 p->stringlen = n;
295 return (p->errcode == NERR_Success);
298 static int package(struct pack_desc *p, ...)
300 va_list args;
301 int needed=0, stringneeded;
302 const char *str=NULL;
303 int is_string=0, stringused;
304 int32 temp;
306 va_start(args,p);
308 if (!*p->curpos) {
309 if (!p->subcount) {
310 p->curpos = p->format;
311 } else {
312 p->curpos = p->subformat;
313 p->subcount--;
316 #if CHECK_TYPES
317 str = va_arg(args,char*);
318 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
319 #endif
320 stringneeded = -1;
322 if (!p->curpos) {
323 va_end(args);
324 return 0;
327 switch( *p->curpos++ ) {
328 case 'W': /* word (2 byte) */
329 needed = 2;
330 temp = va_arg(args,int);
331 if (p->buflen >= needed) {
332 SSVAL(p->structbuf,0,temp);
334 break;
335 case 'K': /* status word? (2 byte) */
336 needed = 2;
337 temp = va_arg(args,int);
338 if (p->buflen >= needed) {
339 SSVAL(p->structbuf,0,temp);
341 break;
342 case 'N': /* count of substructures (word) at end */
343 needed = 2;
344 p->subcount = va_arg(args,int);
345 if (p->buflen >= needed) {
346 SSVAL(p->structbuf,0,p->subcount);
348 break;
349 case 'D': /* double word (4 byte) */
350 needed = 4;
351 temp = va_arg(args,int);
352 if (p->buflen >= needed) {
353 SIVAL(p->structbuf,0,temp);
355 break;
356 case 'B': /* byte (with optional counter) */
357 needed = get_counter(&p->curpos);
359 char *s = va_arg(args,char*);
360 if (p->buflen >= needed) {
361 StrnCpy(p->structbuf,s?s:"",needed-1);
364 break;
365 case 'z': /* offset to zero terminated string (4 byte) */
366 str = va_arg(args,char*);
367 stringneeded = (str ? strlen(str)+1 : 0);
368 is_string = 1;
369 break;
370 case 'l': /* offset to user data (4 byte) */
371 str = va_arg(args,char*);
372 stringneeded = va_arg(args,int);
373 is_string = 0;
374 break;
375 case 'b': /* offset to data (with counter) (4 byte) */
376 str = va_arg(args,char*);
377 stringneeded = get_counter(&p->curpos);
378 is_string = 0;
379 break;
382 va_end(args);
383 if (stringneeded >= 0) {
384 needed = 4;
385 if (p->buflen >= needed) {
386 stringused = stringneeded;
387 if (stringused > p->stringlen) {
388 stringused = (is_string ? p->stringlen : 0);
389 if (p->errcode == NERR_Success) {
390 p->errcode = ERRmoredata;
393 if (!stringused) {
394 SIVAL(p->structbuf,0,0);
395 } else {
396 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
397 memcpy(p->stringbuf,str?str:"",stringused);
398 if (is_string) {
399 p->stringbuf[stringused-1] = '\0';
401 p->stringbuf += stringused;
402 p->stringlen -= stringused;
403 p->usedlen += stringused;
406 p->neededlen += stringneeded;
409 p->neededlen += needed;
410 if (p->buflen >= needed) {
411 p->structbuf += needed;
412 p->buflen -= needed;
413 p->usedlen += needed;
414 } else {
415 if (p->errcode == NERR_Success) {
416 p->errcode = ERRmoredata;
419 return 1;
422 #if CHECK_TYPES
423 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
424 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
425 #else
426 #define PACK(desc,t,v) package(desc,v)
427 #define PACKl(desc,t,v,l) package(desc,v,l)
428 #endif
430 static void PACKI(struct pack_desc* desc, const char *t,int v)
432 PACK(desc,t,v);
435 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
437 PACK(desc,t,v);
440 /****************************************************************************
441 Get a print queue.
442 ****************************************************************************/
444 static void PackDriverData(struct pack_desc* desc)
446 char drivdata[4+4+32];
447 SIVAL(drivdata,0,sizeof drivdata); /* cb */
448 SIVAL(drivdata,4,1000); /* lVersion */
449 memset(drivdata+8,0,32); /* szDeviceName */
450 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
451 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
454 static int check_printq_info(struct pack_desc* desc,
455 unsigned int uLevel, char *id1, char *id2)
457 desc->subformat = NULL;
458 switch( uLevel ) {
459 case 0:
460 desc->format = "B13";
461 break;
462 case 1:
463 desc->format = "B13BWWWzzzzzWW";
464 break;
465 case 2:
466 desc->format = "B13BWWWzzzzzWN";
467 desc->subformat = "WB21BB16B10zWWzDDz";
468 break;
469 case 3:
470 desc->format = "zWWWWzzzzWWzzl";
471 break;
472 case 4:
473 desc->format = "zWWWWzzzzWNzzl";
474 desc->subformat = "WWzWWDDzz";
475 break;
476 case 5:
477 desc->format = "z";
478 break;
479 case 51:
480 desc->format = "K";
481 break;
482 case 52:
483 desc->format = "WzzzzzzzzN";
484 desc->subformat = "z";
485 break;
486 default:
487 DEBUG(0,("check_printq_info: invalid level %d\n",
488 uLevel ));
489 return False;
491 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
492 DEBUG(0,("check_printq_info: invalid format %s\n",
493 id1 ? id1 : "<NULL>" ));
494 return False;
496 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
497 DEBUG(0,("check_printq_info: invalid subformat %s\n",
498 id2 ? id2 : "<NULL>" ));
499 return False;
501 return True;
505 #define RAP_JOB_STATUS_QUEUED 0
506 #define RAP_JOB_STATUS_PAUSED 1
507 #define RAP_JOB_STATUS_SPOOLING 2
508 #define RAP_JOB_STATUS_PRINTING 3
509 #define RAP_JOB_STATUS_PRINTED 4
511 #define RAP_QUEUE_STATUS_PAUSED 1
512 #define RAP_QUEUE_STATUS_ERROR 2
514 /* turn a print job status into a on the wire status
516 static int printj_spoolss_status(int v)
518 if (v == JOB_STATUS_QUEUED)
519 return RAP_JOB_STATUS_QUEUED;
520 if (v & JOB_STATUS_PAUSED)
521 return RAP_JOB_STATUS_PAUSED;
522 if (v & JOB_STATUS_SPOOLING)
523 return RAP_JOB_STATUS_SPOOLING;
524 if (v & JOB_STATUS_PRINTING)
525 return RAP_JOB_STATUS_PRINTING;
526 return 0;
529 /* turn a print queue status into a on the wire status
531 static int printq_spoolss_status(int v)
533 if (v == PRINTER_STATUS_OK)
534 return 0;
535 if (v & PRINTER_STATUS_PAUSED)
536 return RAP_QUEUE_STATUS_PAUSED;
537 return RAP_QUEUE_STATUS_ERROR;
540 static void fill_spoolss_printjob_info(int uLevel,
541 struct pack_desc *desc,
542 struct spoolss_JobInfo2 *info2,
543 int n)
545 time_t t = spoolss_Time_to_time_t(&info2->submitted);
547 /* the client expects localtime */
548 t -= get_time_zone(t);
550 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
551 if (uLevel == 1) {
552 PACKS(desc,"B21", info2->user_name); /* szUserName */
553 PACKS(desc,"B",""); /* pad */
554 PACKS(desc,"B16",""); /* szNotifyName */
555 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
556 PACKS(desc,"z",""); /* pszParms */
557 PACKI(desc,"W",n+1); /* uPosition */
558 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
559 PACKS(desc,"z",""); /* pszStatus */
560 PACKI(desc,"D", t); /* ulSubmitted */
561 PACKI(desc,"D", info2->size); /* ulSize */
562 PACKS(desc,"z", info2->document_name); /* pszComment */
564 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
565 PACKI(desc,"W", info2->priority); /* uPriority */
566 PACKS(desc,"z", info2->user_name); /* pszUserName */
567 PACKI(desc,"W",n+1); /* uPosition */
568 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
569 PACKI(desc,"D",t); /* ulSubmitted */
570 PACKI(desc,"D", info2->size); /* ulSize */
571 PACKS(desc,"z","Samba"); /* pszComment */
572 PACKS(desc,"z", info2->document_name); /* pszDocument */
573 if (uLevel == 3) {
574 PACKS(desc,"z",""); /* pszNotifyName */
575 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
576 PACKS(desc,"z",""); /* pszParms */
577 PACKS(desc,"z",""); /* pszStatus */
578 PACKS(desc,"z", info2->printer_name); /* pszQueue */
579 PACKS(desc,"z","lpd"); /* pszQProcName */
580 PACKS(desc,"z",""); /* pszQProcParms */
581 PACKS(desc,"z","NULL"); /* pszDriverName */
582 PackDriverData(desc); /* pDriverData */
583 PACKS(desc,"z",""); /* pszPrinterName */
584 } else if (uLevel == 4) { /* OS2 */
585 PACKS(desc,"z",""); /* pszSpoolFileName */
586 PACKS(desc,"z",""); /* pszPortName */
587 PACKS(desc,"z",""); /* pszStatus */
588 PACKI(desc,"D",0); /* ulPagesSpooled */
589 PACKI(desc,"D",0); /* ulPagesSent */
590 PACKI(desc,"D",0); /* ulPagesPrinted */
591 PACKI(desc,"D",0); /* ulTimePrinted */
592 PACKI(desc,"D",0); /* ulExtendJobStatus */
593 PACKI(desc,"D",0); /* ulStartPage */
594 PACKI(desc,"D",0); /* ulEndPage */
599 /********************************************************************
600 Respond to the DosPrintQInfo command with a level of 52
601 This is used to get printer driver information for Win9x clients
602 ********************************************************************/
603 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
604 struct pack_desc* desc, int count,
605 const char *printer_name)
607 int i;
608 fstring location;
609 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
610 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
611 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
613 PACKI(desc, "W", 0x0400); /* don't know */
614 PACKS(desc, "z", driver->driver_name); /* long printer name */
615 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
616 PACKS(desc, "z", driver->data_file); /* Datafile name */
617 PACKS(desc, "z", driver->monitor_name); /* language monitor */
619 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
620 standard_sub_basic( "", "", location, sizeof(location)-1 );
621 PACKS(desc,"z", location); /* share to retrieve files */
623 PACKS(desc,"z", driver->default_datatype); /* default data type */
624 PACKS(desc,"z", driver->help_file); /* helpfile name */
625 PACKS(desc,"z", driver->driver_path); /* driver name */
627 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
628 DEBUG(3,("Driver: %s:\n",driver->driver_path));
629 DEBUG(3,("Data File: %s:\n",driver->data_file));
630 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
631 DEBUG(3,("Driver Location: %s:\n",location));
632 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
633 DEBUG(3,("Help File: %s:\n",driver->help_file));
634 PACKI(desc,"N",count); /* number of files to copy */
636 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
638 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
639 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
640 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
643 /* sanity check */
644 if ( i != count )
645 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
646 count, i));
648 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
650 desc->errcode=NERR_Success;
654 static const char *strip_unc(const char *unc)
656 char *p;
658 if (unc == NULL) {
659 return NULL;
662 if ((p = strrchr(unc, '\\')) != NULL) {
663 return p+1;
666 return unc;
669 static void fill_printq_info(int uLevel,
670 struct pack_desc* desc,
671 int count,
672 union spoolss_JobInfo *job_info,
673 struct spoolss_DriverInfo3 *driver_info,
674 struct spoolss_PrinterInfo2 *printer_info)
676 switch (uLevel) {
677 case 0:
678 case 1:
679 case 2:
680 PACKS(desc,"B13", strip_unc(printer_info->printername));
681 break;
682 case 3:
683 case 4:
684 case 5:
685 PACKS(desc,"z", strip_unc(printer_info->printername));
686 break;
687 case 51:
688 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
689 break;
692 if (uLevel == 1 || uLevel == 2) {
693 PACKS(desc,"B",""); /* alignment */
694 PACKI(desc,"W",5); /* priority */
695 PACKI(desc,"W",0); /* start time */
696 PACKI(desc,"W",0); /* until time */
697 PACKS(desc,"z",""); /* pSepFile */
698 PACKS(desc,"z","lpd"); /* pPrProc */
699 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */
700 PACKS(desc,"z",""); /* pParms */
701 if (printer_info->printername == NULL) {
702 PACKS(desc,"z","UNKNOWN PRINTER");
703 PACKI(desc,"W",LPSTAT_ERROR);
704 } else {
705 PACKS(desc,"z", printer_info->comment);
706 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
708 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
711 if (uLevel == 3 || uLevel == 4) {
712 PACKI(desc,"W",5); /* uPriority */
713 PACKI(desc,"W",0); /* uStarttime */
714 PACKI(desc,"W",0); /* uUntiltime */
715 PACKI(desc,"W",5); /* pad1 */
716 PACKS(desc,"z",""); /* pszSepFile */
717 PACKS(desc,"z","WinPrint"); /* pszPrProc */
718 PACKS(desc,"z",NULL); /* pszParms */
719 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
720 /* "don't ask" that it's done this way to fix corrupted
721 Win9X/ME printer comments. */
722 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
723 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
724 PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */
725 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
726 PackDriverData(desc); /* pDriverData */
729 if (uLevel == 2 || uLevel == 4) {
730 int i;
731 for (i = 0; i < count; i++) {
732 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
736 if (uLevel==52)
737 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
740 /* This function returns the number of files for a given driver */
741 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
743 int result = 0;
745 /* count the number of files */
746 while (driver->dependent_files && *driver->dependent_files[result])
747 result++;
749 return result;
752 static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn,
753 connection_struct *conn, uint16 vuid,
754 char *param, int tpscnt,
755 char *data, int tdscnt,
756 int mdrcnt,int mprcnt,
757 char **rdata,char **rparam,
758 int *rdata_len,int *rparam_len)
760 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
761 char *str2 = skip_string(param,tpscnt,str1);
762 char *p = skip_string(param,tpscnt,str2);
763 char *QueueName = p;
764 unsigned int uLevel;
765 uint32_t count = 0;
766 char *str3;
767 struct pack_desc desc;
768 char* tmpdata=NULL;
770 WERROR werr = WERR_OK;
771 TALLOC_CTX *mem_ctx = talloc_tos();
772 NTSTATUS status;
773 struct rpc_pipe_client *cli = NULL;
774 struct policy_handle handle;
775 struct spoolss_DevmodeContainer devmode_ctr;
776 union spoolss_DriverInfo driver_info;
777 union spoolss_JobInfo *job_info = NULL;
778 union spoolss_PrinterInfo printer_info;
780 if (!str1 || !str2 || !p) {
781 return False;
783 memset((char *)&desc,'\0',sizeof(desc));
785 p = skip_string(param,tpscnt,p);
786 if (!p) {
787 return False;
789 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
790 str3 = get_safe_str_ptr(param,tpscnt,p,4);
791 /* str3 may be null here and is checked in check_printq_info(). */
793 /* remove any trailing username */
794 if ((p = strchr_m(QueueName,'%')))
795 *p = 0;
797 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
799 /* check it's a supported varient */
800 if (!prefix_ok(str1,"zWrLh"))
801 return False;
802 if (!check_printq_info(&desc,uLevel,str2,str3)) {
804 * Patch from Scott Moomaw <scott@bridgewater.edu>
805 * to return the 'invalid info level' error if an
806 * unknown level was requested.
808 *rdata_len = 0;
809 *rparam_len = 6;
810 *rparam = smb_realloc_limit(*rparam,*rparam_len);
811 if (!*rparam) {
812 return False;
814 SSVALS(*rparam,0,ERRunknownlevel);
815 SSVAL(*rparam,2,0);
816 SSVAL(*rparam,4,0);
817 return(True);
820 ZERO_STRUCT(handle);
822 if (QueueName == NULL || (strlen(QueueName) < 1)) {
823 desc.errcode = W_ERROR_V(WERR_INVALID_PARAM);
824 goto out;
827 status = rpc_connect_spoolss_pipe(conn, &cli);
828 if (!NT_STATUS_IS_OK(status)) {
829 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
830 nt_errstr(status)));
831 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
832 goto out;
835 ZERO_STRUCT(devmode_ctr);
837 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
838 QueueName,
839 "RAW",
840 devmode_ctr,
841 PRINTER_ACCESS_USE,
842 &handle,
843 &werr);
844 if (!NT_STATUS_IS_OK(status)) {
845 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
846 goto out;
848 if (!W_ERROR_IS_OK(werr)) {
849 desc.errcode = W_ERROR_V(werr);
850 goto out;
853 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
854 &handle,
857 &printer_info);
858 if (!W_ERROR_IS_OK(werr)) {
859 desc.errcode = W_ERROR_V(werr);
860 goto out;
863 if (uLevel==52) {
864 uint32_t server_major_version;
865 uint32_t server_minor_version;
867 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
868 &handle,
869 "Windows 4.0",
870 3, /* level */
872 0, /* version */
874 &driver_info,
875 &server_major_version,
876 &server_minor_version);
877 if (!W_ERROR_IS_OK(werr)) {
878 desc.errcode = W_ERROR_V(werr);
879 goto out;
882 count = get_printerdrivernumber(&driver_info.info3);
883 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
884 } else {
885 uint32_t num_jobs;
886 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
887 &handle,
888 0, /* firstjob */
889 0xff, /* numjobs */
890 2, /* level */
891 0, /* offered */
892 &num_jobs,
893 &job_info);
894 if (!W_ERROR_IS_OK(werr)) {
895 desc.errcode = W_ERROR_V(werr);
896 goto out;
899 count = num_jobs;
902 if (mdrcnt > 0) {
903 *rdata = smb_realloc_limit(*rdata,mdrcnt);
904 if (!*rdata) {
905 return False;
907 desc.base = *rdata;
908 desc.buflen = mdrcnt;
909 } else {
911 * Don't return data but need to get correct length
912 * init_package will return wrong size if buflen=0
914 desc.buflen = getlen(desc.format);
915 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
918 if (init_package(&desc,1,count)) {
919 desc.subcount = count;
920 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
923 *rdata_len = desc.usedlen;
926 * We must set the return code to ERRbuftoosmall
927 * in order to support lanman style printing with Win NT/2k
928 * clients --jerry
930 if (!mdrcnt && lp_disable_spoolss())
931 desc.errcode = ERRbuftoosmall;
933 out:
934 if (cli && is_valid_policy_hnd(&handle)) {
935 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
938 *rdata_len = desc.usedlen;
939 *rparam_len = 6;
940 *rparam = smb_realloc_limit(*rparam,*rparam_len);
941 if (!*rparam) {
942 SAFE_FREE(tmpdata);
943 return False;
945 SSVALS(*rparam,0,desc.errcode);
946 SSVAL(*rparam,2,0);
947 SSVAL(*rparam,4,desc.neededlen);
949 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
951 SAFE_FREE(tmpdata);
953 return(True);
956 /****************************************************************************
957 View list of all print jobs on all queues.
958 ****************************************************************************/
960 static bool api_DosPrintQEnum(struct smbd_server_connection *sconn,
961 connection_struct *conn, uint16 vuid,
962 char *param, int tpscnt,
963 char *data, int tdscnt,
964 int mdrcnt, int mprcnt,
965 char **rdata, char** rparam,
966 int *rdata_len, int *rparam_len)
968 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
969 char *output_format1 = skip_string(param,tpscnt,param_format);
970 char *p = skip_string(param,tpscnt,output_format1);
971 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
972 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
973 int i;
974 struct pack_desc desc;
975 int *subcntarr = NULL;
976 int queuecnt = 0, subcnt = 0, succnt = 0;
978 WERROR werr = WERR_OK;
979 TALLOC_CTX *mem_ctx = talloc_tos();
980 NTSTATUS status;
981 struct rpc_pipe_client *cli = NULL;
982 struct spoolss_DevmodeContainer devmode_ctr;
983 uint32_t num_printers;
984 union spoolss_PrinterInfo *printer_info;
985 union spoolss_DriverInfo *driver_info;
986 union spoolss_JobInfo **job_info;
988 if (!param_format || !output_format1 || !p) {
989 return False;
992 memset((char *)&desc,'\0',sizeof(desc));
994 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
996 if (!prefix_ok(param_format,"WrLeh")) {
997 return False;
999 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1001 * Patch from Scott Moomaw <scott@bridgewater.edu>
1002 * to return the 'invalid info level' error if an
1003 * unknown level was requested.
1005 *rdata_len = 0;
1006 *rparam_len = 6;
1007 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1008 if (!*rparam) {
1009 return False;
1011 SSVALS(*rparam,0,ERRunknownlevel);
1012 SSVAL(*rparam,2,0);
1013 SSVAL(*rparam,4,0);
1014 return(True);
1017 status = rpc_connect_spoolss_pipe(conn, &cli);
1018 if (!NT_STATUS_IS_OK(status)) {
1019 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
1020 nt_errstr(status)));
1021 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1022 goto out;
1025 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1026 PRINTER_ENUM_LOCAL,
1027 cli->srv_name_slash,
1030 &num_printers,
1031 &printer_info);
1032 if (!W_ERROR_IS_OK(werr)) {
1033 desc.errcode = W_ERROR_V(werr);
1034 goto out;
1037 queuecnt = num_printers;
1039 job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers);
1040 if (job_info == NULL) {
1041 goto err;
1044 driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers);
1045 if (driver_info == NULL) {
1046 goto err;
1049 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1050 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1051 goto err;
1054 if (mdrcnt > 0) {
1055 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1056 if (!*rdata) {
1057 goto err;
1060 desc.base = *rdata;
1061 desc.buflen = mdrcnt;
1063 subcnt = 0;
1064 for (i = 0; i < num_printers; i++) {
1066 uint32_t num_jobs;
1067 struct policy_handle handle;
1068 const char *printername;
1070 printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername);
1071 if (printername == NULL) {
1072 goto err;
1075 ZERO_STRUCT(handle);
1076 ZERO_STRUCT(devmode_ctr);
1078 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1079 printername,
1080 "RAW",
1081 devmode_ctr,
1082 PRINTER_ACCESS_USE,
1083 &handle,
1084 &werr);
1085 if (!NT_STATUS_IS_OK(status)) {
1086 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1087 goto out;
1089 if (!W_ERROR_IS_OK(werr)) {
1090 desc.errcode = W_ERROR_V(werr);
1091 goto out;
1094 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1095 &handle,
1096 0, /* firstjob */
1097 0xff, /* numjobs */
1098 2, /* level */
1099 0, /* offered */
1100 &num_jobs,
1101 &job_info[i]);
1102 if (!W_ERROR_IS_OK(werr)) {
1103 desc.errcode = W_ERROR_V(werr);
1104 goto out;
1107 if (uLevel==52) {
1108 uint32_t server_major_version;
1109 uint32_t server_minor_version;
1111 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1112 &handle,
1113 "Windows 4.0",
1114 3, /* level */
1116 0, /* version */
1118 &driver_info[i],
1119 &server_major_version,
1120 &server_minor_version);
1121 if (!W_ERROR_IS_OK(werr)) {
1122 desc.errcode = W_ERROR_V(werr);
1123 goto out;
1127 subcntarr[i] = num_jobs;
1128 subcnt += subcntarr[i];
1130 if (cli && is_valid_policy_hnd(&handle)) {
1131 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1135 if (init_package(&desc,queuecnt,subcnt)) {
1136 for (i = 0; i < num_printers; i++) {
1137 fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2);
1138 if (desc.errcode == NERR_Success) {
1139 succnt = i;
1144 SAFE_FREE(subcntarr);
1145 out:
1146 *rdata_len = desc.usedlen;
1147 *rparam_len = 8;
1148 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1149 if (!*rparam) {
1150 goto err;
1152 SSVALS(*rparam,0,desc.errcode);
1153 SSVAL(*rparam,2,0);
1154 SSVAL(*rparam,4,succnt);
1155 SSVAL(*rparam,6,queuecnt);
1157 return True;
1159 err:
1161 SAFE_FREE(subcntarr);
1163 return False;
1166 /****************************************************************************
1167 Get info level for a server list query.
1168 ****************************************************************************/
1170 static bool check_server_info(int uLevel, char* id)
1172 switch( uLevel ) {
1173 case 0:
1174 if (strcmp(id,"B16") != 0) {
1175 return False;
1177 break;
1178 case 1:
1179 if (strcmp(id,"B16BBDz") != 0) {
1180 return False;
1182 break;
1183 default:
1184 return False;
1186 return True;
1189 struct srv_info_struct {
1190 fstring name;
1191 uint32 type;
1192 fstring comment;
1193 fstring domain;
1194 bool server_added;
1197 /*******************************************************************
1198 Get server info lists from the files saved by nmbd. Return the
1199 number of entries.
1200 ******************************************************************/
1202 static int get_server_info(uint32 servertype,
1203 struct srv_info_struct **servers,
1204 const char *domain)
1206 int count=0;
1207 int alloced=0;
1208 char **lines;
1209 bool local_list_only;
1210 int i;
1212 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1213 if (!lines) {
1214 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1215 return 0;
1218 /* request for everything is code for request all servers */
1219 if (servertype == SV_TYPE_ALL) {
1220 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1223 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1225 DEBUG(4,("Servertype search: %8x\n",servertype));
1227 for (i=0;lines[i];i++) {
1228 fstring stype;
1229 struct srv_info_struct *s;
1230 const char *ptr = lines[i];
1231 bool ok = True;
1232 TALLOC_CTX *frame = NULL;
1233 char *p;
1235 if (!*ptr) {
1236 continue;
1239 if (count == alloced) {
1240 alloced += 10;
1241 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1242 if (!*servers) {
1243 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1244 TALLOC_FREE(lines);
1245 return 0;
1247 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1249 s = &(*servers)[count];
1251 frame = talloc_stackframe();
1252 s->name[0] = '\0';
1253 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1254 TALLOC_FREE(frame);
1255 continue;
1257 fstrcpy(s->name, p);
1259 stype[0] = '\0';
1260 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1261 TALLOC_FREE(frame);
1262 continue;
1264 fstrcpy(stype, p);
1266 s->comment[0] = '\0';
1267 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1268 TALLOC_FREE(frame);
1269 continue;
1271 fstrcpy(s->comment, p);
1272 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1274 s->domain[0] = '\0';
1275 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1276 /* this allows us to cope with an old nmbd */
1277 fstrcpy(s->domain,lp_workgroup());
1278 } else {
1279 fstrcpy(s->domain, p);
1281 TALLOC_FREE(frame);
1283 if (sscanf(stype,"%X",&s->type) != 1) {
1284 DEBUG(4,("r:host file "));
1285 ok = False;
1288 /* Filter the servers/domains we return based on what was asked for. */
1290 /* Check to see if we are being asked for a local list only. */
1291 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1292 DEBUG(4,("r: local list only"));
1293 ok = False;
1296 /* doesn't match up: don't want it */
1297 if (!(servertype & s->type)) {
1298 DEBUG(4,("r:serv type "));
1299 ok = False;
1302 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1303 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1304 DEBUG(4,("s: dom mismatch "));
1305 ok = False;
1308 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1309 ok = False;
1312 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1313 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1315 if (ok) {
1316 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1317 s->name, s->type, s->comment, s->domain));
1318 s->server_added = True;
1319 count++;
1320 } else {
1321 DEBUG(4,("%20s %8x %25s %15s\n",
1322 s->name, s->type, s->comment, s->domain));
1326 TALLOC_FREE(lines);
1327 return count;
1330 /*******************************************************************
1331 Fill in a server info structure.
1332 ******************************************************************/
1334 static int fill_srv_info(struct srv_info_struct *service,
1335 int uLevel, char **buf, int *buflen,
1336 char **stringbuf, int *stringspace, char *baseaddr)
1338 int struct_len;
1339 char* p;
1340 char* p2;
1341 int l2;
1342 int len;
1344 switch (uLevel) {
1345 case 0:
1346 struct_len = 16;
1347 break;
1348 case 1:
1349 struct_len = 26;
1350 break;
1351 default:
1352 return -1;
1355 if (!buf) {
1356 len = 0;
1357 switch (uLevel) {
1358 case 1:
1359 len = strlen(service->comment)+1;
1360 break;
1363 *buflen = struct_len;
1364 *stringspace = len;
1365 return struct_len + len;
1368 len = struct_len;
1369 p = *buf;
1370 if (*buflen < struct_len) {
1371 return -1;
1373 if (stringbuf) {
1374 p2 = *stringbuf;
1375 l2 = *stringspace;
1376 } else {
1377 p2 = p + struct_len;
1378 l2 = *buflen - struct_len;
1380 if (!baseaddr) {
1381 baseaddr = p;
1384 switch (uLevel) {
1385 case 0:
1386 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1387 break;
1389 case 1:
1390 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1391 SIVAL(p,18,service->type);
1392 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1393 len += CopyAndAdvance(&p2,service->comment,&l2);
1394 break;
1397 if (stringbuf) {
1398 *buf = p + struct_len;
1399 *buflen -= struct_len;
1400 *stringbuf = p2;
1401 *stringspace = l2;
1402 } else {
1403 *buf = p2;
1404 *buflen -= len;
1406 return len;
1410 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1412 return StrCaseCmp(s1->name,s2->name);
1415 /****************************************************************************
1416 View list of servers available (or possibly domains). The info is
1417 extracted from lists saved by nmbd on the local host.
1418 ****************************************************************************/
1420 static bool api_RNetServerEnum2(struct smbd_server_connection *sconn,
1421 connection_struct *conn, uint16 vuid,
1422 char *param, int tpscnt,
1423 char *data, int tdscnt,
1424 int mdrcnt, int mprcnt, char **rdata,
1425 char **rparam, int *rdata_len, int *rparam_len)
1427 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1428 char *str2 = skip_string(param,tpscnt,str1);
1429 char *p = skip_string(param,tpscnt,str2);
1430 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1431 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1432 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1433 char *p2;
1434 int data_len, fixed_len, string_len;
1435 int f_len = 0, s_len = 0;
1436 struct srv_info_struct *servers=NULL;
1437 int counted=0,total=0;
1438 int i,missed;
1439 fstring domain;
1440 bool domain_request;
1441 bool local_request;
1443 if (!str1 || !str2 || !p) {
1444 return False;
1447 /* If someone sets all the bits they don't really mean to set
1448 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1449 known servers. */
1451 if (servertype == SV_TYPE_ALL) {
1452 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1455 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1456 any other bit (they may just set this bit on its own) they
1457 want all the locally seen servers. However this bit can be
1458 set on its own so set the requested servers to be
1459 ALL - DOMAIN_ENUM. */
1461 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1462 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1465 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1466 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1468 p += 8;
1470 if (!prefix_ok(str1,"WrLehD")) {
1471 return False;
1473 if (!check_server_info(uLevel,str2)) {
1474 return False;
1477 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1478 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1479 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1481 if (strcmp(str1, "WrLehDz") == 0) {
1482 if (skip_string(param,tpscnt,p) == NULL) {
1483 return False;
1485 pull_ascii_fstring(domain, p);
1486 } else {
1487 fstrcpy(domain, lp_workgroup());
1490 DEBUG(4, ("domain [%s]\n", domain));
1492 if (lp_browse_list()) {
1493 total = get_server_info(servertype,&servers,domain);
1496 data_len = fixed_len = string_len = 0;
1497 missed = 0;
1499 TYPESAFE_QSORT(servers, total, srv_comp);
1502 char *lastname=NULL;
1504 for (i=0;i<total;i++) {
1505 struct srv_info_struct *s = &servers[i];
1507 if (lastname && strequal(lastname,s->name)) {
1508 continue;
1510 lastname = s->name;
1511 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1512 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1513 i, s->name, s->type, s->comment, s->domain));
1515 if (data_len < buf_len) {
1516 counted++;
1517 fixed_len += f_len;
1518 string_len += s_len;
1519 } else {
1520 missed++;
1525 *rdata_len = fixed_len + string_len;
1526 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1527 if (!*rdata) {
1528 return False;
1531 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1532 p = *rdata;
1533 f_len = fixed_len;
1534 s_len = string_len;
1537 char *lastname=NULL;
1538 int count2 = counted;
1540 for (i = 0; i < total && count2;i++) {
1541 struct srv_info_struct *s = &servers[i];
1543 if (lastname && strequal(lastname,s->name)) {
1544 continue;
1546 lastname = s->name;
1547 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1548 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1549 i, s->name, s->type, s->comment, s->domain));
1550 count2--;
1554 *rparam_len = 8;
1555 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1556 if (!*rparam) {
1557 return False;
1559 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1560 SSVAL(*rparam,2,0);
1561 SSVAL(*rparam,4,counted);
1562 SSVAL(*rparam,6,counted+missed);
1564 SAFE_FREE(servers);
1566 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1567 domain,uLevel,counted,counted+missed));
1569 return True;
1572 static int srv_name_match(const char *n1, const char *n2)
1575 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1577 * In Windows, FirstNameToReturn need not be an exact match:
1578 * the server will return a list of servers that exist on
1579 * the network greater than or equal to the FirstNameToReturn.
1581 int ret = StrCaseCmp(n1, n2);
1583 if (ret <= 0) {
1584 return 0;
1587 return ret;
1590 static bool api_RNetServerEnum3(struct smbd_server_connection *sconn,
1591 connection_struct *conn, uint16 vuid,
1592 char *param, int tpscnt,
1593 char *data, int tdscnt,
1594 int mdrcnt, int mprcnt, char **rdata,
1595 char **rparam, int *rdata_len, int *rparam_len)
1597 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1598 char *str2 = skip_string(param,tpscnt,str1);
1599 char *p = skip_string(param,tpscnt,str2);
1600 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1601 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1602 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1603 char *p2;
1604 int data_len, fixed_len, string_len;
1605 int f_len = 0, s_len = 0;
1606 struct srv_info_struct *servers=NULL;
1607 int counted=0,first=0,total=0;
1608 int i,missed;
1609 fstring domain;
1610 fstring first_name;
1611 bool domain_request;
1612 bool local_request;
1614 if (!str1 || !str2 || !p) {
1615 return False;
1618 /* If someone sets all the bits they don't really mean to set
1619 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1620 known servers. */
1622 if (servertype == SV_TYPE_ALL) {
1623 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1626 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1627 any other bit (they may just set this bit on its own) they
1628 want all the locally seen servers. However this bit can be
1629 set on its own so set the requested servers to be
1630 ALL - DOMAIN_ENUM. */
1632 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1633 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1636 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1637 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1639 p += 8;
1641 if (strcmp(str1, "WrLehDzz") != 0) {
1642 return false;
1644 if (!check_server_info(uLevel,str2)) {
1645 return False;
1648 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1649 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1650 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1652 if (skip_string(param,tpscnt,p) == NULL) {
1653 return False;
1655 pull_ascii_fstring(domain, p);
1656 if (domain[0] == '\0') {
1657 fstrcpy(domain, lp_workgroup());
1659 p = skip_string(param,tpscnt,p);
1660 if (skip_string(param,tpscnt,p) == NULL) {
1661 return False;
1663 pull_ascii_fstring(first_name, p);
1665 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1666 domain, first_name));
1668 if (lp_browse_list()) {
1669 total = get_server_info(servertype,&servers,domain);
1672 data_len = fixed_len = string_len = 0;
1673 missed = 0;
1675 TYPESAFE_QSORT(servers, total, srv_comp);
1677 if (first_name[0] != '\0') {
1678 struct srv_info_struct *first_server = NULL;
1680 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1681 srv_name_match, first_server);
1682 if (first_server) {
1683 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1685 * The binary search may not find the exact match
1686 * so we need to search backward to find the first match
1688 * This implements the strange matching windows
1689 * implements. (see the comment in srv_name_match().
1691 for (;first > 0;) {
1692 int ret;
1693 ret = StrCaseCmp(first_name,
1694 servers[first-1].name);
1695 if (ret > 0) {
1696 break;
1698 first--;
1700 } else {
1701 /* we should return no entries */
1702 first = total;
1707 char *lastname=NULL;
1709 for (i=first;i<total;i++) {
1710 struct srv_info_struct *s = &servers[i];
1712 if (lastname && strequal(lastname,s->name)) {
1713 continue;
1715 lastname = s->name;
1716 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1717 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1718 i, s->name, s->type, s->comment, s->domain));
1720 if (data_len < buf_len) {
1721 counted++;
1722 fixed_len += f_len;
1723 string_len += s_len;
1724 } else {
1725 missed++;
1730 *rdata_len = fixed_len + string_len;
1731 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1732 if (!*rdata) {
1733 return False;
1736 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1737 p = *rdata;
1738 f_len = fixed_len;
1739 s_len = string_len;
1742 char *lastname=NULL;
1743 int count2 = counted;
1745 for (i = first; i < total && count2;i++) {
1746 struct srv_info_struct *s = &servers[i];
1748 if (lastname && strequal(lastname,s->name)) {
1749 continue;
1751 lastname = s->name;
1752 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1753 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1754 i, s->name, s->type, s->comment, s->domain));
1755 count2--;
1759 *rparam_len = 8;
1760 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1761 if (!*rparam) {
1762 return False;
1764 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1765 SSVAL(*rparam,2,0);
1766 SSVAL(*rparam,4,counted);
1767 SSVAL(*rparam,6,counted+missed);
1769 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1770 domain,uLevel,first,first_name,
1771 first < total ? servers[first].name : "",
1772 counted,counted+missed));
1774 SAFE_FREE(servers);
1776 return True;
1779 /****************************************************************************
1780 command 0x34 - suspected of being a "Lookup Names" stub api
1781 ****************************************************************************/
1783 static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn,
1784 connection_struct *conn, uint16 vuid,
1785 char *param, int tpscnt,
1786 char *data, int tdscnt,
1787 int mdrcnt, int mprcnt, char **rdata,
1788 char **rparam, int *rdata_len, int *rparam_len)
1790 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1791 char *str2 = skip_string(param,tpscnt,str1);
1792 char *p = skip_string(param,tpscnt,str2);
1793 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1794 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1795 int counted=0;
1796 int missed=0;
1798 if (!str1 || !str2 || !p) {
1799 return False;
1802 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1803 str1, str2, p, uLevel, buf_len));
1805 if (!prefix_ok(str1,"zWrLeh")) {
1806 return False;
1809 *rdata_len = 0;
1811 *rparam_len = 8;
1812 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1813 if (!*rparam) {
1814 return False;
1817 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1818 SSVAL(*rparam,2,0);
1819 SSVAL(*rparam,4,counted);
1820 SSVAL(*rparam,6,counted+missed);
1822 return True;
1825 /****************************************************************************
1826 get info about a share
1827 ****************************************************************************/
1829 static bool check_share_info(int uLevel, char* id)
1831 switch( uLevel ) {
1832 case 0:
1833 if (strcmp(id,"B13") != 0) {
1834 return False;
1836 break;
1837 case 1:
1838 /* Level-2 descriptor is allowed (and ignored) */
1839 if (strcmp(id,"B13BWz") != 0 &&
1840 strcmp(id,"B13BWzWWWzB9B") != 0) {
1841 return False;
1843 break;
1844 case 2:
1845 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1846 return False;
1848 break;
1849 case 91:
1850 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1851 return False;
1853 break;
1854 default:
1855 return False;
1857 return True;
1860 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1861 char** buf, int* buflen,
1862 char** stringbuf, int* stringspace, char* baseaddr)
1864 int struct_len;
1865 char* p;
1866 char* p2;
1867 int l2;
1868 int len;
1870 switch( uLevel ) {
1871 case 0:
1872 struct_len = 13;
1873 break;
1874 case 1:
1875 struct_len = 20;
1876 break;
1877 case 2:
1878 struct_len = 40;
1879 break;
1880 case 91:
1881 struct_len = 68;
1882 break;
1883 default:
1884 return -1;
1887 if (!buf) {
1888 len = 0;
1890 if (uLevel > 0) {
1891 len += StrlenExpanded(conn,snum,lp_comment(snum));
1893 if (uLevel > 1) {
1894 len += strlen(lp_pathname(snum)) + 1;
1896 if (buflen) {
1897 *buflen = struct_len;
1899 if (stringspace) {
1900 *stringspace = len;
1902 return struct_len + len;
1905 len = struct_len;
1906 p = *buf;
1907 if ((*buflen) < struct_len) {
1908 return -1;
1911 if (stringbuf) {
1912 p2 = *stringbuf;
1913 l2 = *stringspace;
1914 } else {
1915 p2 = p + struct_len;
1916 l2 = (*buflen) - struct_len;
1919 if (!baseaddr) {
1920 baseaddr = p;
1923 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1925 if (uLevel > 0) {
1926 int type;
1928 SCVAL(p,13,0);
1929 type = STYPE_DISKTREE;
1930 if (lp_print_ok(snum)) {
1931 type = STYPE_PRINTQ;
1933 if (strequal("IPC",lp_fstype(snum))) {
1934 type = STYPE_IPC;
1936 SSVAL(p,14,type); /* device type */
1937 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1938 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1941 if (uLevel > 1) {
1942 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1943 SSVALS(p,22,-1); /* max uses */
1944 SSVAL(p,24,1); /* current uses */
1945 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1946 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1947 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1950 if (uLevel > 2) {
1951 memset(p+40,0,SHPWLEN+2);
1952 SSVAL(p,50,0);
1953 SIVAL(p,52,0);
1954 SSVAL(p,56,0);
1955 SSVAL(p,58,0);
1956 SIVAL(p,60,0);
1957 SSVAL(p,64,0);
1958 SSVAL(p,66,0);
1961 if (stringbuf) {
1962 (*buf) = p + struct_len;
1963 (*buflen) -= struct_len;
1964 (*stringbuf) = p2;
1965 (*stringspace) = l2;
1966 } else {
1967 (*buf) = p2;
1968 (*buflen) -= len;
1971 return len;
1974 static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn,
1975 connection_struct *conn,uint16 vuid,
1976 char *param, int tpscnt,
1977 char *data, int tdscnt,
1978 int mdrcnt,int mprcnt,
1979 char **rdata,char **rparam,
1980 int *rdata_len,int *rparam_len)
1982 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1983 char *str2 = skip_string(param,tpscnt,str1);
1984 char *netname = skip_string(param,tpscnt,str2);
1985 char *p = skip_string(param,tpscnt,netname);
1986 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1987 int snum;
1989 if (!str1 || !str2 || !netname || !p) {
1990 return False;
1993 snum = find_service(netname);
1994 if (snum < 0) {
1995 return False;
1998 /* check it's a supported varient */
1999 if (!prefix_ok(str1,"zWrLh")) {
2000 return False;
2002 if (!check_share_info(uLevel,str2)) {
2003 return False;
2006 *rdata = smb_realloc_limit(*rdata,mdrcnt);
2007 if (!*rdata) {
2008 return False;
2010 p = *rdata;
2011 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
2012 if (*rdata_len < 0) {
2013 return False;
2016 *rparam_len = 6;
2017 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2018 if (!*rparam) {
2019 return False;
2021 SSVAL(*rparam,0,NERR_Success);
2022 SSVAL(*rparam,2,0); /* converter word */
2023 SSVAL(*rparam,4,*rdata_len);
2025 return True;
2028 /****************************************************************************
2029 View the list of available shares.
2031 This function is the server side of the NetShareEnum() RAP call.
2032 It fills the return buffer with share names and share comments.
2033 Note that the return buffer normally (in all known cases) allows only
2034 twelve byte strings for share names (plus one for a nul terminator).
2035 Share names longer than 12 bytes must be skipped.
2036 ****************************************************************************/
2038 static bool api_RNetShareEnum(struct smbd_server_connection *sconn,
2039 connection_struct *conn, uint16 vuid,
2040 char *param, int tpscnt,
2041 char *data, int tdscnt,
2042 int mdrcnt,
2043 int mprcnt,
2044 char **rdata,
2045 char **rparam,
2046 int *rdata_len,
2047 int *rparam_len )
2049 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2050 char *str2 = skip_string(param,tpscnt,str1);
2051 char *p = skip_string(param,tpscnt,str2);
2052 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2053 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2054 char *p2;
2055 int count = 0;
2056 int total=0,counted=0;
2057 bool missed = False;
2058 int i;
2059 int data_len, fixed_len, string_len;
2060 int f_len = 0, s_len = 0;
2062 if (!str1 || !str2 || !p) {
2063 return False;
2066 if (!prefix_ok(str1,"WrLeh")) {
2067 return False;
2069 if (!check_share_info(uLevel,str2)) {
2070 return False;
2073 /* Ensure all the usershares are loaded. */
2074 become_root();
2075 load_registry_shares();
2076 count = load_usershare_shares();
2077 unbecome_root();
2079 data_len = fixed_len = string_len = 0;
2080 for (i=0;i<count;i++) {
2081 fstring servicename_dos;
2082 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2083 continue;
2085 push_ascii_fstring(servicename_dos, lp_servicename(i));
2086 /* Maximum name length = 13. */
2087 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2088 total++;
2089 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2090 if (data_len < buf_len) {
2091 counted++;
2092 fixed_len += f_len;
2093 string_len += s_len;
2094 } else {
2095 missed = True;
2100 *rdata_len = fixed_len + string_len;
2101 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2102 if (!*rdata) {
2103 return False;
2106 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2107 p = *rdata;
2108 f_len = fixed_len;
2109 s_len = string_len;
2111 for( i = 0; i < count; i++ ) {
2112 fstring servicename_dos;
2113 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2114 continue;
2117 push_ascii_fstring(servicename_dos, lp_servicename(i));
2118 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2119 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2120 break;
2125 *rparam_len = 8;
2126 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2127 if (!*rparam) {
2128 return False;
2130 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2131 SSVAL(*rparam,2,0);
2132 SSVAL(*rparam,4,counted);
2133 SSVAL(*rparam,6,total);
2135 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2136 counted,total,uLevel,
2137 buf_len,*rdata_len,mdrcnt));
2139 return True;
2142 /****************************************************************************
2143 Add a share
2144 ****************************************************************************/
2146 static bool api_RNetShareAdd(struct smbd_server_connection *sconn,
2147 connection_struct *conn,uint16 vuid,
2148 char *param, int tpscnt,
2149 char *data, int tdscnt,
2150 int mdrcnt,int mprcnt,
2151 char **rdata,char **rparam,
2152 int *rdata_len,int *rparam_len)
2154 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2155 char *str2 = skip_string(param,tpscnt,str1);
2156 char *p = skip_string(param,tpscnt,str2);
2157 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2158 fstring sharename;
2159 fstring comment;
2160 char *pathname = NULL;
2161 unsigned int offset;
2162 int res = ERRunsup;
2163 size_t converted_size;
2165 WERROR werr = WERR_OK;
2166 TALLOC_CTX *mem_ctx = talloc_tos();
2167 NTSTATUS status;
2168 struct rpc_pipe_client *cli = NULL;
2169 union srvsvc_NetShareInfo info;
2170 struct srvsvc_NetShareInfo2 info2;
2172 if (!str1 || !str2 || !p) {
2173 return False;
2176 /* check it's a supported varient */
2177 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2178 return False;
2180 if (!check_share_info(uLevel,str2)) {
2181 return False;
2183 if (uLevel != 2) {
2184 return False;
2187 /* Do we have a string ? */
2188 if (skip_string(data,mdrcnt,data) == NULL) {
2189 return False;
2191 pull_ascii_fstring(sharename,data);
2193 if (mdrcnt < 28) {
2194 return False;
2197 /* only support disk share adds */
2198 if (SVAL(data,14)!=STYPE_DISKTREE) {
2199 return False;
2202 offset = IVAL(data, 16);
2203 if (offset >= mdrcnt) {
2204 res = ERRinvalidparam;
2205 goto out;
2208 /* Do we have a string ? */
2209 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2210 return False;
2212 pull_ascii_fstring(comment, offset? (data+offset) : "");
2214 offset = IVAL(data, 26);
2216 if (offset >= mdrcnt) {
2217 res = ERRinvalidparam;
2218 goto out;
2221 /* Do we have a string ? */
2222 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2223 return False;
2226 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2227 offset ? (data+offset) : "", &converted_size))
2229 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2230 strerror(errno)));
2233 if (!pathname) {
2234 return false;
2237 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
2238 conn->server_info,
2239 &conn->sconn->client_id,
2240 conn->sconn->msg_ctx,
2241 &cli);
2242 if (!NT_STATUS_IS_OK(status)) {
2243 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2244 nt_errstr(status)));
2245 res = W_ERROR_V(ntstatus_to_werror(status));
2246 goto out;
2249 info2.name = sharename;
2250 info2.type = STYPE_DISKTREE;
2251 info2.comment = comment;
2252 info2.permissions = 0;
2253 info2.max_users = 0;
2254 info2.current_users = 0;
2255 info2.path = pathname;
2256 info2.password = NULL;
2258 info.info2 = &info2;
2260 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2261 cli->srv_name_slash,
2263 &info,
2264 NULL,
2265 &werr);
2266 if (!NT_STATUS_IS_OK(status)) {
2267 res = W_ERROR_V(ntstatus_to_werror(status));
2268 goto out;
2270 if (!W_ERROR_IS_OK(werr)) {
2271 res = W_ERROR_V(werr);
2272 goto out;
2275 *rparam_len = 6;
2276 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2277 if (!*rparam) {
2278 return False;
2280 SSVAL(*rparam,0,NERR_Success);
2281 SSVAL(*rparam,2,0); /* converter word */
2282 SSVAL(*rparam,4,*rdata_len);
2283 *rdata_len = 0;
2285 return True;
2287 out:
2289 *rparam_len = 4;
2290 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2291 if (!*rparam) {
2292 return False;
2294 *rdata_len = 0;
2295 SSVAL(*rparam,0,res);
2296 SSVAL(*rparam,2,0);
2297 return True;
2300 /****************************************************************************
2301 view list of groups available
2302 ****************************************************************************/
2304 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2305 connection_struct *conn,uint16 vuid,
2306 char *param, int tpscnt,
2307 char *data, int tdscnt,
2308 int mdrcnt,int mprcnt,
2309 char **rdata,char **rparam,
2310 int *rdata_len,int *rparam_len)
2312 int i;
2313 int errflags=0;
2314 int resume_context, cli_buf_size;
2315 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2316 char *str2 = skip_string(param,tpscnt,str1);
2317 char *p = skip_string(param,tpscnt,str2);
2319 uint32_t num_groups;
2320 uint32_t resume_handle;
2321 struct rpc_pipe_client *samr_pipe;
2322 struct policy_handle samr_handle, domain_handle;
2323 NTSTATUS status;
2325 if (!str1 || !str2 || !p) {
2326 return False;
2329 if (strcmp(str1,"WrLeh") != 0) {
2330 return False;
2333 /* parameters
2334 * W-> resume context (number of users to skip)
2335 * r -> return parameter pointer to receive buffer
2336 * L -> length of receive buffer
2337 * e -> return parameter number of entries
2338 * h -> return parameter total number of users
2341 if (strcmp("B21",str2) != 0) {
2342 return False;
2345 status = rpc_pipe_open_internal(
2346 talloc_tos(), &ndr_table_samr.syntax_id,
2347 conn->server_info, &conn->sconn->client_id,
2348 conn->sconn->msg_ctx, &samr_pipe);
2349 if (!NT_STATUS_IS_OK(status)) {
2350 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2351 nt_errstr(status)));
2352 return false;
2355 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2356 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2357 if (!NT_STATUS_IS_OK(status)) {
2358 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2359 nt_errstr(status)));
2360 return false;
2363 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2364 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2365 get_global_sam_sid(), &domain_handle);
2366 if (!NT_STATUS_IS_OK(status)) {
2367 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2368 nt_errstr(status)));
2369 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2370 return false;
2373 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2374 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2375 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2376 "%d\n", resume_context, cli_buf_size));
2378 *rdata_len = cli_buf_size;
2379 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2380 if (!*rdata) {
2381 return False;
2384 p = *rdata;
2386 errflags = NERR_Success;
2387 num_groups = 0;
2388 resume_handle = 0;
2390 while (true) {
2391 struct samr_SamArray *sam_entries;
2392 uint32_t num_entries;
2394 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2395 &domain_handle,
2396 &resume_handle,
2397 &sam_entries, 1,
2398 &num_entries);
2399 if (!NT_STATUS_IS_OK(status)) {
2400 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2401 "%s\n", nt_errstr(status)));
2402 break;
2405 if (num_entries == 0) {
2406 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2407 "no entries -- done\n"));
2408 break;
2411 for(i=0; i<num_entries; i++) {
2412 const char *name;
2414 name = sam_entries->entries[i].name.string;
2416 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2417 /* set overflow error */
2418 DEBUG(3,("overflow on entry %d group %s\n", i,
2419 name));
2420 errflags=234;
2421 break;
2424 /* truncate the name at 21 chars. */
2425 memset(p, 0, 21);
2426 strlcpy(p, name, 21);
2427 DEBUG(10,("adding entry %d group %s\n", i, p));
2428 p += 21;
2429 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2430 * idea why... */
2431 num_groups += 1;
2434 if (errflags != NERR_Success) {
2435 break;
2438 TALLOC_FREE(sam_entries);
2441 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2442 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2444 *rdata_len = PTR_DIFF(p,*rdata);
2446 *rparam_len = 8;
2447 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2448 if (!*rparam) {
2449 return False;
2451 SSVAL(*rparam, 0, errflags);
2452 SSVAL(*rparam, 2, 0); /* converter word */
2453 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2454 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2456 return(True);
2459 /*******************************************************************
2460 Get groups that a user is a member of.
2461 ******************************************************************/
2463 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2464 connection_struct *conn,uint16 vuid,
2465 char *param, int tpscnt,
2466 char *data, int tdscnt,
2467 int mdrcnt,int mprcnt,
2468 char **rdata,char **rparam,
2469 int *rdata_len,int *rparam_len)
2471 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2472 char *str2 = skip_string(param,tpscnt,str1);
2473 char *UserName = skip_string(param,tpscnt,str2);
2474 char *p = skip_string(param,tpscnt,UserName);
2475 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2476 const char *level_string;
2477 int count=0;
2478 bool ret = False;
2479 uint32_t i;
2480 char *endp = NULL;
2482 struct rpc_pipe_client *samr_pipe;
2483 struct policy_handle samr_handle, domain_handle, user_handle;
2484 struct lsa_String name;
2485 struct lsa_Strings names;
2486 struct samr_Ids type, rid;
2487 struct samr_RidWithAttributeArray *rids;
2488 NTSTATUS status;
2490 if (!str1 || !str2 || !UserName || !p) {
2491 return False;
2494 *rparam_len = 8;
2495 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2496 if (!*rparam) {
2497 return False;
2500 /* check it's a supported varient */
2502 if ( strcmp(str1,"zWrLeh") != 0 )
2503 return False;
2505 switch( uLevel ) {
2506 case 0:
2507 level_string = "B21";
2508 break;
2509 default:
2510 return False;
2513 if (strcmp(level_string,str2) != 0)
2514 return False;
2516 *rdata_len = mdrcnt + 1024;
2517 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2518 if (!*rdata) {
2519 return False;
2522 SSVAL(*rparam,0,NERR_Success);
2523 SSVAL(*rparam,2,0); /* converter word */
2525 p = *rdata;
2526 endp = *rdata + *rdata_len;
2528 status = rpc_pipe_open_internal(
2529 talloc_tos(), &ndr_table_samr.syntax_id,
2530 conn->server_info, &conn->sconn->client_id,
2531 conn->sconn->msg_ctx, &samr_pipe);
2532 if (!NT_STATUS_IS_OK(status)) {
2533 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2534 nt_errstr(status)));
2535 return false;
2538 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2539 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2540 if (!NT_STATUS_IS_OK(status)) {
2541 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2542 nt_errstr(status)));
2543 return false;
2546 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2547 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2548 get_global_sam_sid(), &domain_handle);
2549 if (!NT_STATUS_IS_OK(status)) {
2550 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2551 nt_errstr(status)));
2552 goto close_sam;
2555 name.string = UserName;
2557 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2558 &domain_handle, 1, &name,
2559 &rid, &type);
2560 if (!NT_STATUS_IS_OK(status)) {
2561 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2562 nt_errstr(status)));
2563 goto close_domain;
2566 if (type.ids[0] != SID_NAME_USER) {
2567 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2568 sid_type_lookup(type.ids[0])));
2569 goto close_domain;
2572 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2573 &domain_handle,
2574 SAMR_USER_ACCESS_GET_GROUPS,
2575 rid.ids[0], &user_handle);
2576 if (!NT_STATUS_IS_OK(status)) {
2577 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2578 nt_errstr(status)));
2579 goto close_domain;
2582 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2583 &user_handle, &rids);
2584 if (!NT_STATUS_IS_OK(status)) {
2585 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2586 nt_errstr(status)));
2587 goto close_user;
2590 for (i=0; i<rids->count; i++) {
2592 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2593 &domain_handle,
2594 1, &rids->rids[i].rid,
2595 &names, &type);
2596 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2597 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2598 p += 21;
2599 count++;
2603 *rdata_len = PTR_DIFF(p,*rdata);
2605 SSVAL(*rparam,4,count); /* is this right?? */
2606 SSVAL(*rparam,6,count); /* is this right?? */
2608 ret = True;
2610 close_user:
2611 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2612 close_domain:
2613 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2614 close_sam:
2615 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2617 return ret;
2620 /*******************************************************************
2621 Get all users.
2622 ******************************************************************/
2624 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2625 connection_struct *conn, uint16 vuid,
2626 char *param, int tpscnt,
2627 char *data, int tdscnt,
2628 int mdrcnt,int mprcnt,
2629 char **rdata,char **rparam,
2630 int *rdata_len,int *rparam_len)
2632 int count_sent=0;
2633 int num_users=0;
2634 int errflags=0;
2635 int i, resume_context, cli_buf_size;
2636 uint32_t resume_handle;
2638 struct rpc_pipe_client *samr_pipe;
2639 struct policy_handle samr_handle, domain_handle;
2640 NTSTATUS status;
2642 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2643 char *str2 = skip_string(param,tpscnt,str1);
2644 char *p = skip_string(param,tpscnt,str2);
2645 char *endp = NULL;
2647 if (!str1 || !str2 || !p) {
2648 return False;
2651 if (strcmp(str1,"WrLeh") != 0)
2652 return False;
2653 /* parameters
2654 * W-> resume context (number of users to skip)
2655 * r -> return parameter pointer to receive buffer
2656 * L -> length of receive buffer
2657 * e -> return parameter number of entries
2658 * h -> return parameter total number of users
2661 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2662 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2663 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2664 resume_context, cli_buf_size));
2666 *rparam_len = 8;
2667 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2668 if (!*rparam) {
2669 return False;
2672 /* check it's a supported varient */
2673 if (strcmp("B21",str2) != 0)
2674 return False;
2676 *rdata_len = cli_buf_size;
2677 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2678 if (!*rdata) {
2679 return False;
2682 p = *rdata;
2683 endp = *rdata + *rdata_len;
2685 status = rpc_pipe_open_internal(
2686 talloc_tos(), &ndr_table_samr.syntax_id,
2687 conn->server_info, &conn->sconn->client_id,
2688 conn->sconn->msg_ctx, &samr_pipe);
2689 if (!NT_STATUS_IS_OK(status)) {
2690 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2691 nt_errstr(status)));
2692 return false;
2695 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2696 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2697 if (!NT_STATUS_IS_OK(status)) {
2698 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2699 nt_errstr(status)));
2700 return false;
2703 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2704 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2705 get_global_sam_sid(), &domain_handle);
2706 if (!NT_STATUS_IS_OK(status)) {
2707 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2708 nt_errstr(status)));
2709 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2710 return false;
2713 errflags=NERR_Success;
2715 resume_handle = 0;
2717 while (true) {
2718 struct samr_SamArray *sam_entries;
2719 uint32_t num_entries;
2721 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2722 &domain_handle,
2723 &resume_handle,
2724 0, &sam_entries, 1,
2725 &num_entries);
2727 if (!NT_STATUS_IS_OK(status)) {
2728 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2729 "%s\n", nt_errstr(status)));
2730 break;
2733 if (num_entries == 0) {
2734 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2735 "no entries -- done\n"));
2736 break;
2739 for (i=0; i<num_entries; i++) {
2740 const char *name;
2742 name = sam_entries->entries[i].name.string;
2744 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2745 &&(strlen(name)<=21)) {
2746 strlcpy(p,name,PTR_DIFF(endp,p));
2747 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2748 "username %s\n",count_sent,p));
2749 p += 21;
2750 count_sent++;
2751 } else {
2752 /* set overflow error */
2753 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2754 "username %s\n",count_sent,name));
2755 errflags=234;
2756 break;
2760 if (errflags != NERR_Success) {
2761 break;
2764 TALLOC_FREE(sam_entries);
2767 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2768 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2770 *rdata_len = PTR_DIFF(p,*rdata);
2772 SSVAL(*rparam,0,errflags);
2773 SSVAL(*rparam,2,0); /* converter word */
2774 SSVAL(*rparam,4,count_sent); /* is this right?? */
2775 SSVAL(*rparam,6,num_users); /* is this right?? */
2777 return True;
2780 /****************************************************************************
2781 Get the time of day info.
2782 ****************************************************************************/
2784 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2785 connection_struct *conn,uint16 vuid,
2786 char *param, int tpscnt,
2787 char *data, int tdscnt,
2788 int mdrcnt,int mprcnt,
2789 char **rdata,char **rparam,
2790 int *rdata_len,int *rparam_len)
2792 struct tm *t;
2793 time_t unixdate = time(NULL);
2794 char *p;
2796 *rparam_len = 4;
2797 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2798 if (!*rparam) {
2799 return False;
2802 *rdata_len = 21;
2803 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2804 if (!*rdata) {
2805 return False;
2808 SSVAL(*rparam,0,NERR_Success);
2809 SSVAL(*rparam,2,0); /* converter word */
2811 p = *rdata;
2813 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2814 by NT in a "net time" operation,
2815 it seems to ignore the one below */
2817 /* the client expects to get localtime, not GMT, in this bit
2818 (I think, this needs testing) */
2819 t = localtime(&unixdate);
2820 if (!t) {
2821 return False;
2824 SIVAL(p,4,0); /* msecs ? */
2825 SCVAL(p,8,t->tm_hour);
2826 SCVAL(p,9,t->tm_min);
2827 SCVAL(p,10,t->tm_sec);
2828 SCVAL(p,11,0); /* hundredths of seconds */
2829 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2830 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2831 SCVAL(p,16,t->tm_mday);
2832 SCVAL(p,17,t->tm_mon + 1);
2833 SSVAL(p,18,1900+t->tm_year);
2834 SCVAL(p,20,t->tm_wday);
2836 return True;
2839 /****************************************************************************
2840 Set the user password.
2841 *****************************************************************************/
2843 static bool api_SetUserPassword(struct smbd_server_connection *sconn,
2844 connection_struct *conn,uint16 vuid,
2845 char *param, int tpscnt,
2846 char *data, int tdscnt,
2847 int mdrcnt,int mprcnt,
2848 char **rdata,char **rparam,
2849 int *rdata_len,int *rparam_len)
2851 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2852 char *p = NULL;
2853 fstring user;
2854 fstring pass1,pass2;
2855 TALLOC_CTX *mem_ctx = talloc_tos();
2856 NTSTATUS status;
2857 struct rpc_pipe_client *cli = NULL;
2858 struct policy_handle connect_handle, domain_handle, user_handle;
2859 struct lsa_String domain_name;
2860 struct dom_sid2 *domain_sid;
2861 struct lsa_String names;
2862 struct samr_Ids rids;
2863 struct samr_Ids types;
2864 struct samr_Password old_lm_hash;
2865 struct samr_Password new_lm_hash;
2866 int errcode = NERR_badpass;
2867 uint32_t rid;
2868 int encrypted;
2869 int min_pwd_length;
2871 /* Skip 2 strings. */
2872 p = skip_string(param,tpscnt,np);
2873 p = skip_string(param,tpscnt,p);
2875 if (!np || !p) {
2876 return False;
2879 /* Do we have a string ? */
2880 if (skip_string(param,tpscnt,p) == NULL) {
2881 return False;
2883 pull_ascii_fstring(user,p);
2885 p = skip_string(param,tpscnt,p);
2886 if (!p) {
2887 return False;
2890 memset(pass1,'\0',sizeof(pass1));
2891 memset(pass2,'\0',sizeof(pass2));
2893 * We use 31 here not 32 as we're checking
2894 * the last byte we want to access is safe.
2896 if (!is_offset_safe(param,tpscnt,p,31)) {
2897 return False;
2899 memcpy(pass1,p,16);
2900 memcpy(pass2,p+16,16);
2902 encrypted = get_safe_SVAL(param,tpscnt,p+32,0,-1);
2903 if (encrypted == -1) {
2904 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2905 goto out;
2908 min_pwd_length = get_safe_SVAL(param,tpscnt,p+34,0,-1);
2909 if (min_pwd_length == -1) {
2910 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2911 goto out;
2914 *rparam_len = 4;
2915 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2916 if (!*rparam) {
2917 return False;
2920 *rdata_len = 0;
2922 DEBUG(3,("Set password for <%s> (encrypted: %d, min_pwd_length: %d)\n",
2923 user, encrypted, min_pwd_length));
2925 ZERO_STRUCT(connect_handle);
2926 ZERO_STRUCT(domain_handle);
2927 ZERO_STRUCT(user_handle);
2929 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
2930 conn->server_info,
2931 &conn->sconn->client_id,
2932 conn->sconn->msg_ctx,
2933 &cli);
2934 if (!NT_STATUS_IS_OK(status)) {
2935 DEBUG(0,("api_SetUserPassword: could not connect to samr: %s\n",
2936 nt_errstr(status)));
2937 errcode = W_ERROR_V(ntstatus_to_werror(status));
2938 goto out;
2941 status = rpccli_samr_Connect2(cli, mem_ctx,
2942 global_myname(),
2943 SAMR_ACCESS_CONNECT_TO_SERVER |
2944 SAMR_ACCESS_ENUM_DOMAINS |
2945 SAMR_ACCESS_LOOKUP_DOMAIN,
2946 &connect_handle);
2947 if (!NT_STATUS_IS_OK(status)) {
2948 errcode = W_ERROR_V(ntstatus_to_werror(status));
2949 goto out;
2952 init_lsa_String(&domain_name, get_global_sam_name());
2954 status = rpccli_samr_LookupDomain(cli, mem_ctx,
2955 &connect_handle,
2956 &domain_name,
2957 &domain_sid);
2958 if (!NT_STATUS_IS_OK(status)) {
2959 errcode = W_ERROR_V(ntstatus_to_werror(status));
2960 goto out;
2963 status = rpccli_samr_OpenDomain(cli, mem_ctx,
2964 &connect_handle,
2965 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2966 domain_sid,
2967 &domain_handle);
2968 if (!NT_STATUS_IS_OK(status)) {
2969 errcode = W_ERROR_V(ntstatus_to_werror(status));
2970 goto out;
2973 init_lsa_String(&names, user);
2975 status = rpccli_samr_LookupNames(cli, mem_ctx,
2976 &domain_handle,
2978 &names,
2979 &rids,
2980 &types);
2981 if (!NT_STATUS_IS_OK(status)) {
2982 errcode = W_ERROR_V(ntstatus_to_werror(status));
2983 goto out;
2986 if (rids.count != 1) {
2987 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
2988 goto out;
2990 if (rids.count != types.count) {
2991 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2992 goto out;
2994 if (types.ids[0] != SID_NAME_USER) {
2995 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2996 goto out;
2999 rid = rids.ids[0];
3001 status = rpccli_samr_OpenUser(cli, mem_ctx,
3002 &domain_handle,
3003 SAMR_USER_ACCESS_CHANGE_PASSWORD,
3004 rid,
3005 &user_handle);
3006 if (!NT_STATUS_IS_OK(status)) {
3007 errcode = W_ERROR_V(ntstatus_to_werror(status));
3008 goto out;
3011 if (encrypted == 0) {
3012 E_deshash(pass1, old_lm_hash.hash);
3013 E_deshash(pass2, new_lm_hash.hash);
3014 } else {
3015 ZERO_STRUCT(old_lm_hash);
3016 ZERO_STRUCT(new_lm_hash);
3017 memcpy(old_lm_hash.hash, pass1, MIN(strlen(pass1), 16));
3018 memcpy(new_lm_hash.hash, pass1, MIN(strlen(pass2), 16));
3021 status = rpccli_samr_ChangePasswordUser(cli, mem_ctx,
3022 &user_handle,
3023 true, /* lm_present */
3024 &old_lm_hash,
3025 &new_lm_hash,
3026 false, /* nt_present */
3027 NULL, /* old_nt_crypted */
3028 NULL, /* new_nt_crypted */
3029 false, /* cross1_present */
3030 NULL, /* nt_cross */
3031 false, /* cross2_present */
3032 NULL); /* lm_cross */
3033 if (!NT_STATUS_IS_OK(status)) {
3034 errcode = W_ERROR_V(ntstatus_to_werror(status));
3035 goto out;
3038 errcode = NERR_Success;
3039 out:
3041 if (cli && is_valid_policy_hnd(&user_handle)) {
3042 rpccli_samr_Close(cli, mem_ctx, &user_handle);
3044 if (cli && is_valid_policy_hnd(&domain_handle)) {
3045 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
3047 if (cli && is_valid_policy_hnd(&connect_handle)) {
3048 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
3051 memset((char *)pass1,'\0',sizeof(fstring));
3052 memset((char *)pass2,'\0',sizeof(fstring));
3054 SSVAL(*rparam,0,errcode);
3055 SSVAL(*rparam,2,0); /* converter word */
3056 return(True);
3059 /****************************************************************************
3060 Set the user password (SamOEM version - gets plaintext).
3061 ****************************************************************************/
3063 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
3064 connection_struct *conn,uint16 vuid,
3065 char *param, int tpscnt,
3066 char *data, int tdscnt,
3067 int mdrcnt,int mprcnt,
3068 char **rdata,char **rparam,
3069 int *rdata_len,int *rparam_len)
3071 fstring user;
3072 char *p = get_safe_str_ptr(param,tpscnt,param,2);
3074 TALLOC_CTX *mem_ctx = talloc_tos();
3075 NTSTATUS status;
3076 struct rpc_pipe_client *cli = NULL;
3077 struct lsa_AsciiString server, account;
3078 struct samr_CryptPassword password;
3079 struct samr_Password hash;
3080 int errcode = NERR_badpass;
3081 int bufsize;
3083 *rparam_len = 4;
3084 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3085 if (!*rparam) {
3086 return False;
3089 if (!p) {
3090 return False;
3092 *rdata_len = 0;
3094 SSVAL(*rparam,0,NERR_badpass);
3097 * Check the parameter definition is correct.
3100 /* Do we have a string ? */
3101 if (skip_string(param,tpscnt,p) == 0) {
3102 return False;
3104 if(!strequal(p, "zsT")) {
3105 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3106 return False;
3108 p = skip_string(param, tpscnt, p);
3109 if (!p) {
3110 return False;
3113 /* Do we have a string ? */
3114 if (skip_string(param,tpscnt,p) == 0) {
3115 return False;
3117 if(!strequal(p, "B516B16")) {
3118 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3119 return False;
3121 p = skip_string(param,tpscnt,p);
3122 if (!p) {
3123 return False;
3125 /* Do we have a string ? */
3126 if (skip_string(param,tpscnt,p) == 0) {
3127 return False;
3129 p += pull_ascii_fstring(user,p);
3131 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3133 if (tdscnt != 532) {
3134 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3135 goto out;
3138 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3139 if (bufsize != 532) {
3140 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3141 goto out;
3144 memcpy(password.data, data, 516);
3145 memcpy(hash.hash, data+516, 16);
3147 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3148 conn->server_info,
3149 &conn->sconn->client_id,
3150 conn->sconn->msg_ctx,
3151 &cli);
3152 if (!NT_STATUS_IS_OK(status)) {
3153 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3154 nt_errstr(status)));
3155 errcode = W_ERROR_V(ntstatus_to_werror(status));
3156 goto out;
3159 init_lsa_AsciiString(&server, global_myname());
3160 init_lsa_AsciiString(&account, user);
3162 status = rpccli_samr_OemChangePasswordUser2(cli, mem_ctx,
3163 &server,
3164 &account,
3165 &password,
3166 &hash);
3167 if (!NT_STATUS_IS_OK(status)) {
3168 errcode = W_ERROR_V(ntstatus_to_werror(status));
3169 goto out;
3172 errcode = NERR_Success;
3173 out:
3174 SSVAL(*rparam,0,errcode);
3175 SSVAL(*rparam,2,0); /* converter word */
3177 return(True);
3180 /****************************************************************************
3181 delete a print job
3182 Form: <W> <>
3183 ****************************************************************************/
3185 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3186 connection_struct *conn,uint16 vuid,
3187 char *param, int tpscnt,
3188 char *data, int tdscnt,
3189 int mdrcnt,int mprcnt,
3190 char **rdata,char **rparam,
3191 int *rdata_len,int *rparam_len)
3193 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3194 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3195 char *str2 = skip_string(param,tpscnt,str1);
3196 char *p = skip_string(param,tpscnt,str2);
3197 uint32 jobid;
3198 fstring sharename;
3199 int errcode;
3200 WERROR werr = WERR_OK;
3202 TALLOC_CTX *mem_ctx = talloc_tos();
3203 NTSTATUS status;
3204 struct rpc_pipe_client *cli = NULL;
3205 struct policy_handle handle;
3206 struct spoolss_DevmodeContainer devmode_ctr;
3207 enum spoolss_JobControl command;
3209 if (!str1 || !str2 || !p) {
3210 return False;
3213 * We use 1 here not 2 as we're checking
3214 * the last byte we want to access is safe.
3216 if (!is_offset_safe(param,tpscnt,p,1)) {
3217 return False;
3219 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3220 return False;
3222 /* check it's a supported varient */
3223 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3224 return(False);
3226 *rparam_len = 4;
3227 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3228 if (!*rparam) {
3229 return False;
3231 *rdata_len = 0;
3233 ZERO_STRUCT(handle);
3235 status = rpc_connect_spoolss_pipe(conn, &cli);
3236 if (!NT_STATUS_IS_OK(status)) {
3237 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3238 nt_errstr(status)));
3239 errcode = W_ERROR_V(ntstatus_to_werror(status));
3240 goto out;
3243 ZERO_STRUCT(devmode_ctr);
3245 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3246 sharename,
3247 "RAW",
3248 devmode_ctr,
3249 JOB_ACCESS_ADMINISTER,
3250 &handle,
3251 &werr);
3252 if (!NT_STATUS_IS_OK(status)) {
3253 errcode = W_ERROR_V(ntstatus_to_werror(status));
3254 goto out;
3256 if (!W_ERROR_IS_OK(werr)) {
3257 errcode = W_ERROR_V(werr);
3258 goto out;
3261 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3262 * and NERR_DestNotFound if share did not exist */
3264 errcode = NERR_Success;
3266 switch (function) {
3267 case 81: /* delete */
3268 command = SPOOLSS_JOB_CONTROL_DELETE;
3269 break;
3270 case 82: /* pause */
3271 command = SPOOLSS_JOB_CONTROL_PAUSE;
3272 break;
3273 case 83: /* resume */
3274 command = SPOOLSS_JOB_CONTROL_RESUME;
3275 break;
3276 default:
3277 errcode = NERR_notsupported;
3278 goto out;
3281 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3282 &handle,
3283 jobid,
3284 NULL, /* unique ptr ctr */
3285 command,
3286 &werr);
3287 if (!NT_STATUS_IS_OK(status)) {
3288 errcode = W_ERROR_V(ntstatus_to_werror(status));
3289 goto out;
3291 if (!W_ERROR_IS_OK(werr)) {
3292 errcode = W_ERROR_V(werr);
3293 goto out;
3296 out:
3297 if (cli && is_valid_policy_hnd(&handle)) {
3298 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3301 SSVAL(*rparam,0,errcode);
3302 SSVAL(*rparam,2,0); /* converter word */
3304 return(True);
3307 /****************************************************************************
3308 Purge a print queue - or pause or resume it.
3309 ****************************************************************************/
3311 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3312 connection_struct *conn,uint16 vuid,
3313 char *param, int tpscnt,
3314 char *data, int tdscnt,
3315 int mdrcnt,int mprcnt,
3316 char **rdata,char **rparam,
3317 int *rdata_len,int *rparam_len)
3319 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3320 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3321 char *str2 = skip_string(param,tpscnt,str1);
3322 char *QueueName = skip_string(param,tpscnt,str2);
3323 int errcode = NERR_notsupported;
3324 WERROR werr = WERR_OK;
3325 NTSTATUS status;
3327 TALLOC_CTX *mem_ctx = talloc_tos();
3328 struct rpc_pipe_client *cli = NULL;
3329 struct policy_handle handle;
3330 struct spoolss_SetPrinterInfoCtr info_ctr;
3331 struct spoolss_DevmodeContainer devmode_ctr;
3332 struct sec_desc_buf secdesc_ctr;
3333 enum spoolss_PrinterControl command;
3335 if (!str1 || !str2 || !QueueName) {
3336 return False;
3339 /* check it's a supported varient */
3340 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3341 return(False);
3343 *rparam_len = 4;
3344 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3345 if (!*rparam) {
3346 return False;
3348 *rdata_len = 0;
3350 if (skip_string(param,tpscnt,QueueName) == NULL) {
3351 return False;
3354 ZERO_STRUCT(handle);
3356 status = rpc_connect_spoolss_pipe(conn, &cli);
3357 if (!NT_STATUS_IS_OK(status)) {
3358 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3359 nt_errstr(status)));
3360 errcode = W_ERROR_V(ntstatus_to_werror(status));
3361 goto out;
3364 ZERO_STRUCT(devmode_ctr);
3366 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3367 QueueName,
3368 NULL,
3369 devmode_ctr,
3370 SEC_FLAG_MAXIMUM_ALLOWED,
3371 &handle,
3372 &werr);
3373 if (!NT_STATUS_IS_OK(status)) {
3374 errcode = W_ERROR_V(ntstatus_to_werror(status));
3375 goto out;
3377 if (!W_ERROR_IS_OK(werr)) {
3378 errcode = W_ERROR_V(werr);
3379 goto out;
3382 switch (function) {
3383 case 74: /* Pause queue */
3384 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3385 break;
3386 case 75: /* Resume queue */
3387 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3388 break;
3389 case 103: /* Purge */
3390 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3391 break;
3392 default:
3393 werr = WERR_NOT_SUPPORTED;
3394 break;
3397 if (!W_ERROR_IS_OK(werr)) {
3398 errcode = W_ERROR_V(werr);
3399 goto out;
3402 ZERO_STRUCT(info_ctr);
3403 ZERO_STRUCT(secdesc_ctr);
3405 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3406 &handle,
3407 &info_ctr,
3408 &devmode_ctr,
3409 &secdesc_ctr,
3410 command,
3411 &werr);
3412 if (!NT_STATUS_IS_OK(status)) {
3413 errcode = W_ERROR_V(ntstatus_to_werror(status));
3414 goto out;
3416 if (!W_ERROR_IS_OK(werr)) {
3417 errcode = W_ERROR_V(werr);
3418 goto out;
3421 errcode = W_ERROR_V(werr);
3423 out:
3425 if (cli && is_valid_policy_hnd(&handle)) {
3426 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3429 SSVAL(*rparam,0,errcode);
3430 SSVAL(*rparam,2,0); /* converter word */
3432 return(True);
3435 /****************************************************************************
3436 set the property of a print job (undocumented?)
3437 ? function = 0xb -> set name of print job
3438 ? function = 0x6 -> move print job up/down
3439 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3440 or <WWsTP> <WB21BB16B10zWWzDDz>
3441 ****************************************************************************/
3443 static int check_printjob_info(struct pack_desc* desc,
3444 int uLevel, char* id)
3446 desc->subformat = NULL;
3447 switch( uLevel ) {
3448 case 0: desc->format = "W"; break;
3449 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3450 case 2: desc->format = "WWzWWDDzz"; break;
3451 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3452 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3453 default:
3454 DEBUG(0,("check_printjob_info: invalid level %d\n",
3455 uLevel ));
3456 return False;
3458 if (id == NULL || strcmp(desc->format,id) != 0) {
3459 DEBUG(0,("check_printjob_info: invalid format %s\n",
3460 id ? id : "<NULL>" ));
3461 return False;
3463 return True;
3466 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3467 connection_struct *conn, uint16 vuid,
3468 char *param, int tpscnt,
3469 char *data, int tdscnt,
3470 int mdrcnt,int mprcnt,
3471 char **rdata,char **rparam,
3472 int *rdata_len,int *rparam_len)
3474 struct pack_desc desc;
3475 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3476 char *str2 = skip_string(param,tpscnt,str1);
3477 char *p = skip_string(param,tpscnt,str2);
3478 uint32 jobid;
3479 fstring sharename;
3480 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3481 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3482 int errcode;
3484 TALLOC_CTX *mem_ctx = talloc_tos();
3485 WERROR werr;
3486 NTSTATUS status;
3487 struct rpc_pipe_client *cli = NULL;
3488 struct policy_handle handle;
3489 struct spoolss_DevmodeContainer devmode_ctr;
3490 struct spoolss_JobInfoContainer ctr;
3491 union spoolss_JobInfo info;
3492 struct spoolss_SetJobInfo1 info1;
3494 if (!str1 || !str2 || !p) {
3495 return False;
3498 * We use 1 here not 2 as we're checking
3499 * the last byte we want to access is safe.
3501 if (!is_offset_safe(param,tpscnt,p,1)) {
3502 return False;
3504 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3505 return False;
3506 *rparam_len = 4;
3507 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3508 if (!*rparam) {
3509 return False;
3512 *rdata_len = 0;
3514 /* check it's a supported varient */
3515 if ((strcmp(str1,"WWsTP")) ||
3516 (!check_printjob_info(&desc,uLevel,str2)))
3517 return(False);
3519 errcode = NERR_notsupported;
3521 switch (function) {
3522 case 0xb:
3523 /* change print job name, data gives the name */
3524 break;
3525 default:
3526 goto out;
3529 ZERO_STRUCT(handle);
3531 status = rpc_connect_spoolss_pipe(conn, &cli);
3532 if (!NT_STATUS_IS_OK(status)) {
3533 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3534 nt_errstr(status)));
3535 errcode = W_ERROR_V(ntstatus_to_werror(status));
3536 goto out;
3539 ZERO_STRUCT(devmode_ctr);
3541 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3542 sharename,
3543 "RAW",
3544 devmode_ctr,
3545 PRINTER_ACCESS_USE,
3546 &handle,
3547 &werr);
3548 if (!NT_STATUS_IS_OK(status)) {
3549 errcode = W_ERROR_V(ntstatus_to_werror(status));
3550 goto out;
3552 if (!W_ERROR_IS_OK(werr)) {
3553 errcode = W_ERROR_V(werr);
3554 goto out;
3557 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3558 &handle,
3559 jobid,
3560 1, /* level */
3561 0, /* offered */
3562 &info);
3563 if (!W_ERROR_IS_OK(werr)) {
3564 errcode = W_ERROR_V(werr);
3565 goto out;
3568 ZERO_STRUCT(ctr);
3570 info1.job_id = info.info1.job_id;
3571 info1.printer_name = info.info1.printer_name;
3572 info1.user_name = info.info1.user_name;
3573 info1.document_name = data;
3574 info1.data_type = info.info1.data_type;
3575 info1.text_status = info.info1.text_status;
3576 info1.status = info.info1.status;
3577 info1.priority = info.info1.priority;
3578 info1.position = info.info1.position;
3579 info1.total_pages = info.info1.total_pages;
3580 info1.pages_printed = info.info1.pages_printed;
3581 info1.submitted = info.info1.submitted;
3583 ctr.level = 1;
3584 ctr.info.info1 = &info1;
3586 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3587 &handle,
3588 jobid,
3589 &ctr,
3591 &werr);
3592 if (!NT_STATUS_IS_OK(status)) {
3593 errcode = W_ERROR_V(ntstatus_to_werror(status));
3594 goto out;
3596 if (!W_ERROR_IS_OK(werr)) {
3597 errcode = W_ERROR_V(werr);
3598 goto out;
3601 errcode = NERR_Success;
3602 out:
3604 if (cli && is_valid_policy_hnd(&handle)) {
3605 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3608 SSVALS(*rparam,0,errcode);
3609 SSVAL(*rparam,2,0); /* converter word */
3611 return(True);
3615 /****************************************************************************
3616 Get info about the server.
3617 ****************************************************************************/
3619 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3620 connection_struct *conn,uint16 vuid,
3621 char *param, int tpscnt,
3622 char *data, int tdscnt,
3623 int mdrcnt,int mprcnt,
3624 char **rdata,char **rparam,
3625 int *rdata_len,int *rparam_len)
3627 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3628 char *str2 = skip_string(param,tpscnt,str1);
3629 char *p = skip_string(param,tpscnt,str2);
3630 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3631 char *p2;
3632 int struct_len;
3634 NTSTATUS status;
3635 WERROR werr;
3636 TALLOC_CTX *mem_ctx = talloc_tos();
3637 struct rpc_pipe_client *cli = NULL;
3638 union srvsvc_NetSrvInfo info;
3639 int errcode;
3641 if (!str1 || !str2 || !p) {
3642 return False;
3645 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3647 /* check it's a supported varient */
3648 if (!prefix_ok(str1,"WrLh")) {
3649 return False;
3652 switch( uLevel ) {
3653 case 0:
3654 if (strcmp(str2,"B16") != 0) {
3655 return False;
3657 struct_len = 16;
3658 break;
3659 case 1:
3660 if (strcmp(str2,"B16BBDz") != 0) {
3661 return False;
3663 struct_len = 26;
3664 break;
3665 case 2:
3666 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3667 return False;
3669 struct_len = 134;
3670 break;
3671 case 3:
3672 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3673 return False;
3675 struct_len = 144;
3676 break;
3677 case 20:
3678 if (strcmp(str2,"DN") != 0) {
3679 return False;
3681 struct_len = 6;
3682 break;
3683 case 50:
3684 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3685 return False;
3687 struct_len = 42;
3688 break;
3689 default:
3690 return False;
3693 *rdata_len = mdrcnt;
3694 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3695 if (!*rdata) {
3696 return False;
3699 p = *rdata;
3700 p2 = p + struct_len;
3702 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3703 conn->server_info,
3704 &conn->sconn->client_id,
3705 conn->sconn->msg_ctx,
3706 &cli);
3707 if (!NT_STATUS_IS_OK(status)) {
3708 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3709 nt_errstr(status)));
3710 errcode = W_ERROR_V(ntstatus_to_werror(status));
3711 goto out;
3714 status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3715 NULL,
3716 101,
3717 &info,
3718 &werr);
3719 if (!NT_STATUS_IS_OK(status)) {
3720 errcode = W_ERROR_V(ntstatus_to_werror(status));
3721 goto out;
3723 if (!W_ERROR_IS_OK(werr)) {
3724 errcode = W_ERROR_V(werr);
3725 goto out;
3728 if (info.info101 == NULL) {
3729 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3730 goto out;
3733 if (uLevel != 20) {
3734 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3735 STR_ASCII|STR_UPPER|STR_TERMINATE);
3737 p += 16;
3738 if (uLevel > 0) {
3739 SCVAL(p,0,info.info101->version_major);
3740 SCVAL(p,1,info.info101->version_minor);
3741 SIVAL(p,2,info.info101->server_type);
3743 if (mdrcnt == struct_len) {
3744 SIVAL(p,6,0);
3745 } else {
3746 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3747 if (mdrcnt - struct_len <= 0) {
3748 return false;
3750 push_ascii(p2,
3751 info.info101->comment,
3752 MIN(mdrcnt - struct_len,
3753 MAX_SERVER_STRING_LENGTH),
3754 STR_TERMINATE);
3755 p2 = skip_string(*rdata,*rdata_len,p2);
3756 if (!p2) {
3757 return False;
3762 if (uLevel > 1) {
3763 return False; /* not yet implemented */
3766 errcode = NERR_Success;
3768 out:
3770 *rdata_len = PTR_DIFF(p2,*rdata);
3772 *rparam_len = 6;
3773 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3774 if (!*rparam) {
3775 return False;
3777 SSVAL(*rparam,0,errcode);
3778 SSVAL(*rparam,2,0); /* converter word */
3779 SSVAL(*rparam,4,*rdata_len);
3781 return True;
3784 /****************************************************************************
3785 Get info about the server.
3786 ****************************************************************************/
3788 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3789 connection_struct *conn,uint16 vuid,
3790 char *param, int tpscnt,
3791 char *data, int tdscnt,
3792 int mdrcnt,int mprcnt,
3793 char **rdata,char **rparam,
3794 int *rdata_len,int *rparam_len)
3796 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3797 char *str2 = skip_string(param,tpscnt,str1);
3798 char *p = skip_string(param,tpscnt,str2);
3799 char *p2;
3800 char *endp;
3801 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3803 if (!str1 || !str2 || !p) {
3804 return False;
3807 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3809 *rparam_len = 6;
3810 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3811 if (!*rparam) {
3812 return False;
3815 /* check it's a supported varient */
3816 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3817 return False;
3820 *rdata_len = mdrcnt + 1024;
3821 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3822 if (!*rdata) {
3823 return False;
3826 SSVAL(*rparam,0,NERR_Success);
3827 SSVAL(*rparam,2,0); /* converter word */
3829 p = *rdata;
3830 endp = *rdata + *rdata_len;
3832 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3833 if (!p2) {
3834 return False;
3837 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3838 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3839 strupper_m(p2);
3840 p2 = skip_string(*rdata,*rdata_len,p2);
3841 if (!p2) {
3842 return False;
3844 p += 4;
3846 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3847 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3848 p2 = skip_string(*rdata,*rdata_len,p2);
3849 if (!p2) {
3850 return False;
3852 p += 4;
3854 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3855 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3856 strupper_m(p2);
3857 p2 = skip_string(*rdata,*rdata_len,p2);
3858 if (!p2) {
3859 return False;
3861 p += 4;
3863 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3864 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3865 p += 2;
3867 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3868 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3869 p2 = skip_string(*rdata,*rdata_len,p2);
3870 if (!p2) {
3871 return False;
3873 p += 4;
3875 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3876 strlcpy(p2,"",PTR_DIFF(endp,p2));
3877 p2 = skip_string(*rdata,*rdata_len,p2);
3878 if (!p2) {
3879 return False;
3881 p += 4;
3883 *rdata_len = PTR_DIFF(p2,*rdata);
3885 SSVAL(*rparam,4,*rdata_len);
3887 return True;
3890 /****************************************************************************
3891 get info about a user
3893 struct user_info_11 {
3894 char usri11_name[21]; 0-20
3895 char usri11_pad; 21
3896 char *usri11_comment; 22-25
3897 char *usri11_usr_comment; 26-29
3898 unsigned short usri11_priv; 30-31
3899 unsigned long usri11_auth_flags; 32-35
3900 long usri11_password_age; 36-39
3901 char *usri11_homedir; 40-43
3902 char *usri11_parms; 44-47
3903 long usri11_last_logon; 48-51
3904 long usri11_last_logoff; 52-55
3905 unsigned short usri11_bad_pw_count; 56-57
3906 unsigned short usri11_num_logons; 58-59
3907 char *usri11_logon_server; 60-63
3908 unsigned short usri11_country_code; 64-65
3909 char *usri11_workstations; 66-69
3910 unsigned long usri11_max_storage; 70-73
3911 unsigned short usri11_units_per_week; 74-75
3912 unsigned char *usri11_logon_hours; 76-79
3913 unsigned short usri11_code_page; 80-81
3916 where:
3918 usri11_name specifies the user name for which information is retrieved
3920 usri11_pad aligns the next data structure element to a word boundary
3922 usri11_comment is a null terminated ASCII comment
3924 usri11_user_comment is a null terminated ASCII comment about the user
3926 usri11_priv specifies the level of the privilege assigned to the user.
3927 The possible values are:
3929 Name Value Description
3930 USER_PRIV_GUEST 0 Guest privilege
3931 USER_PRIV_USER 1 User privilege
3932 USER_PRV_ADMIN 2 Administrator privilege
3934 usri11_auth_flags specifies the account operator privileges. The
3935 possible values are:
3937 Name Value Description
3938 AF_OP_PRINT 0 Print operator
3941 Leach, Naik [Page 28]
3945 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3948 AF_OP_COMM 1 Communications operator
3949 AF_OP_SERVER 2 Server operator
3950 AF_OP_ACCOUNTS 3 Accounts operator
3953 usri11_password_age specifies how many seconds have elapsed since the
3954 password was last changed.
3956 usri11_home_dir points to a null terminated ASCII string that contains
3957 the path name of the user's home directory.
3959 usri11_parms points to a null terminated ASCII string that is set
3960 aside for use by applications.
3962 usri11_last_logon specifies the time when the user last logged on.
3963 This value is stored as the number of seconds elapsed since
3964 00:00:00, January 1, 1970.
3966 usri11_last_logoff specifies the time when the user last logged off.
3967 This value is stored as the number of seconds elapsed since
3968 00:00:00, January 1, 1970. A value of 0 means the last logoff
3969 time is unknown.
3971 usri11_bad_pw_count specifies the number of incorrect passwords
3972 entered since the last successful logon.
3974 usri11_log1_num_logons specifies the number of times this user has
3975 logged on. A value of -1 means the number of logons is unknown.
3977 usri11_logon_server points to a null terminated ASCII string that
3978 contains the name of the server to which logon requests are sent.
3979 A null string indicates logon requests should be sent to the
3980 domain controller.
3982 usri11_country_code specifies the country code for the user's language
3983 of choice.
3985 usri11_workstations points to a null terminated ASCII string that
3986 contains the names of workstations the user may log on from.
3987 There may be up to 8 workstations, with the names separated by
3988 commas. A null strings indicates there are no restrictions.
3990 usri11_max_storage specifies the maximum amount of disk space the user
3991 can occupy. A value of 0xffffffff indicates there are no
3992 restrictions.
3994 usri11_units_per_week specifies the equal number of time units into
3995 which a week is divided. This value must be equal to 168.
3997 usri11_logon_hours points to a 21 byte (168 bits) string that
3998 specifies the time during which the user can log on. Each bit
3999 represents one unique hour in a week. The first bit (bit 0, word
4000 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
4004 Leach, Naik [Page 29]
4008 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4011 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
4012 are no restrictions.
4014 usri11_code_page specifies the code page for the user's language of
4015 choice
4017 All of the pointers in this data structure need to be treated
4018 specially. The pointer is a 32 bit pointer. The higher 16 bits need
4019 to be ignored. The converter word returned in the parameters section
4020 needs to be subtracted from the lower 16 bits to calculate an offset
4021 into the return buffer where this ASCII string resides.
4023 There is no auxiliary data in the response.
4025 ****************************************************************************/
4027 #define usri11_name 0
4028 #define usri11_pad 21
4029 #define usri11_comment 22
4030 #define usri11_usr_comment 26
4031 #define usri11_full_name 30
4032 #define usri11_priv 34
4033 #define usri11_auth_flags 36
4034 #define usri11_password_age 40
4035 #define usri11_homedir 44
4036 #define usri11_parms 48
4037 #define usri11_last_logon 52
4038 #define usri11_last_logoff 56
4039 #define usri11_bad_pw_count 60
4040 #define usri11_num_logons 62
4041 #define usri11_logon_server 64
4042 #define usri11_country_code 68
4043 #define usri11_workstations 70
4044 #define usri11_max_storage 74
4045 #define usri11_units_per_week 78
4046 #define usri11_logon_hours 80
4047 #define usri11_code_page 84
4048 #define usri11_end 86
4050 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4051 connection_struct *conn, uint16 vuid,
4052 char *param, int tpscnt,
4053 char *data, int tdscnt,
4054 int mdrcnt,int mprcnt,
4055 char **rdata,char **rparam,
4056 int *rdata_len,int *rparam_len)
4058 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4059 char *str2 = skip_string(param,tpscnt,str1);
4060 char *UserName = skip_string(param,tpscnt,str2);
4061 char *p = skip_string(param,tpscnt,UserName);
4062 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4063 char *p2;
4064 char *endp;
4065 const char *level_string;
4067 TALLOC_CTX *mem_ctx = talloc_tos();
4068 NTSTATUS status;
4069 struct rpc_pipe_client *cli = NULL;
4070 struct policy_handle connect_handle, domain_handle, user_handle;
4071 struct lsa_String domain_name;
4072 struct dom_sid2 *domain_sid;
4073 struct lsa_String names;
4074 struct samr_Ids rids;
4075 struct samr_Ids types;
4076 int errcode = W_ERROR_V(WERR_USER_NOT_FOUND);
4077 uint32_t rid;
4078 union samr_UserInfo *info;
4080 if (!str1 || !str2 || !UserName || !p) {
4081 return False;
4084 *rparam_len = 6;
4085 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4086 if (!*rparam) {
4087 return False;
4090 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4092 /* check it's a supported variant */
4093 if (strcmp(str1,"zWrLh") != 0) {
4094 return False;
4096 switch( uLevel ) {
4097 case 0: level_string = "B21"; break;
4098 case 1: level_string = "B21BB16DWzzWz"; break;
4099 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4100 case 10: level_string = "B21Bzzz"; break;
4101 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4102 default: return False;
4105 if (strcmp(level_string,str2) != 0) {
4106 return False;
4109 *rdata_len = mdrcnt + 1024;
4110 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4111 if (!*rdata) {
4112 return False;
4115 p = *rdata;
4116 endp = *rdata + *rdata_len;
4117 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4118 if (!p2) {
4119 return False;
4122 ZERO_STRUCT(connect_handle);
4123 ZERO_STRUCT(domain_handle);
4124 ZERO_STRUCT(user_handle);
4126 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
4127 conn->server_info,
4128 &conn->sconn->client_id,
4129 conn->sconn->msg_ctx,
4130 &cli);
4131 if (!NT_STATUS_IS_OK(status)) {
4132 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4133 nt_errstr(status)));
4134 errcode = W_ERROR_V(ntstatus_to_werror(status));
4135 goto out;
4138 status = rpccli_samr_Connect2(cli, mem_ctx,
4139 global_myname(),
4140 SAMR_ACCESS_CONNECT_TO_SERVER |
4141 SAMR_ACCESS_ENUM_DOMAINS |
4142 SAMR_ACCESS_LOOKUP_DOMAIN,
4143 &connect_handle);
4144 if (!NT_STATUS_IS_OK(status)) {
4145 errcode = W_ERROR_V(ntstatus_to_werror(status));
4146 goto out;
4149 init_lsa_String(&domain_name, get_global_sam_name());
4151 status = rpccli_samr_LookupDomain(cli, mem_ctx,
4152 &connect_handle,
4153 &domain_name,
4154 &domain_sid);
4155 if (!NT_STATUS_IS_OK(status)) {
4156 errcode = W_ERROR_V(ntstatus_to_werror(status));
4157 goto out;
4160 status = rpccli_samr_OpenDomain(cli, mem_ctx,
4161 &connect_handle,
4162 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4163 domain_sid,
4164 &domain_handle);
4165 if (!NT_STATUS_IS_OK(status)) {
4166 errcode = W_ERROR_V(ntstatus_to_werror(status));
4167 goto out;
4170 init_lsa_String(&names, UserName);
4172 status = rpccli_samr_LookupNames(cli, mem_ctx,
4173 &domain_handle,
4175 &names,
4176 &rids,
4177 &types);
4178 if (!NT_STATUS_IS_OK(status)) {
4179 errcode = W_ERROR_V(ntstatus_to_werror(status));
4180 goto out;
4183 if (rids.count != 1) {
4184 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4185 goto out;
4187 if (rids.count != types.count) {
4188 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4189 goto out;
4191 if (types.ids[0] != SID_NAME_USER) {
4192 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4193 goto out;
4196 rid = rids.ids[0];
4198 status = rpccli_samr_OpenUser(cli, mem_ctx,
4199 &domain_handle,
4200 SAMR_USER_ACCESS_GET_LOCALE |
4201 SAMR_USER_ACCESS_GET_LOGONINFO |
4202 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4203 SAMR_USER_ACCESS_GET_GROUPS |
4204 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4205 SEC_STD_READ_CONTROL,
4206 rid,
4207 &user_handle);
4208 if (!NT_STATUS_IS_OK(status)) {
4209 errcode = W_ERROR_V(ntstatus_to_werror(status));
4210 goto out;
4213 status = rpccli_samr_QueryUserInfo2(cli, mem_ctx,
4214 &user_handle,
4215 UserAllInformation,
4216 &info);
4217 if (!NT_STATUS_IS_OK(status)) {
4218 errcode = W_ERROR_V(ntstatus_to_werror(status));
4219 goto out;
4222 memset(p,0,21);
4223 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4225 if (uLevel > 0) {
4226 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4227 *p2 = 0;
4230 if (uLevel >= 10) {
4231 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4232 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4233 p2 = skip_string(*rdata,*rdata_len,p2);
4234 if (!p2) {
4235 return False;
4238 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4239 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4240 p2 = skip_string(*rdata,*rdata_len,p2);
4241 if (!p2) {
4242 return False;
4245 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4246 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4247 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4248 p2 = skip_string(*rdata,*rdata_len,p2);
4249 if (!p2) {
4250 return False;
4254 if (uLevel == 11) {
4255 const char *homedir = info->info21.home_directory.string;
4256 /* modelled after NTAS 3.51 reply */
4257 SSVAL(p,usri11_priv,
4258 (get_current_uid(conn) == sec_initial_uid())?
4259 USER_PRIV_ADMIN:USER_PRIV_USER);
4260 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4261 SIVALS(p,usri11_password_age,-1); /* password age */
4262 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4263 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4264 p2 = skip_string(*rdata,*rdata_len,p2);
4265 if (!p2) {
4266 return False;
4268 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4269 strlcpy(p2,"",PTR_DIFF(endp,p2));
4270 p2 = skip_string(*rdata,*rdata_len,p2);
4271 if (!p2) {
4272 return False;
4274 SIVAL(p,usri11_last_logon,0); /* last logon */
4275 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4276 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4277 SSVALS(p,usri11_num_logons,-1); /* num logons */
4278 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4279 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4280 p2 = skip_string(*rdata,*rdata_len,p2);
4281 if (!p2) {
4282 return False;
4284 SSVAL(p,usri11_country_code,0); /* country code */
4286 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4287 strlcpy(p2,"",PTR_DIFF(endp,p2));
4288 p2 = skip_string(*rdata,*rdata_len,p2);
4289 if (!p2) {
4290 return False;
4293 SIVALS(p,usri11_max_storage,-1); /* max storage */
4294 SSVAL(p,usri11_units_per_week,168); /* units per week */
4295 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4297 /* a simple way to get logon hours at all times. */
4298 memset(p2,0xff,21);
4299 SCVAL(p2,21,0); /* fix zero termination */
4300 p2 = skip_string(*rdata,*rdata_len,p2);
4301 if (!p2) {
4302 return False;
4305 SSVAL(p,usri11_code_page,0); /* code page */
4308 if (uLevel == 1 || uLevel == 2) {
4309 memset(p+22,' ',16); /* password */
4310 SIVALS(p,38,-1); /* password age */
4311 SSVAL(p,42,
4312 (get_current_uid(conn) == sec_initial_uid())?
4313 USER_PRIV_ADMIN:USER_PRIV_USER);
4314 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4315 strlcpy(p2, info->info21.home_directory.string,
4316 PTR_DIFF(endp,p2));
4317 p2 = skip_string(*rdata,*rdata_len,p2);
4318 if (!p2) {
4319 return False;
4321 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4322 *p2++ = 0;
4323 SSVAL(p,52,0); /* flags */
4324 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4325 strlcpy(p2, info->info21.logon_script.string,
4326 PTR_DIFF(endp,p2));
4327 p2 = skip_string(*rdata,*rdata_len,p2);
4328 if (!p2) {
4329 return False;
4331 if (uLevel == 2) {
4332 SIVAL(p,58,0); /* auth_flags */
4333 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4334 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4335 p2 = skip_string(*rdata,*rdata_len,p2);
4336 if (!p2) {
4337 return False;
4339 SIVAL(p,66,0); /* urs_comment */
4340 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4341 strlcpy(p2,"",PTR_DIFF(endp,p2));
4342 p2 = skip_string(*rdata,*rdata_len,p2);
4343 if (!p2) {
4344 return False;
4346 SIVAL(p,74,0); /* workstations */
4347 SIVAL(p,78,0); /* last_logon */
4348 SIVAL(p,82,0); /* last_logoff */
4349 SIVALS(p,86,-1); /* acct_expires */
4350 SIVALS(p,90,-1); /* max_storage */
4351 SSVAL(p,94,168); /* units_per_week */
4352 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4353 memset(p2,-1,21);
4354 p2 += 21;
4355 SSVALS(p,100,-1); /* bad_pw_count */
4356 SSVALS(p,102,-1); /* num_logons */
4357 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4359 TALLOC_CTX *ctx = talloc_tos();
4360 int space_rem = *rdata_len - (p2 - *rdata);
4361 char *tmp;
4363 if (space_rem <= 0) {
4364 return false;
4366 tmp = talloc_strdup(ctx, "\\\\%L");
4367 if (!tmp) {
4368 return false;
4370 tmp = talloc_sub_basic(ctx,
4373 tmp);
4374 if (!tmp) {
4375 return false;
4378 push_ascii(p2,
4379 tmp,
4380 space_rem,
4381 STR_TERMINATE);
4383 p2 = skip_string(*rdata,*rdata_len,p2);
4384 if (!p2) {
4385 return False;
4387 SSVAL(p,108,49); /* country_code */
4388 SSVAL(p,110,860); /* code page */
4392 errcode = NERR_Success;
4394 out:
4395 *rdata_len = PTR_DIFF(p2,*rdata);
4397 if (cli && is_valid_policy_hnd(&user_handle)) {
4398 rpccli_samr_Close(cli, mem_ctx, &user_handle);
4400 if (cli && is_valid_policy_hnd(&domain_handle)) {
4401 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
4403 if (cli && is_valid_policy_hnd(&connect_handle)) {
4404 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
4407 SSVAL(*rparam,0,errcode);
4408 SSVAL(*rparam,2,0); /* converter word */
4409 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4411 return(True);
4414 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4415 connection_struct *conn,uint16 vuid,
4416 char *param, int tpscnt,
4417 char *data, int tdscnt,
4418 int mdrcnt,int mprcnt,
4419 char **rdata,char **rparam,
4420 int *rdata_len,int *rparam_len)
4422 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4423 char *str2 = skip_string(param,tpscnt,str1);
4424 char *p = skip_string(param,tpscnt,str2);
4425 int uLevel;
4426 struct pack_desc desc;
4427 char* name;
4428 /* With share level security vuid will always be zero.
4429 Don't depend on vuser being non-null !!. JRA */
4430 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4432 if (!str1 || !str2 || !p) {
4433 return False;
4436 if(vuser != NULL) {
4437 DEBUG(3,(" Username of UID %d is %s\n",
4438 (int)vuser->server_info->utok.uid,
4439 vuser->server_info->unix_name));
4442 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4443 name = get_safe_str_ptr(param,tpscnt,p,2);
4444 if (!name) {
4445 return False;
4448 memset((char *)&desc,'\0',sizeof(desc));
4450 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4452 /* check it's a supported varient */
4453 if (strcmp(str1,"OOWb54WrLh") != 0) {
4454 return False;
4456 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4457 return False;
4459 if (mdrcnt > 0) {
4460 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4461 if (!*rdata) {
4462 return False;
4466 desc.base = *rdata;
4467 desc.buflen = mdrcnt;
4468 desc.subformat = NULL;
4469 desc.format = str2;
4471 if (init_package(&desc,1,0)) {
4472 PACKI(&desc,"W",0); /* code */
4473 PACKS(&desc,"B21",name); /* eff. name */
4474 PACKS(&desc,"B",""); /* pad */
4475 PACKI(&desc,"W",
4476 (get_current_uid(conn) == sec_initial_uid())?
4477 USER_PRIV_ADMIN:USER_PRIV_USER);
4478 PACKI(&desc,"D",0); /* auth flags XXX */
4479 PACKI(&desc,"W",0); /* num logons */
4480 PACKI(&desc,"W",0); /* bad pw count */
4481 PACKI(&desc,"D",0); /* last logon */
4482 PACKI(&desc,"D",-1); /* last logoff */
4483 PACKI(&desc,"D",-1); /* logoff time */
4484 PACKI(&desc,"D",-1); /* kickoff time */
4485 PACKI(&desc,"D",0); /* password age */
4486 PACKI(&desc,"D",0); /* password can change */
4487 PACKI(&desc,"D",-1); /* password must change */
4490 fstring mypath;
4491 fstrcpy(mypath,"\\\\");
4492 fstrcat(mypath,get_local_machine_name());
4493 strupper_m(mypath);
4494 PACKS(&desc,"z",mypath); /* computer */
4497 PACKS(&desc,"z",lp_workgroup());/* domain */
4498 PACKS(&desc,"z", vuser ?
4499 vuser->server_info->info3->base.logon_script.string
4500 : ""); /* script path */
4501 PACKI(&desc,"D",0x00000000); /* reserved */
4504 *rdata_len = desc.usedlen;
4505 *rparam_len = 6;
4506 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4507 if (!*rparam) {
4508 return False;
4510 SSVALS(*rparam,0,desc.errcode);
4511 SSVAL(*rparam,2,0);
4512 SSVAL(*rparam,4,desc.neededlen);
4514 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4516 return True;
4519 /****************************************************************************
4520 api_WAccessGetUserPerms
4521 ****************************************************************************/
4523 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4524 connection_struct *conn,uint16 vuid,
4525 char *param, int tpscnt,
4526 char *data, int tdscnt,
4527 int mdrcnt,int mprcnt,
4528 char **rdata,char **rparam,
4529 int *rdata_len,int *rparam_len)
4531 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4532 char *str2 = skip_string(param,tpscnt,str1);
4533 char *user = skip_string(param,tpscnt,str2);
4534 char *resource = skip_string(param,tpscnt,user);
4536 if (!str1 || !str2 || !user || !resource) {
4537 return False;
4540 if (skip_string(param,tpscnt,resource) == NULL) {
4541 return False;
4543 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4545 /* check it's a supported varient */
4546 if (strcmp(str1,"zzh") != 0) {
4547 return False;
4549 if (strcmp(str2,"") != 0) {
4550 return False;
4553 *rparam_len = 6;
4554 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4555 if (!*rparam) {
4556 return False;
4558 SSVALS(*rparam,0,0); /* errorcode */
4559 SSVAL(*rparam,2,0); /* converter word */
4560 SSVAL(*rparam,4,0x7f); /* permission flags */
4562 return True;
4565 /****************************************************************************
4566 api_WPrintJobEnumerate
4567 ****************************************************************************/
4569 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4570 connection_struct *conn, uint16 vuid,
4571 char *param, int tpscnt,
4572 char *data, int tdscnt,
4573 int mdrcnt,int mprcnt,
4574 char **rdata,char **rparam,
4575 int *rdata_len,int *rparam_len)
4577 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4578 char *str2 = skip_string(param,tpscnt,str1);
4579 char *p = skip_string(param,tpscnt,str2);
4580 int uLevel;
4581 fstring sharename;
4582 uint32 jobid;
4583 struct pack_desc desc;
4584 char *tmpdata=NULL;
4586 TALLOC_CTX *mem_ctx = talloc_tos();
4587 WERROR werr;
4588 NTSTATUS status;
4589 struct rpc_pipe_client *cli = NULL;
4590 struct policy_handle handle;
4591 struct spoolss_DevmodeContainer devmode_ctr;
4592 union spoolss_JobInfo info;
4594 if (!str1 || !str2 || !p) {
4595 return False;
4598 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4600 memset((char *)&desc,'\0',sizeof(desc));
4601 memset((char *)&status,'\0',sizeof(status));
4603 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4605 /* check it's a supported varient */
4606 if (strcmp(str1,"WWrLh") != 0) {
4607 return False;
4609 if (!check_printjob_info(&desc,uLevel,str2)) {
4610 return False;
4613 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4614 return False;
4617 ZERO_STRUCT(handle);
4619 status = rpc_connect_spoolss_pipe(conn, &cli);
4620 if (!NT_STATUS_IS_OK(status)) {
4621 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4622 nt_errstr(status)));
4623 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4624 goto out;
4627 ZERO_STRUCT(devmode_ctr);
4629 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4630 sharename,
4631 "RAW",
4632 devmode_ctr,
4633 PRINTER_ACCESS_USE,
4634 &handle,
4635 &werr);
4636 if (!NT_STATUS_IS_OK(status)) {
4637 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4638 goto out;
4640 if (!W_ERROR_IS_OK(werr)) {
4641 desc.errcode = W_ERROR_V(werr);
4642 goto out;
4645 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4646 &handle,
4647 jobid,
4648 2, /* level */
4649 0, /* offered */
4650 &info);
4651 if (!W_ERROR_IS_OK(werr)) {
4652 desc.errcode = W_ERROR_V(werr);
4653 goto out;
4656 if (mdrcnt > 0) {
4657 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4658 if (!*rdata) {
4659 return False;
4661 desc.base = *rdata;
4662 desc.buflen = mdrcnt;
4663 } else {
4665 * Don't return data but need to get correct length
4666 * init_package will return wrong size if buflen=0
4668 desc.buflen = getlen(desc.format);
4669 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4672 if (init_package(&desc,1,0)) {
4673 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4674 *rdata_len = desc.usedlen;
4675 } else {
4676 desc.errcode = NERR_JobNotFound;
4677 *rdata_len = 0;
4679 out:
4680 if (cli && is_valid_policy_hnd(&handle)) {
4681 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4684 *rparam_len = 6;
4685 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4686 if (!*rparam) {
4687 return False;
4689 SSVALS(*rparam,0,desc.errcode);
4690 SSVAL(*rparam,2,0);
4691 SSVAL(*rparam,4,desc.neededlen);
4693 SAFE_FREE(tmpdata);
4695 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4697 return True;
4700 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4701 connection_struct *conn, uint16 vuid,
4702 char *param, int tpscnt,
4703 char *data, int tdscnt,
4704 int mdrcnt,int mprcnt,
4705 char **rdata,char **rparam,
4706 int *rdata_len,int *rparam_len)
4708 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4709 char *str2 = skip_string(param,tpscnt,str1);
4710 char *p = skip_string(param,tpscnt,str2);
4711 char *name = p;
4712 int uLevel;
4713 int i, succnt=0;
4714 struct pack_desc desc;
4716 TALLOC_CTX *mem_ctx = talloc_tos();
4717 WERROR werr;
4718 NTSTATUS status;
4719 struct rpc_pipe_client *cli = NULL;
4720 struct policy_handle handle;
4721 struct spoolss_DevmodeContainer devmode_ctr;
4722 uint32_t count = 0;
4723 union spoolss_JobInfo *info;
4725 if (!str1 || !str2 || !p) {
4726 return False;
4729 memset((char *)&desc,'\0',sizeof(desc));
4731 p = skip_string(param,tpscnt,p);
4732 if (!p) {
4733 return False;
4735 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4737 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4739 /* check it's a supported variant */
4740 if (strcmp(str1,"zWrLeh") != 0) {
4741 return False;
4744 if (uLevel > 2) {
4745 return False; /* defined only for uLevel 0,1,2 */
4748 if (!check_printjob_info(&desc,uLevel,str2)) {
4749 return False;
4752 ZERO_STRUCT(handle);
4754 status = rpc_connect_spoolss_pipe(conn, &cli);
4755 if (!NT_STATUS_IS_OK(status)) {
4756 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4757 nt_errstr(status)));
4758 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4759 goto out;
4762 ZERO_STRUCT(devmode_ctr);
4764 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4765 name,
4766 NULL,
4767 devmode_ctr,
4768 SEC_FLAG_MAXIMUM_ALLOWED,
4769 &handle,
4770 &werr);
4771 if (!NT_STATUS_IS_OK(status)) {
4772 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4773 goto out;
4775 if (!W_ERROR_IS_OK(werr)) {
4776 desc.errcode = W_ERROR_V(werr);
4777 goto out;
4780 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4781 &handle,
4782 0, /* firstjob */
4783 0xff, /* numjobs */
4784 2, /* level */
4785 0, /* offered */
4786 &count,
4787 &info);
4788 if (!W_ERROR_IS_OK(werr)) {
4789 desc.errcode = W_ERROR_V(werr);
4790 goto out;
4793 if (mdrcnt > 0) {
4794 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4795 if (!*rdata) {
4796 return False;
4799 desc.base = *rdata;
4800 desc.buflen = mdrcnt;
4802 if (init_package(&desc,count,0)) {
4803 succnt = 0;
4804 for (i = 0; i < count; i++) {
4805 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4806 if (desc.errcode == NERR_Success) {
4807 succnt = i+1;
4811 out:
4812 if (cli && is_valid_policy_hnd(&handle)) {
4813 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4816 *rdata_len = desc.usedlen;
4818 *rparam_len = 8;
4819 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4820 if (!*rparam) {
4821 return False;
4823 SSVALS(*rparam,0,desc.errcode);
4824 SSVAL(*rparam,2,0);
4825 SSVAL(*rparam,4,succnt);
4826 SSVAL(*rparam,6,count);
4828 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4830 return True;
4833 static int check_printdest_info(struct pack_desc* desc,
4834 int uLevel, char* id)
4836 desc->subformat = NULL;
4837 switch( uLevel ) {
4838 case 0:
4839 desc->format = "B9";
4840 break;
4841 case 1:
4842 desc->format = "B9B21WWzW";
4843 break;
4844 case 2:
4845 desc->format = "z";
4846 break;
4847 case 3:
4848 desc->format = "zzzWWzzzWW";
4849 break;
4850 default:
4851 DEBUG(0,("check_printdest_info: invalid level %d\n",
4852 uLevel));
4853 return False;
4855 if (id == NULL || strcmp(desc->format,id) != 0) {
4856 DEBUG(0,("check_printdest_info: invalid string %s\n",
4857 id ? id : "<NULL>" ));
4858 return False;
4860 return True;
4863 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4864 struct pack_desc* desc)
4866 char buf[100];
4868 strncpy(buf, info2->printername, sizeof(buf)-1);
4869 buf[sizeof(buf)-1] = 0;
4870 strupper_m(buf);
4872 if (uLevel <= 1) {
4873 PACKS(desc,"B9",buf); /* szName */
4874 if (uLevel == 1) {
4875 PACKS(desc,"B21",""); /* szUserName */
4876 PACKI(desc,"W",0); /* uJobId */
4877 PACKI(desc,"W",0); /* fsStatus */
4878 PACKS(desc,"z",""); /* pszStatus */
4879 PACKI(desc,"W",0); /* time */
4883 if (uLevel == 2 || uLevel == 3) {
4884 PACKS(desc,"z",buf); /* pszPrinterName */
4885 if (uLevel == 3) {
4886 PACKS(desc,"z",""); /* pszUserName */
4887 PACKS(desc,"z",""); /* pszLogAddr */
4888 PACKI(desc,"W",0); /* uJobId */
4889 PACKI(desc,"W",0); /* fsStatus */
4890 PACKS(desc,"z",""); /* pszStatus */
4891 PACKS(desc,"z",""); /* pszComment */
4892 PACKS(desc,"z","NULL"); /* pszDrivers */
4893 PACKI(desc,"W",0); /* time */
4894 PACKI(desc,"W",0); /* pad1 */
4899 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4900 connection_struct *conn, uint16 vuid,
4901 char *param, int tpscnt,
4902 char *data, int tdscnt,
4903 int mdrcnt,int mprcnt,
4904 char **rdata,char **rparam,
4905 int *rdata_len,int *rparam_len)
4907 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4908 char *str2 = skip_string(param,tpscnt,str1);
4909 char *p = skip_string(param,tpscnt,str2);
4910 char* PrinterName = p;
4911 int uLevel;
4912 struct pack_desc desc;
4913 char *tmpdata=NULL;
4915 TALLOC_CTX *mem_ctx = talloc_tos();
4916 WERROR werr;
4917 NTSTATUS status;
4918 struct rpc_pipe_client *cli = NULL;
4919 struct policy_handle handle;
4920 struct spoolss_DevmodeContainer devmode_ctr;
4921 union spoolss_PrinterInfo info;
4923 if (!str1 || !str2 || !p) {
4924 return False;
4927 memset((char *)&desc,'\0',sizeof(desc));
4929 p = skip_string(param,tpscnt,p);
4930 if (!p) {
4931 return False;
4933 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4935 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4937 /* check it's a supported varient */
4938 if (strcmp(str1,"zWrLh") != 0) {
4939 return False;
4941 if (!check_printdest_info(&desc,uLevel,str2)) {
4942 return False;
4945 ZERO_STRUCT(handle);
4947 status = rpc_connect_spoolss_pipe(conn, &cli);
4948 if (!NT_STATUS_IS_OK(status)) {
4949 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4950 nt_errstr(status)));
4951 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4952 goto out;
4955 ZERO_STRUCT(devmode_ctr);
4957 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4958 PrinterName,
4959 NULL,
4960 devmode_ctr,
4961 SEC_FLAG_MAXIMUM_ALLOWED,
4962 &handle,
4963 &werr);
4964 if (!NT_STATUS_IS_OK(status)) {
4965 *rdata_len = 0;
4966 desc.errcode = NERR_DestNotFound;
4967 desc.neededlen = 0;
4968 goto out;
4970 if (!W_ERROR_IS_OK(werr)) {
4971 *rdata_len = 0;
4972 desc.errcode = NERR_DestNotFound;
4973 desc.neededlen = 0;
4974 goto out;
4977 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4978 &handle,
4981 &info);
4982 if (!W_ERROR_IS_OK(werr)) {
4983 *rdata_len = 0;
4984 desc.errcode = NERR_DestNotFound;
4985 desc.neededlen = 0;
4986 goto out;
4989 if (mdrcnt > 0) {
4990 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4991 if (!*rdata) {
4992 return False;
4994 desc.base = *rdata;
4995 desc.buflen = mdrcnt;
4996 } else {
4998 * Don't return data but need to get correct length
4999 * init_package will return wrong size if buflen=0
5001 desc.buflen = getlen(desc.format);
5002 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
5004 if (init_package(&desc,1,0)) {
5005 fill_printdest_info(&info.info2, uLevel,&desc);
5008 out:
5009 if (cli && is_valid_policy_hnd(&handle)) {
5010 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
5013 *rdata_len = desc.usedlen;
5015 *rparam_len = 6;
5016 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5017 if (!*rparam) {
5018 return False;
5020 SSVALS(*rparam,0,desc.errcode);
5021 SSVAL(*rparam,2,0);
5022 SSVAL(*rparam,4,desc.neededlen);
5024 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5025 SAFE_FREE(tmpdata);
5027 return True;
5030 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5031 connection_struct *conn, uint16 vuid,
5032 char *param, int tpscnt,
5033 char *data, int tdscnt,
5034 int mdrcnt,int mprcnt,
5035 char **rdata,char **rparam,
5036 int *rdata_len,int *rparam_len)
5038 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5039 char *str2 = skip_string(param,tpscnt,str1);
5040 char *p = skip_string(param,tpscnt,str2);
5041 int uLevel;
5042 int queuecnt;
5043 int i, n, succnt=0;
5044 struct pack_desc desc;
5046 TALLOC_CTX *mem_ctx = talloc_tos();
5047 WERROR werr;
5048 NTSTATUS status;
5049 struct rpc_pipe_client *cli = NULL;
5050 union spoolss_PrinterInfo *info;
5051 uint32_t count;
5053 if (!str1 || !str2 || !p) {
5054 return False;
5057 memset((char *)&desc,'\0',sizeof(desc));
5059 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5061 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5063 /* check it's a supported varient */
5064 if (strcmp(str1,"WrLeh") != 0) {
5065 return False;
5067 if (!check_printdest_info(&desc,uLevel,str2)) {
5068 return False;
5071 queuecnt = 0;
5073 status = rpc_connect_spoolss_pipe(conn, &cli);
5074 if (!NT_STATUS_IS_OK(status)) {
5075 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5076 nt_errstr(status)));
5077 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5078 goto out;
5081 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5082 PRINTER_ENUM_LOCAL,
5083 cli->srv_name_slash,
5086 &count,
5087 &info);
5088 if (!W_ERROR_IS_OK(werr)) {
5089 desc.errcode = W_ERROR_V(werr);
5090 *rdata_len = 0;
5091 desc.errcode = NERR_DestNotFound;
5092 desc.neededlen = 0;
5093 goto out;
5096 queuecnt = count;
5098 if (mdrcnt > 0) {
5099 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5100 if (!*rdata) {
5101 return False;
5105 desc.base = *rdata;
5106 desc.buflen = mdrcnt;
5107 if (init_package(&desc,queuecnt,0)) {
5108 succnt = 0;
5109 n = 0;
5110 for (i = 0; i < count; i++) {
5111 fill_printdest_info(&info[i].info2, uLevel,&desc);
5112 n++;
5113 if (desc.errcode == NERR_Success) {
5114 succnt = n;
5118 out:
5119 *rdata_len = desc.usedlen;
5121 *rparam_len = 8;
5122 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5123 if (!*rparam) {
5124 return False;
5126 SSVALS(*rparam,0,desc.errcode);
5127 SSVAL(*rparam,2,0);
5128 SSVAL(*rparam,4,succnt);
5129 SSVAL(*rparam,6,queuecnt);
5131 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5133 return True;
5136 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5137 connection_struct *conn, uint16 vuid,
5138 char *param, int tpscnt,
5139 char *data, int tdscnt,
5140 int mdrcnt,int mprcnt,
5141 char **rdata,char **rparam,
5142 int *rdata_len,int *rparam_len)
5144 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5145 char *str2 = skip_string(param,tpscnt,str1);
5146 char *p = skip_string(param,tpscnt,str2);
5147 int uLevel;
5148 int succnt;
5149 struct pack_desc desc;
5151 if (!str1 || !str2 || !p) {
5152 return False;
5155 memset((char *)&desc,'\0',sizeof(desc));
5157 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5159 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5161 /* check it's a supported varient */
5162 if (strcmp(str1,"WrLeh") != 0) {
5163 return False;
5165 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5166 return False;
5169 if (mdrcnt > 0) {
5170 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5171 if (!*rdata) {
5172 return False;
5175 desc.base = *rdata;
5176 desc.buflen = mdrcnt;
5177 if (init_package(&desc,1,0)) {
5178 PACKS(&desc,"B41","NULL");
5181 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5183 *rdata_len = desc.usedlen;
5185 *rparam_len = 8;
5186 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5187 if (!*rparam) {
5188 return False;
5190 SSVALS(*rparam,0,desc.errcode);
5191 SSVAL(*rparam,2,0);
5192 SSVAL(*rparam,4,succnt);
5193 SSVAL(*rparam,6,1);
5195 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5197 return True;
5200 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5201 connection_struct *conn, uint16 vuid,
5202 char *param, int tpscnt,
5203 char *data, int tdscnt,
5204 int mdrcnt,int mprcnt,
5205 char **rdata,char **rparam,
5206 int *rdata_len,int *rparam_len)
5208 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5209 char *str2 = skip_string(param,tpscnt,str1);
5210 char *p = skip_string(param,tpscnt,str2);
5211 int uLevel;
5212 int succnt;
5213 struct pack_desc desc;
5215 if (!str1 || !str2 || !p) {
5216 return False;
5218 memset((char *)&desc,'\0',sizeof(desc));
5220 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5222 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5224 /* check it's a supported varient */
5225 if (strcmp(str1,"WrLeh") != 0) {
5226 return False;
5228 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5229 return False;
5232 if (mdrcnt > 0) {
5233 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5234 if (!*rdata) {
5235 return False;
5238 desc.base = *rdata;
5239 desc.buflen = mdrcnt;
5240 desc.format = str2;
5241 if (init_package(&desc,1,0)) {
5242 PACKS(&desc,"B13","lpd");
5245 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5247 *rdata_len = desc.usedlen;
5249 *rparam_len = 8;
5250 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5251 if (!*rparam) {
5252 return False;
5254 SSVALS(*rparam,0,desc.errcode);
5255 SSVAL(*rparam,2,0);
5256 SSVAL(*rparam,4,succnt);
5257 SSVAL(*rparam,6,1);
5259 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5261 return True;
5264 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5265 connection_struct *conn, uint16 vuid,
5266 char *param, int tpscnt,
5267 char *data, int tdscnt,
5268 int mdrcnt,int mprcnt,
5269 char **rdata,char **rparam,
5270 int *rdata_len,int *rparam_len)
5272 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5273 char *str2 = skip_string(param,tpscnt,str1);
5274 char *p = skip_string(param,tpscnt,str2);
5275 int uLevel;
5276 int succnt;
5277 struct pack_desc desc;
5279 if (!str1 || !str2 || !p) {
5280 return False;
5283 memset((char *)&desc,'\0',sizeof(desc));
5285 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5287 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5289 /* check it's a supported varient */
5290 if (strcmp(str1,"WrLeh") != 0) {
5291 return False;
5293 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5294 return False;
5297 if (mdrcnt > 0) {
5298 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5299 if (!*rdata) {
5300 return False;
5303 memset((char *)&desc,'\0',sizeof(desc));
5304 desc.base = *rdata;
5305 desc.buflen = mdrcnt;
5306 desc.format = str2;
5307 if (init_package(&desc,1,0)) {
5308 PACKS(&desc,"B13","lp0");
5311 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5313 *rdata_len = desc.usedlen;
5315 *rparam_len = 8;
5316 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5317 if (!*rparam) {
5318 return False;
5320 SSVALS(*rparam,0,desc.errcode);
5321 SSVAL(*rparam,2,0);
5322 SSVAL(*rparam,4,succnt);
5323 SSVAL(*rparam,6,1);
5325 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5327 return True;
5330 /****************************************************************************
5331 List open sessions
5332 ****************************************************************************/
5334 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5335 connection_struct *conn, uint16 vuid,
5336 char *param, int tpscnt,
5337 char *data, int tdscnt,
5338 int mdrcnt,int mprcnt,
5339 char **rdata,char **rparam,
5340 int *rdata_len,int *rparam_len)
5343 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5344 char *str2 = skip_string(param,tpscnt,str1);
5345 char *p = skip_string(param,tpscnt,str2);
5346 int uLevel;
5347 struct pack_desc desc;
5348 struct sessionid *session_list;
5349 int i, num_sessions;
5351 if (!str1 || !str2 || !p) {
5352 return False;
5355 memset((char *)&desc,'\0',sizeof(desc));
5357 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5359 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5360 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5361 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5363 /* check it's a supported varient */
5364 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5365 return False;
5367 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5368 return False;
5371 num_sessions = list_sessions(talloc_tos(), &session_list);
5373 if (mdrcnt > 0) {
5374 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5375 if (!*rdata) {
5376 return False;
5379 memset((char *)&desc,'\0',sizeof(desc));
5380 desc.base = *rdata;
5381 desc.buflen = mdrcnt;
5382 desc.format = str2;
5383 if (!init_package(&desc,num_sessions,0)) {
5384 return False;
5387 for(i=0; i<num_sessions; i++) {
5388 PACKS(&desc, "z", session_list[i].remote_machine);
5389 PACKS(&desc, "z", session_list[i].username);
5390 PACKI(&desc, "W", 1); /* num conns */
5391 PACKI(&desc, "W", 0); /* num opens */
5392 PACKI(&desc, "W", 1); /* num users */
5393 PACKI(&desc, "D", 0); /* session time */
5394 PACKI(&desc, "D", 0); /* idle time */
5395 PACKI(&desc, "D", 0); /* flags */
5396 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5399 *rdata_len = desc.usedlen;
5401 *rparam_len = 8;
5402 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5403 if (!*rparam) {
5404 return False;
5406 SSVALS(*rparam,0,desc.errcode);
5407 SSVAL(*rparam,2,0); /* converter */
5408 SSVAL(*rparam,4,num_sessions); /* count */
5410 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5412 return True;
5416 /****************************************************************************
5417 The buffer was too small.
5418 ****************************************************************************/
5420 static bool api_TooSmall(struct smbd_server_connection *sconn,
5421 connection_struct *conn,uint16 vuid, char *param, char *data,
5422 int mdrcnt, int mprcnt,
5423 char **rdata, char **rparam,
5424 int *rdata_len, int *rparam_len)
5426 *rparam_len = MIN(*rparam_len,mprcnt);
5427 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5428 if (!*rparam) {
5429 return False;
5432 *rdata_len = 0;
5434 SSVAL(*rparam,0,NERR_BufTooSmall);
5436 DEBUG(3,("Supplied buffer too small in API command\n"));
5438 return True;
5441 /****************************************************************************
5442 The request is not supported.
5443 ****************************************************************************/
5445 static bool api_Unsupported(struct smbd_server_connection *sconn,
5446 connection_struct *conn, uint16 vuid,
5447 char *param, int tpscnt,
5448 char *data, int tdscnt,
5449 int mdrcnt, int mprcnt,
5450 char **rdata, char **rparam,
5451 int *rdata_len, int *rparam_len)
5453 *rparam_len = 4;
5454 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5455 if (!*rparam) {
5456 return False;
5459 *rdata_len = 0;
5461 SSVAL(*rparam,0,NERR_notsupported);
5462 SSVAL(*rparam,2,0); /* converter word */
5464 DEBUG(3,("Unsupported API command\n"));
5466 return True;
5469 static const struct {
5470 const char *name;
5471 int id;
5472 bool (*fn)(struct smbd_server_connection *sconn,
5473 connection_struct *, uint16,
5474 char *, int,
5475 char *, int,
5476 int,int,char **,char **,int *,int *);
5477 bool auth_user; /* Deny anonymous access? */
5478 } api_commands[] = {
5479 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5480 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5481 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5482 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5483 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5484 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5485 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5486 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5487 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5488 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5489 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5490 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5491 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5492 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5493 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5494 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5495 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5496 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5497 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5498 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5499 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5500 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5501 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5502 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5503 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5504 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5505 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5506 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5507 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5508 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5509 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5510 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5511 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5512 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5513 {NULL, -1, api_Unsupported}
5514 /* The following RAP calls are not implemented by Samba:
5516 RAP_WFileEnum2 - anon not OK
5521 /****************************************************************************
5522 Handle remote api calls.
5523 ****************************************************************************/
5525 void api_reply(connection_struct *conn, uint16 vuid,
5526 struct smb_request *req,
5527 char *data, char *params,
5528 int tdscnt, int tpscnt,
5529 int mdrcnt, int mprcnt)
5531 int api_command;
5532 char *rdata = NULL;
5533 char *rparam = NULL;
5534 const char *name1 = NULL;
5535 const char *name2 = NULL;
5536 int rdata_len = 0;
5537 int rparam_len = 0;
5538 bool reply=False;
5539 int i;
5541 if (!params) {
5542 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5543 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5544 return;
5547 if (tpscnt < 2) {
5548 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5549 return;
5551 api_command = SVAL(params,0);
5552 /* Is there a string at position params+2 ? */
5553 if (skip_string(params,tpscnt,params+2)) {
5554 name1 = params + 2;
5555 } else {
5556 name1 = "";
5558 name2 = skip_string(params,tpscnt,params+2);
5559 if (!name2) {
5560 name2 = "";
5563 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5564 api_command,
5565 name1,
5566 name2,
5567 tdscnt,tpscnt,mdrcnt,mprcnt));
5569 for (i=0;api_commands[i].name;i++) {
5570 if (api_commands[i].id == api_command && api_commands[i].fn) {
5571 DEBUG(3,("Doing %s\n",api_commands[i].name));
5572 break;
5576 /* Check whether this api call can be done anonymously */
5578 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5579 user_struct *user = get_valid_user_struct(req->sconn, vuid);
5581 if (!user || user->server_info->guest) {
5582 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5583 return;
5587 rdata = (char *)SMB_MALLOC(1024);
5588 if (rdata) {
5589 memset(rdata,'\0',1024);
5592 rparam = (char *)SMB_MALLOC(1024);
5593 if (rparam) {
5594 memset(rparam,'\0',1024);
5597 if(!rdata || !rparam) {
5598 DEBUG(0,("api_reply: malloc fail !\n"));
5599 SAFE_FREE(rdata);
5600 SAFE_FREE(rparam);
5601 reply_nterror(req, NT_STATUS_NO_MEMORY);
5602 return;
5605 reply = api_commands[i].fn(req->sconn, conn,
5606 vuid,
5607 params,tpscnt, /* params + length */
5608 data,tdscnt, /* data + length */
5609 mdrcnt,mprcnt,
5610 &rdata,&rparam,&rdata_len,&rparam_len);
5613 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5614 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5615 mdrcnt,mprcnt,
5616 &rdata,&rparam,&rdata_len,&rparam_len);
5619 /* if we get False back then it's actually unsupported */
5620 if (!reply) {
5621 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5622 data,
5623 tdscnt,mdrcnt,mprcnt,
5624 &rdata,&rparam,&rdata_len,&rparam_len);
5627 /* If api_Unsupported returns false we can't return anything. */
5628 if (reply) {
5629 send_trans_reply(conn, req, rparam, rparam_len,
5630 rdata, rdata_len, False);
5633 SAFE_FREE(rdata);
5634 SAFE_FREE(rparam);
5635 return;