s3: Lift the server_messaging_context from notify_job_status
[Samba/gbeck.git] / source3 / smbd / lanman.c
blob2be2a8c4ac46c7a59155f52d4a772dad5bef3ef0
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->msg_ctx,
2240 &cli);
2241 if (!NT_STATUS_IS_OK(status)) {
2242 DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n",
2243 nt_errstr(status)));
2244 res = W_ERROR_V(ntstatus_to_werror(status));
2245 goto out;
2248 info2.name = sharename;
2249 info2.type = STYPE_DISKTREE;
2250 info2.comment = comment;
2251 info2.permissions = 0;
2252 info2.max_users = 0;
2253 info2.current_users = 0;
2254 info2.path = pathname;
2255 info2.password = NULL;
2257 info.info2 = &info2;
2259 status = rpccli_srvsvc_NetShareAdd(cli, mem_ctx,
2260 cli->srv_name_slash,
2262 &info,
2263 NULL,
2264 &werr);
2265 if (!NT_STATUS_IS_OK(status)) {
2266 res = W_ERROR_V(ntstatus_to_werror(status));
2267 goto out;
2269 if (!W_ERROR_IS_OK(werr)) {
2270 res = W_ERROR_V(werr);
2271 goto out;
2274 *rparam_len = 6;
2275 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2276 if (!*rparam) {
2277 return False;
2279 SSVAL(*rparam,0,NERR_Success);
2280 SSVAL(*rparam,2,0); /* converter word */
2281 SSVAL(*rparam,4,*rdata_len);
2282 *rdata_len = 0;
2284 return True;
2286 out:
2288 *rparam_len = 4;
2289 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2290 if (!*rparam) {
2291 return False;
2293 *rdata_len = 0;
2294 SSVAL(*rparam,0,res);
2295 SSVAL(*rparam,2,0);
2296 return True;
2299 /****************************************************************************
2300 view list of groups available
2301 ****************************************************************************/
2303 static bool api_RNetGroupEnum(struct smbd_server_connection *sconn,
2304 connection_struct *conn,uint16 vuid,
2305 char *param, int tpscnt,
2306 char *data, int tdscnt,
2307 int mdrcnt,int mprcnt,
2308 char **rdata,char **rparam,
2309 int *rdata_len,int *rparam_len)
2311 int i;
2312 int errflags=0;
2313 int resume_context, cli_buf_size;
2314 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2315 char *str2 = skip_string(param,tpscnt,str1);
2316 char *p = skip_string(param,tpscnt,str2);
2318 uint32_t num_groups;
2319 uint32_t resume_handle;
2320 struct rpc_pipe_client *samr_pipe;
2321 struct policy_handle samr_handle, domain_handle;
2322 NTSTATUS status;
2324 if (!str1 || !str2 || !p) {
2325 return False;
2328 if (strcmp(str1,"WrLeh") != 0) {
2329 return False;
2332 /* parameters
2333 * W-> resume context (number of users to skip)
2334 * r -> return parameter pointer to receive buffer
2335 * L -> length of receive buffer
2336 * e -> return parameter number of entries
2337 * h -> return parameter total number of users
2340 if (strcmp("B21",str2) != 0) {
2341 return False;
2344 status = rpc_pipe_open_internal(
2345 talloc_tos(), &ndr_table_samr.syntax_id,
2346 conn->server_info, conn->sconn->msg_ctx, &samr_pipe);
2347 if (!NT_STATUS_IS_OK(status)) {
2348 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2349 nt_errstr(status)));
2350 return false;
2353 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2354 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2355 if (!NT_STATUS_IS_OK(status)) {
2356 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2357 nt_errstr(status)));
2358 return false;
2361 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2362 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2363 get_global_sam_sid(), &domain_handle);
2364 if (!NT_STATUS_IS_OK(status)) {
2365 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2366 nt_errstr(status)));
2367 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2368 return false;
2371 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2372 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2373 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2374 "%d\n", resume_context, cli_buf_size));
2376 *rdata_len = cli_buf_size;
2377 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2378 if (!*rdata) {
2379 return False;
2382 p = *rdata;
2384 errflags = NERR_Success;
2385 num_groups = 0;
2386 resume_handle = 0;
2388 while (true) {
2389 struct samr_SamArray *sam_entries;
2390 uint32_t num_entries;
2392 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2393 &domain_handle,
2394 &resume_handle,
2395 &sam_entries, 1,
2396 &num_entries);
2397 if (!NT_STATUS_IS_OK(status)) {
2398 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2399 "%s\n", nt_errstr(status)));
2400 break;
2403 if (num_entries == 0) {
2404 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2405 "no entries -- done\n"));
2406 break;
2409 for(i=0; i<num_entries; i++) {
2410 const char *name;
2412 name = sam_entries->entries[i].name.string;
2414 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2415 /* set overflow error */
2416 DEBUG(3,("overflow on entry %d group %s\n", i,
2417 name));
2418 errflags=234;
2419 break;
2422 /* truncate the name at 21 chars. */
2423 memset(p, 0, 21);
2424 strlcpy(p, name, 21);
2425 DEBUG(10,("adding entry %d group %s\n", i, p));
2426 p += 21;
2427 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2428 * idea why... */
2429 num_groups += 1;
2432 if (errflags != NERR_Success) {
2433 break;
2436 TALLOC_FREE(sam_entries);
2439 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2440 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2442 *rdata_len = PTR_DIFF(p,*rdata);
2444 *rparam_len = 8;
2445 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2446 if (!*rparam) {
2447 return False;
2449 SSVAL(*rparam, 0, errflags);
2450 SSVAL(*rparam, 2, 0); /* converter word */
2451 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2452 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2454 return(True);
2457 /*******************************************************************
2458 Get groups that a user is a member of.
2459 ******************************************************************/
2461 static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
2462 connection_struct *conn,uint16 vuid,
2463 char *param, int tpscnt,
2464 char *data, int tdscnt,
2465 int mdrcnt,int mprcnt,
2466 char **rdata,char **rparam,
2467 int *rdata_len,int *rparam_len)
2469 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2470 char *str2 = skip_string(param,tpscnt,str1);
2471 char *UserName = skip_string(param,tpscnt,str2);
2472 char *p = skip_string(param,tpscnt,UserName);
2473 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2474 const char *level_string;
2475 int count=0;
2476 bool ret = False;
2477 uint32_t i;
2478 char *endp = NULL;
2480 struct rpc_pipe_client *samr_pipe;
2481 struct policy_handle samr_handle, domain_handle, user_handle;
2482 struct lsa_String name;
2483 struct lsa_Strings names;
2484 struct samr_Ids type, rid;
2485 struct samr_RidWithAttributeArray *rids;
2486 NTSTATUS status;
2488 if (!str1 || !str2 || !UserName || !p) {
2489 return False;
2492 *rparam_len = 8;
2493 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2494 if (!*rparam) {
2495 return False;
2498 /* check it's a supported varient */
2500 if ( strcmp(str1,"zWrLeh") != 0 )
2501 return False;
2503 switch( uLevel ) {
2504 case 0:
2505 level_string = "B21";
2506 break;
2507 default:
2508 return False;
2511 if (strcmp(level_string,str2) != 0)
2512 return False;
2514 *rdata_len = mdrcnt + 1024;
2515 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2516 if (!*rdata) {
2517 return False;
2520 SSVAL(*rparam,0,NERR_Success);
2521 SSVAL(*rparam,2,0); /* converter word */
2523 p = *rdata;
2524 endp = *rdata + *rdata_len;
2526 status = rpc_pipe_open_internal(
2527 talloc_tos(), &ndr_table_samr.syntax_id,
2528 conn->server_info, conn->sconn->msg_ctx, &samr_pipe);
2529 if (!NT_STATUS_IS_OK(status)) {
2530 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2531 nt_errstr(status)));
2532 return false;
2535 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2536 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2537 if (!NT_STATUS_IS_OK(status)) {
2538 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2539 nt_errstr(status)));
2540 return false;
2543 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2544 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2545 get_global_sam_sid(), &domain_handle);
2546 if (!NT_STATUS_IS_OK(status)) {
2547 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2548 nt_errstr(status)));
2549 goto close_sam;
2552 name.string = UserName;
2554 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2555 &domain_handle, 1, &name,
2556 &rid, &type);
2557 if (!NT_STATUS_IS_OK(status)) {
2558 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2559 nt_errstr(status)));
2560 goto close_domain;
2563 if (type.ids[0] != SID_NAME_USER) {
2564 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2565 sid_type_lookup(type.ids[0])));
2566 goto close_domain;
2569 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2570 &domain_handle,
2571 SAMR_USER_ACCESS_GET_GROUPS,
2572 rid.ids[0], &user_handle);
2573 if (!NT_STATUS_IS_OK(status)) {
2574 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2575 nt_errstr(status)));
2576 goto close_domain;
2579 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2580 &user_handle, &rids);
2581 if (!NT_STATUS_IS_OK(status)) {
2582 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2583 nt_errstr(status)));
2584 goto close_user;
2587 for (i=0; i<rids->count; i++) {
2589 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2590 &domain_handle,
2591 1, &rids->rids[i].rid,
2592 &names, &type);
2593 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2594 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2595 p += 21;
2596 count++;
2600 *rdata_len = PTR_DIFF(p,*rdata);
2602 SSVAL(*rparam,4,count); /* is this right?? */
2603 SSVAL(*rparam,6,count); /* is this right?? */
2605 ret = True;
2607 close_user:
2608 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2609 close_domain:
2610 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2611 close_sam:
2612 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2614 return ret;
2617 /*******************************************************************
2618 Get all users.
2619 ******************************************************************/
2621 static bool api_RNetUserEnum(struct smbd_server_connection *sconn,
2622 connection_struct *conn, uint16 vuid,
2623 char *param, int tpscnt,
2624 char *data, int tdscnt,
2625 int mdrcnt,int mprcnt,
2626 char **rdata,char **rparam,
2627 int *rdata_len,int *rparam_len)
2629 int count_sent=0;
2630 int num_users=0;
2631 int errflags=0;
2632 int i, resume_context, cli_buf_size;
2633 uint32_t resume_handle;
2635 struct rpc_pipe_client *samr_pipe;
2636 struct policy_handle samr_handle, domain_handle;
2637 NTSTATUS status;
2639 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2640 char *str2 = skip_string(param,tpscnt,str1);
2641 char *p = skip_string(param,tpscnt,str2);
2642 char *endp = NULL;
2644 if (!str1 || !str2 || !p) {
2645 return False;
2648 if (strcmp(str1,"WrLeh") != 0)
2649 return False;
2650 /* parameters
2651 * W-> resume context (number of users to skip)
2652 * r -> return parameter pointer to receive buffer
2653 * L -> length of receive buffer
2654 * e -> return parameter number of entries
2655 * h -> return parameter total number of users
2658 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2659 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2660 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2661 resume_context, cli_buf_size));
2663 *rparam_len = 8;
2664 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2665 if (!*rparam) {
2666 return False;
2669 /* check it's a supported varient */
2670 if (strcmp("B21",str2) != 0)
2671 return False;
2673 *rdata_len = cli_buf_size;
2674 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2675 if (!*rdata) {
2676 return False;
2679 p = *rdata;
2680 endp = *rdata + *rdata_len;
2682 status = rpc_pipe_open_internal(
2683 talloc_tos(), &ndr_table_samr.syntax_id,
2684 conn->server_info, conn->sconn->msg_ctx, &samr_pipe);
2685 if (!NT_STATUS_IS_OK(status)) {
2686 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2687 nt_errstr(status)));
2688 return false;
2691 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2692 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2693 if (!NT_STATUS_IS_OK(status)) {
2694 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2695 nt_errstr(status)));
2696 return false;
2699 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2700 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2701 get_global_sam_sid(), &domain_handle);
2702 if (!NT_STATUS_IS_OK(status)) {
2703 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2704 nt_errstr(status)));
2705 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2706 return false;
2709 errflags=NERR_Success;
2711 resume_handle = 0;
2713 while (true) {
2714 struct samr_SamArray *sam_entries;
2715 uint32_t num_entries;
2717 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2718 &domain_handle,
2719 &resume_handle,
2720 0, &sam_entries, 1,
2721 &num_entries);
2723 if (!NT_STATUS_IS_OK(status)) {
2724 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2725 "%s\n", nt_errstr(status)));
2726 break;
2729 if (num_entries == 0) {
2730 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2731 "no entries -- done\n"));
2732 break;
2735 for (i=0; i<num_entries; i++) {
2736 const char *name;
2738 name = sam_entries->entries[i].name.string;
2740 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2741 &&(strlen(name)<=21)) {
2742 strlcpy(p,name,PTR_DIFF(endp,p));
2743 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2744 "username %s\n",count_sent,p));
2745 p += 21;
2746 count_sent++;
2747 } else {
2748 /* set overflow error */
2749 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2750 "username %s\n",count_sent,name));
2751 errflags=234;
2752 break;
2756 if (errflags != NERR_Success) {
2757 break;
2760 TALLOC_FREE(sam_entries);
2763 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2764 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2766 *rdata_len = PTR_DIFF(p,*rdata);
2768 SSVAL(*rparam,0,errflags);
2769 SSVAL(*rparam,2,0); /* converter word */
2770 SSVAL(*rparam,4,count_sent); /* is this right?? */
2771 SSVAL(*rparam,6,num_users); /* is this right?? */
2773 return True;
2776 /****************************************************************************
2777 Get the time of day info.
2778 ****************************************************************************/
2780 static bool api_NetRemoteTOD(struct smbd_server_connection *sconn,
2781 connection_struct *conn,uint16 vuid,
2782 char *param, int tpscnt,
2783 char *data, int tdscnt,
2784 int mdrcnt,int mprcnt,
2785 char **rdata,char **rparam,
2786 int *rdata_len,int *rparam_len)
2788 struct tm *t;
2789 time_t unixdate = time(NULL);
2790 char *p;
2792 *rparam_len = 4;
2793 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2794 if (!*rparam) {
2795 return False;
2798 *rdata_len = 21;
2799 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2800 if (!*rdata) {
2801 return False;
2804 SSVAL(*rparam,0,NERR_Success);
2805 SSVAL(*rparam,2,0); /* converter word */
2807 p = *rdata;
2809 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2810 by NT in a "net time" operation,
2811 it seems to ignore the one below */
2813 /* the client expects to get localtime, not GMT, in this bit
2814 (I think, this needs testing) */
2815 t = localtime(&unixdate);
2816 if (!t) {
2817 return False;
2820 SIVAL(p,4,0); /* msecs ? */
2821 SCVAL(p,8,t->tm_hour);
2822 SCVAL(p,9,t->tm_min);
2823 SCVAL(p,10,t->tm_sec);
2824 SCVAL(p,11,0); /* hundredths of seconds */
2825 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2826 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2827 SCVAL(p,16,t->tm_mday);
2828 SCVAL(p,17,t->tm_mon + 1);
2829 SSVAL(p,18,1900+t->tm_year);
2830 SCVAL(p,20,t->tm_wday);
2832 return True;
2835 /****************************************************************************
2836 Set the user password.
2837 *****************************************************************************/
2839 static bool api_SetUserPassword(struct smbd_server_connection *sconn,
2840 connection_struct *conn,uint16 vuid,
2841 char *param, int tpscnt,
2842 char *data, int tdscnt,
2843 int mdrcnt,int mprcnt,
2844 char **rdata,char **rparam,
2845 int *rdata_len,int *rparam_len)
2847 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2848 char *p = NULL;
2849 fstring user;
2850 fstring pass1,pass2;
2851 TALLOC_CTX *mem_ctx = talloc_tos();
2852 NTSTATUS status;
2853 struct rpc_pipe_client *cli = NULL;
2854 struct policy_handle connect_handle, domain_handle, user_handle;
2855 struct lsa_String domain_name;
2856 struct dom_sid2 *domain_sid;
2857 struct lsa_String names;
2858 struct samr_Ids rids;
2859 struct samr_Ids types;
2860 struct samr_Password old_lm_hash;
2861 struct samr_Password new_lm_hash;
2862 int errcode = NERR_badpass;
2863 uint32_t rid;
2864 int encrypted;
2865 int min_pwd_length;
2867 /* Skip 2 strings. */
2868 p = skip_string(param,tpscnt,np);
2869 p = skip_string(param,tpscnt,p);
2871 if (!np || !p) {
2872 return False;
2875 /* Do we have a string ? */
2876 if (skip_string(param,tpscnt,p) == NULL) {
2877 return False;
2879 pull_ascii_fstring(user,p);
2881 p = skip_string(param,tpscnt,p);
2882 if (!p) {
2883 return False;
2886 memset(pass1,'\0',sizeof(pass1));
2887 memset(pass2,'\0',sizeof(pass2));
2889 * We use 31 here not 32 as we're checking
2890 * the last byte we want to access is safe.
2892 if (!is_offset_safe(param,tpscnt,p,31)) {
2893 return False;
2895 memcpy(pass1,p,16);
2896 memcpy(pass2,p+16,16);
2898 encrypted = get_safe_SVAL(param,tpscnt,p+32,0,-1);
2899 if (encrypted == -1) {
2900 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2901 goto out;
2904 min_pwd_length = get_safe_SVAL(param,tpscnt,p+34,0,-1);
2905 if (min_pwd_length == -1) {
2906 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2907 goto out;
2910 *rparam_len = 4;
2911 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2912 if (!*rparam) {
2913 return False;
2916 *rdata_len = 0;
2918 DEBUG(3,("Set password for <%s> (encrypted: %d, min_pwd_length: %d)\n",
2919 user, encrypted, min_pwd_length));
2921 ZERO_STRUCT(connect_handle);
2922 ZERO_STRUCT(domain_handle);
2923 ZERO_STRUCT(user_handle);
2925 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
2926 conn->server_info,
2927 conn->sconn->msg_ctx,
2928 &cli);
2929 if (!NT_STATUS_IS_OK(status)) {
2930 DEBUG(0,("api_SetUserPassword: could not connect to samr: %s\n",
2931 nt_errstr(status)));
2932 errcode = W_ERROR_V(ntstatus_to_werror(status));
2933 goto out;
2936 status = rpccli_samr_Connect2(cli, mem_ctx,
2937 global_myname(),
2938 SAMR_ACCESS_CONNECT_TO_SERVER |
2939 SAMR_ACCESS_ENUM_DOMAINS |
2940 SAMR_ACCESS_LOOKUP_DOMAIN,
2941 &connect_handle);
2942 if (!NT_STATUS_IS_OK(status)) {
2943 errcode = W_ERROR_V(ntstatus_to_werror(status));
2944 goto out;
2947 init_lsa_String(&domain_name, get_global_sam_name());
2949 status = rpccli_samr_LookupDomain(cli, mem_ctx,
2950 &connect_handle,
2951 &domain_name,
2952 &domain_sid);
2953 if (!NT_STATUS_IS_OK(status)) {
2954 errcode = W_ERROR_V(ntstatus_to_werror(status));
2955 goto out;
2958 status = rpccli_samr_OpenDomain(cli, mem_ctx,
2959 &connect_handle,
2960 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2961 domain_sid,
2962 &domain_handle);
2963 if (!NT_STATUS_IS_OK(status)) {
2964 errcode = W_ERROR_V(ntstatus_to_werror(status));
2965 goto out;
2968 init_lsa_String(&names, user);
2970 status = rpccli_samr_LookupNames(cli, mem_ctx,
2971 &domain_handle,
2973 &names,
2974 &rids,
2975 &types);
2976 if (!NT_STATUS_IS_OK(status)) {
2977 errcode = W_ERROR_V(ntstatus_to_werror(status));
2978 goto out;
2981 if (rids.count != 1) {
2982 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
2983 goto out;
2985 if (rids.count != types.count) {
2986 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2987 goto out;
2989 if (types.ids[0] != SID_NAME_USER) {
2990 errcode = W_ERROR_V(WERR_INVALID_PARAM);
2991 goto out;
2994 rid = rids.ids[0];
2996 status = rpccli_samr_OpenUser(cli, mem_ctx,
2997 &domain_handle,
2998 SAMR_USER_ACCESS_CHANGE_PASSWORD,
2999 rid,
3000 &user_handle);
3001 if (!NT_STATUS_IS_OK(status)) {
3002 errcode = W_ERROR_V(ntstatus_to_werror(status));
3003 goto out;
3006 if (encrypted == 0) {
3007 E_deshash(pass1, old_lm_hash.hash);
3008 E_deshash(pass2, new_lm_hash.hash);
3009 } else {
3010 ZERO_STRUCT(old_lm_hash);
3011 ZERO_STRUCT(new_lm_hash);
3012 memcpy(old_lm_hash.hash, pass1, MIN(strlen(pass1), 16));
3013 memcpy(new_lm_hash.hash, pass1, MIN(strlen(pass2), 16));
3016 status = rpccli_samr_ChangePasswordUser(cli, mem_ctx,
3017 &user_handle,
3018 true, /* lm_present */
3019 &old_lm_hash,
3020 &new_lm_hash,
3021 false, /* nt_present */
3022 NULL, /* old_nt_crypted */
3023 NULL, /* new_nt_crypted */
3024 false, /* cross1_present */
3025 NULL, /* nt_cross */
3026 false, /* cross2_present */
3027 NULL); /* lm_cross */
3028 if (!NT_STATUS_IS_OK(status)) {
3029 errcode = W_ERROR_V(ntstatus_to_werror(status));
3030 goto out;
3033 errcode = NERR_Success;
3034 out:
3036 if (cli && is_valid_policy_hnd(&user_handle)) {
3037 rpccli_samr_Close(cli, mem_ctx, &user_handle);
3039 if (cli && is_valid_policy_hnd(&domain_handle)) {
3040 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
3042 if (cli && is_valid_policy_hnd(&connect_handle)) {
3043 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
3046 memset((char *)pass1,'\0',sizeof(fstring));
3047 memset((char *)pass2,'\0',sizeof(fstring));
3049 SSVAL(*rparam,0,errcode);
3050 SSVAL(*rparam,2,0); /* converter word */
3051 return(True);
3054 /****************************************************************************
3055 Set the user password (SamOEM version - gets plaintext).
3056 ****************************************************************************/
3058 static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn,
3059 connection_struct *conn,uint16 vuid,
3060 char *param, int tpscnt,
3061 char *data, int tdscnt,
3062 int mdrcnt,int mprcnt,
3063 char **rdata,char **rparam,
3064 int *rdata_len,int *rparam_len)
3066 fstring user;
3067 char *p = get_safe_str_ptr(param,tpscnt,param,2);
3069 TALLOC_CTX *mem_ctx = talloc_tos();
3070 NTSTATUS status;
3071 struct rpc_pipe_client *cli = NULL;
3072 struct lsa_AsciiString server, account;
3073 struct samr_CryptPassword password;
3074 struct samr_Password hash;
3075 int errcode = NERR_badpass;
3076 int bufsize;
3078 *rparam_len = 4;
3079 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3080 if (!*rparam) {
3081 return False;
3084 if (!p) {
3085 return False;
3087 *rdata_len = 0;
3089 SSVAL(*rparam,0,NERR_badpass);
3092 * Check the parameter definition is correct.
3095 /* Do we have a string ? */
3096 if (skip_string(param,tpscnt,p) == 0) {
3097 return False;
3099 if(!strequal(p, "zsT")) {
3100 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
3101 return False;
3103 p = skip_string(param, tpscnt, p);
3104 if (!p) {
3105 return False;
3108 /* Do we have a string ? */
3109 if (skip_string(param,tpscnt,p) == 0) {
3110 return False;
3112 if(!strequal(p, "B516B16")) {
3113 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
3114 return False;
3116 p = skip_string(param,tpscnt,p);
3117 if (!p) {
3118 return False;
3120 /* Do we have a string ? */
3121 if (skip_string(param,tpscnt,p) == 0) {
3122 return False;
3124 p += pull_ascii_fstring(user,p);
3126 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
3128 if (tdscnt != 532) {
3129 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3130 goto out;
3133 bufsize = get_safe_SVAL(param,tpscnt,p,0,-1);
3134 if (bufsize != 532) {
3135 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3136 goto out;
3139 memcpy(password.data, data, 516);
3140 memcpy(hash.hash, data+516, 16);
3142 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
3143 conn->server_info,
3144 conn->sconn->msg_ctx,
3145 &cli);
3146 if (!NT_STATUS_IS_OK(status)) {
3147 DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n",
3148 nt_errstr(status)));
3149 errcode = W_ERROR_V(ntstatus_to_werror(status));
3150 goto out;
3153 init_lsa_AsciiString(&server, global_myname());
3154 init_lsa_AsciiString(&account, user);
3156 status = rpccli_samr_OemChangePasswordUser2(cli, mem_ctx,
3157 &server,
3158 &account,
3159 &password,
3160 &hash);
3161 if (!NT_STATUS_IS_OK(status)) {
3162 errcode = W_ERROR_V(ntstatus_to_werror(status));
3163 goto out;
3166 errcode = NERR_Success;
3167 out:
3168 SSVAL(*rparam,0,errcode);
3169 SSVAL(*rparam,2,0); /* converter word */
3171 return(True);
3174 /****************************************************************************
3175 delete a print job
3176 Form: <W> <>
3177 ****************************************************************************/
3179 static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn,
3180 connection_struct *conn,uint16 vuid,
3181 char *param, int tpscnt,
3182 char *data, int tdscnt,
3183 int mdrcnt,int mprcnt,
3184 char **rdata,char **rparam,
3185 int *rdata_len,int *rparam_len)
3187 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3188 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3189 char *str2 = skip_string(param,tpscnt,str1);
3190 char *p = skip_string(param,tpscnt,str2);
3191 uint32 jobid;
3192 fstring sharename;
3193 int errcode;
3194 WERROR werr = WERR_OK;
3196 TALLOC_CTX *mem_ctx = talloc_tos();
3197 NTSTATUS status;
3198 struct rpc_pipe_client *cli = NULL;
3199 struct policy_handle handle;
3200 struct spoolss_DevmodeContainer devmode_ctr;
3201 enum spoolss_JobControl command;
3203 if (!str1 || !str2 || !p) {
3204 return False;
3207 * We use 1 here not 2 as we're checking
3208 * the last byte we want to access is safe.
3210 if (!is_offset_safe(param,tpscnt,p,1)) {
3211 return False;
3213 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3214 return False;
3216 /* check it's a supported varient */
3217 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3218 return(False);
3220 *rparam_len = 4;
3221 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3222 if (!*rparam) {
3223 return False;
3225 *rdata_len = 0;
3227 ZERO_STRUCT(handle);
3229 status = rpc_connect_spoolss_pipe(conn, &cli);
3230 if (!NT_STATUS_IS_OK(status)) {
3231 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3232 nt_errstr(status)));
3233 errcode = W_ERROR_V(ntstatus_to_werror(status));
3234 goto out;
3237 ZERO_STRUCT(devmode_ctr);
3239 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3240 sharename,
3241 "RAW",
3242 devmode_ctr,
3243 JOB_ACCESS_ADMINISTER,
3244 &handle,
3245 &werr);
3246 if (!NT_STATUS_IS_OK(status)) {
3247 errcode = W_ERROR_V(ntstatus_to_werror(status));
3248 goto out;
3250 if (!W_ERROR_IS_OK(werr)) {
3251 errcode = W_ERROR_V(werr);
3252 goto out;
3255 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3256 * and NERR_DestNotFound if share did not exist */
3258 errcode = NERR_Success;
3260 switch (function) {
3261 case 81: /* delete */
3262 command = SPOOLSS_JOB_CONTROL_DELETE;
3263 break;
3264 case 82: /* pause */
3265 command = SPOOLSS_JOB_CONTROL_PAUSE;
3266 break;
3267 case 83: /* resume */
3268 command = SPOOLSS_JOB_CONTROL_RESUME;
3269 break;
3270 default:
3271 errcode = NERR_notsupported;
3272 goto out;
3275 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3276 &handle,
3277 jobid,
3278 NULL, /* unique ptr ctr */
3279 command,
3280 &werr);
3281 if (!NT_STATUS_IS_OK(status)) {
3282 errcode = W_ERROR_V(ntstatus_to_werror(status));
3283 goto out;
3285 if (!W_ERROR_IS_OK(werr)) {
3286 errcode = W_ERROR_V(werr);
3287 goto out;
3290 out:
3291 if (cli && is_valid_policy_hnd(&handle)) {
3292 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3295 SSVAL(*rparam,0,errcode);
3296 SSVAL(*rparam,2,0); /* converter word */
3298 return(True);
3301 /****************************************************************************
3302 Purge a print queue - or pause or resume it.
3303 ****************************************************************************/
3305 static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn,
3306 connection_struct *conn,uint16 vuid,
3307 char *param, int tpscnt,
3308 char *data, int tdscnt,
3309 int mdrcnt,int mprcnt,
3310 char **rdata,char **rparam,
3311 int *rdata_len,int *rparam_len)
3313 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3314 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3315 char *str2 = skip_string(param,tpscnt,str1);
3316 char *QueueName = skip_string(param,tpscnt,str2);
3317 int errcode = NERR_notsupported;
3318 WERROR werr = WERR_OK;
3319 NTSTATUS status;
3321 TALLOC_CTX *mem_ctx = talloc_tos();
3322 struct rpc_pipe_client *cli = NULL;
3323 struct policy_handle handle;
3324 struct spoolss_SetPrinterInfoCtr info_ctr;
3325 struct spoolss_DevmodeContainer devmode_ctr;
3326 struct sec_desc_buf secdesc_ctr;
3327 enum spoolss_PrinterControl command;
3329 if (!str1 || !str2 || !QueueName) {
3330 return False;
3333 /* check it's a supported varient */
3334 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3335 return(False);
3337 *rparam_len = 4;
3338 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3339 if (!*rparam) {
3340 return False;
3342 *rdata_len = 0;
3344 if (skip_string(param,tpscnt,QueueName) == NULL) {
3345 return False;
3348 ZERO_STRUCT(handle);
3350 status = rpc_connect_spoolss_pipe(conn, &cli);
3351 if (!NT_STATUS_IS_OK(status)) {
3352 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3353 nt_errstr(status)));
3354 errcode = W_ERROR_V(ntstatus_to_werror(status));
3355 goto out;
3358 ZERO_STRUCT(devmode_ctr);
3360 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3361 QueueName,
3362 NULL,
3363 devmode_ctr,
3364 SEC_FLAG_MAXIMUM_ALLOWED,
3365 &handle,
3366 &werr);
3367 if (!NT_STATUS_IS_OK(status)) {
3368 errcode = W_ERROR_V(ntstatus_to_werror(status));
3369 goto out;
3371 if (!W_ERROR_IS_OK(werr)) {
3372 errcode = W_ERROR_V(werr);
3373 goto out;
3376 switch (function) {
3377 case 74: /* Pause queue */
3378 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3379 break;
3380 case 75: /* Resume queue */
3381 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3382 break;
3383 case 103: /* Purge */
3384 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3385 break;
3386 default:
3387 werr = WERR_NOT_SUPPORTED;
3388 break;
3391 if (!W_ERROR_IS_OK(werr)) {
3392 errcode = W_ERROR_V(werr);
3393 goto out;
3396 ZERO_STRUCT(info_ctr);
3397 ZERO_STRUCT(secdesc_ctr);
3399 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3400 &handle,
3401 &info_ctr,
3402 &devmode_ctr,
3403 &secdesc_ctr,
3404 command,
3405 &werr);
3406 if (!NT_STATUS_IS_OK(status)) {
3407 errcode = W_ERROR_V(ntstatus_to_werror(status));
3408 goto out;
3410 if (!W_ERROR_IS_OK(werr)) {
3411 errcode = W_ERROR_V(werr);
3412 goto out;
3415 errcode = W_ERROR_V(werr);
3417 out:
3419 if (cli && is_valid_policy_hnd(&handle)) {
3420 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3423 SSVAL(*rparam,0,errcode);
3424 SSVAL(*rparam,2,0); /* converter word */
3426 return(True);
3429 /****************************************************************************
3430 set the property of a print job (undocumented?)
3431 ? function = 0xb -> set name of print job
3432 ? function = 0x6 -> move print job up/down
3433 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3434 or <WWsTP> <WB21BB16B10zWWzDDz>
3435 ****************************************************************************/
3437 static int check_printjob_info(struct pack_desc* desc,
3438 int uLevel, char* id)
3440 desc->subformat = NULL;
3441 switch( uLevel ) {
3442 case 0: desc->format = "W"; break;
3443 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3444 case 2: desc->format = "WWzWWDDzz"; break;
3445 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3446 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3447 default:
3448 DEBUG(0,("check_printjob_info: invalid level %d\n",
3449 uLevel ));
3450 return False;
3452 if (id == NULL || strcmp(desc->format,id) != 0) {
3453 DEBUG(0,("check_printjob_info: invalid format %s\n",
3454 id ? id : "<NULL>" ));
3455 return False;
3457 return True;
3460 static bool api_PrintJobInfo(struct smbd_server_connection *sconn,
3461 connection_struct *conn, uint16 vuid,
3462 char *param, int tpscnt,
3463 char *data, int tdscnt,
3464 int mdrcnt,int mprcnt,
3465 char **rdata,char **rparam,
3466 int *rdata_len,int *rparam_len)
3468 struct pack_desc desc;
3469 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3470 char *str2 = skip_string(param,tpscnt,str1);
3471 char *p = skip_string(param,tpscnt,str2);
3472 uint32 jobid;
3473 fstring sharename;
3474 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3475 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3476 int errcode;
3478 TALLOC_CTX *mem_ctx = talloc_tos();
3479 WERROR werr;
3480 NTSTATUS status;
3481 struct rpc_pipe_client *cli = NULL;
3482 struct policy_handle handle;
3483 struct spoolss_DevmodeContainer devmode_ctr;
3484 struct spoolss_JobInfoContainer ctr;
3485 union spoolss_JobInfo info;
3486 struct spoolss_SetJobInfo1 info1;
3488 if (!str1 || !str2 || !p) {
3489 return False;
3492 * We use 1 here not 2 as we're checking
3493 * the last byte we want to access is safe.
3495 if (!is_offset_safe(param,tpscnt,p,1)) {
3496 return False;
3498 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3499 return False;
3500 *rparam_len = 4;
3501 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3502 if (!*rparam) {
3503 return False;
3506 *rdata_len = 0;
3508 /* check it's a supported varient */
3509 if ((strcmp(str1,"WWsTP")) ||
3510 (!check_printjob_info(&desc,uLevel,str2)))
3511 return(False);
3513 errcode = NERR_notsupported;
3515 switch (function) {
3516 case 0xb:
3517 /* change print job name, data gives the name */
3518 break;
3519 default:
3520 goto out;
3523 ZERO_STRUCT(handle);
3525 status = rpc_connect_spoolss_pipe(conn, &cli);
3526 if (!NT_STATUS_IS_OK(status)) {
3527 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3528 nt_errstr(status)));
3529 errcode = W_ERROR_V(ntstatus_to_werror(status));
3530 goto out;
3533 ZERO_STRUCT(devmode_ctr);
3535 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3536 sharename,
3537 "RAW",
3538 devmode_ctr,
3539 PRINTER_ACCESS_USE,
3540 &handle,
3541 &werr);
3542 if (!NT_STATUS_IS_OK(status)) {
3543 errcode = W_ERROR_V(ntstatus_to_werror(status));
3544 goto out;
3546 if (!W_ERROR_IS_OK(werr)) {
3547 errcode = W_ERROR_V(werr);
3548 goto out;
3551 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3552 &handle,
3553 jobid,
3554 1, /* level */
3555 0, /* offered */
3556 &info);
3557 if (!W_ERROR_IS_OK(werr)) {
3558 errcode = W_ERROR_V(werr);
3559 goto out;
3562 ZERO_STRUCT(ctr);
3564 info1.job_id = info.info1.job_id;
3565 info1.printer_name = info.info1.printer_name;
3566 info1.user_name = info.info1.user_name;
3567 info1.document_name = data;
3568 info1.data_type = info.info1.data_type;
3569 info1.text_status = info.info1.text_status;
3570 info1.status = info.info1.status;
3571 info1.priority = info.info1.priority;
3572 info1.position = info.info1.position;
3573 info1.total_pages = info.info1.total_pages;
3574 info1.pages_printed = info.info1.pages_printed;
3575 info1.submitted = info.info1.submitted;
3577 ctr.level = 1;
3578 ctr.info.info1 = &info1;
3580 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3581 &handle,
3582 jobid,
3583 &ctr,
3585 &werr);
3586 if (!NT_STATUS_IS_OK(status)) {
3587 errcode = W_ERROR_V(ntstatus_to_werror(status));
3588 goto out;
3590 if (!W_ERROR_IS_OK(werr)) {
3591 errcode = W_ERROR_V(werr);
3592 goto out;
3595 errcode = NERR_Success;
3596 out:
3598 if (cli && is_valid_policy_hnd(&handle)) {
3599 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3602 SSVALS(*rparam,0,errcode);
3603 SSVAL(*rparam,2,0); /* converter word */
3605 return(True);
3609 /****************************************************************************
3610 Get info about the server.
3611 ****************************************************************************/
3613 static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn,
3614 connection_struct *conn,uint16 vuid,
3615 char *param, int tpscnt,
3616 char *data, int tdscnt,
3617 int mdrcnt,int mprcnt,
3618 char **rdata,char **rparam,
3619 int *rdata_len,int *rparam_len)
3621 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3622 char *str2 = skip_string(param,tpscnt,str1);
3623 char *p = skip_string(param,tpscnt,str2);
3624 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3625 char *p2;
3626 int struct_len;
3628 NTSTATUS status;
3629 WERROR werr;
3630 TALLOC_CTX *mem_ctx = talloc_tos();
3631 struct rpc_pipe_client *cli = NULL;
3632 union srvsvc_NetSrvInfo info;
3633 int errcode;
3635 if (!str1 || !str2 || !p) {
3636 return False;
3639 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3641 /* check it's a supported varient */
3642 if (!prefix_ok(str1,"WrLh")) {
3643 return False;
3646 switch( uLevel ) {
3647 case 0:
3648 if (strcmp(str2,"B16") != 0) {
3649 return False;
3651 struct_len = 16;
3652 break;
3653 case 1:
3654 if (strcmp(str2,"B16BBDz") != 0) {
3655 return False;
3657 struct_len = 26;
3658 break;
3659 case 2:
3660 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3661 return False;
3663 struct_len = 134;
3664 break;
3665 case 3:
3666 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3667 return False;
3669 struct_len = 144;
3670 break;
3671 case 20:
3672 if (strcmp(str2,"DN") != 0) {
3673 return False;
3675 struct_len = 6;
3676 break;
3677 case 50:
3678 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3679 return False;
3681 struct_len = 42;
3682 break;
3683 default:
3684 return False;
3687 *rdata_len = mdrcnt;
3688 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3689 if (!*rdata) {
3690 return False;
3693 p = *rdata;
3694 p2 = p + struct_len;
3696 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_srvsvc.syntax_id,
3697 conn->server_info,
3698 conn->sconn->msg_ctx,
3699 &cli);
3700 if (!NT_STATUS_IS_OK(status)) {
3701 DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
3702 nt_errstr(status)));
3703 errcode = W_ERROR_V(ntstatus_to_werror(status));
3704 goto out;
3707 status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx,
3708 NULL,
3709 101,
3710 &info,
3711 &werr);
3712 if (!NT_STATUS_IS_OK(status)) {
3713 errcode = W_ERROR_V(ntstatus_to_werror(status));
3714 goto out;
3716 if (!W_ERROR_IS_OK(werr)) {
3717 errcode = W_ERROR_V(werr);
3718 goto out;
3721 if (info.info101 == NULL) {
3722 errcode = W_ERROR_V(WERR_INVALID_PARAM);
3723 goto out;
3726 if (uLevel != 20) {
3727 srvstr_push(NULL, 0, p, info.info101->server_name, 16,
3728 STR_ASCII|STR_UPPER|STR_TERMINATE);
3730 p += 16;
3731 if (uLevel > 0) {
3732 SCVAL(p,0,info.info101->version_major);
3733 SCVAL(p,1,info.info101->version_minor);
3734 SIVAL(p,2,info.info101->server_type);
3736 if (mdrcnt == struct_len) {
3737 SIVAL(p,6,0);
3738 } else {
3739 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3740 if (mdrcnt - struct_len <= 0) {
3741 return false;
3743 push_ascii(p2,
3744 info.info101->comment,
3745 MIN(mdrcnt - struct_len,
3746 MAX_SERVER_STRING_LENGTH),
3747 STR_TERMINATE);
3748 p2 = skip_string(*rdata,*rdata_len,p2);
3749 if (!p2) {
3750 return False;
3755 if (uLevel > 1) {
3756 return False; /* not yet implemented */
3759 errcode = NERR_Success;
3761 out:
3763 *rdata_len = PTR_DIFF(p2,*rdata);
3765 *rparam_len = 6;
3766 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3767 if (!*rparam) {
3768 return False;
3770 SSVAL(*rparam,0,errcode);
3771 SSVAL(*rparam,2,0); /* converter word */
3772 SSVAL(*rparam,4,*rdata_len);
3774 return True;
3777 /****************************************************************************
3778 Get info about the server.
3779 ****************************************************************************/
3781 static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn,
3782 connection_struct *conn,uint16 vuid,
3783 char *param, int tpscnt,
3784 char *data, int tdscnt,
3785 int mdrcnt,int mprcnt,
3786 char **rdata,char **rparam,
3787 int *rdata_len,int *rparam_len)
3789 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3790 char *str2 = skip_string(param,tpscnt,str1);
3791 char *p = skip_string(param,tpscnt,str2);
3792 char *p2;
3793 char *endp;
3794 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3796 if (!str1 || !str2 || !p) {
3797 return False;
3800 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3802 *rparam_len = 6;
3803 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3804 if (!*rparam) {
3805 return False;
3808 /* check it's a supported varient */
3809 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3810 return False;
3813 *rdata_len = mdrcnt + 1024;
3814 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3815 if (!*rdata) {
3816 return False;
3819 SSVAL(*rparam,0,NERR_Success);
3820 SSVAL(*rparam,2,0); /* converter word */
3822 p = *rdata;
3823 endp = *rdata + *rdata_len;
3825 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3826 if (!p2) {
3827 return False;
3830 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3831 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3832 strupper_m(p2);
3833 p2 = skip_string(*rdata,*rdata_len,p2);
3834 if (!p2) {
3835 return False;
3837 p += 4;
3839 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3840 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3841 p2 = skip_string(*rdata,*rdata_len,p2);
3842 if (!p2) {
3843 return False;
3845 p += 4;
3847 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3848 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3849 strupper_m(p2);
3850 p2 = skip_string(*rdata,*rdata_len,p2);
3851 if (!p2) {
3852 return False;
3854 p += 4;
3856 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3857 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3858 p += 2;
3860 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3861 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3862 p2 = skip_string(*rdata,*rdata_len,p2);
3863 if (!p2) {
3864 return False;
3866 p += 4;
3868 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3869 strlcpy(p2,"",PTR_DIFF(endp,p2));
3870 p2 = skip_string(*rdata,*rdata_len,p2);
3871 if (!p2) {
3872 return False;
3874 p += 4;
3876 *rdata_len = PTR_DIFF(p2,*rdata);
3878 SSVAL(*rparam,4,*rdata_len);
3880 return True;
3883 /****************************************************************************
3884 get info about a user
3886 struct user_info_11 {
3887 char usri11_name[21]; 0-20
3888 char usri11_pad; 21
3889 char *usri11_comment; 22-25
3890 char *usri11_usr_comment; 26-29
3891 unsigned short usri11_priv; 30-31
3892 unsigned long usri11_auth_flags; 32-35
3893 long usri11_password_age; 36-39
3894 char *usri11_homedir; 40-43
3895 char *usri11_parms; 44-47
3896 long usri11_last_logon; 48-51
3897 long usri11_last_logoff; 52-55
3898 unsigned short usri11_bad_pw_count; 56-57
3899 unsigned short usri11_num_logons; 58-59
3900 char *usri11_logon_server; 60-63
3901 unsigned short usri11_country_code; 64-65
3902 char *usri11_workstations; 66-69
3903 unsigned long usri11_max_storage; 70-73
3904 unsigned short usri11_units_per_week; 74-75
3905 unsigned char *usri11_logon_hours; 76-79
3906 unsigned short usri11_code_page; 80-81
3909 where:
3911 usri11_name specifies the user name for which information is retrieved
3913 usri11_pad aligns the next data structure element to a word boundary
3915 usri11_comment is a null terminated ASCII comment
3917 usri11_user_comment is a null terminated ASCII comment about the user
3919 usri11_priv specifies the level of the privilege assigned to the user.
3920 The possible values are:
3922 Name Value Description
3923 USER_PRIV_GUEST 0 Guest privilege
3924 USER_PRIV_USER 1 User privilege
3925 USER_PRV_ADMIN 2 Administrator privilege
3927 usri11_auth_flags specifies the account operator privileges. The
3928 possible values are:
3930 Name Value Description
3931 AF_OP_PRINT 0 Print operator
3934 Leach, Naik [Page 28]
3938 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3941 AF_OP_COMM 1 Communications operator
3942 AF_OP_SERVER 2 Server operator
3943 AF_OP_ACCOUNTS 3 Accounts operator
3946 usri11_password_age specifies how many seconds have elapsed since the
3947 password was last changed.
3949 usri11_home_dir points to a null terminated ASCII string that contains
3950 the path name of the user's home directory.
3952 usri11_parms points to a null terminated ASCII string that is set
3953 aside for use by applications.
3955 usri11_last_logon specifies the time when the user last logged on.
3956 This value is stored as the number of seconds elapsed since
3957 00:00:00, January 1, 1970.
3959 usri11_last_logoff specifies the time when the user last logged off.
3960 This value is stored as the number of seconds elapsed since
3961 00:00:00, January 1, 1970. A value of 0 means the last logoff
3962 time is unknown.
3964 usri11_bad_pw_count specifies the number of incorrect passwords
3965 entered since the last successful logon.
3967 usri11_log1_num_logons specifies the number of times this user has
3968 logged on. A value of -1 means the number of logons is unknown.
3970 usri11_logon_server points to a null terminated ASCII string that
3971 contains the name of the server to which logon requests are sent.
3972 A null string indicates logon requests should be sent to the
3973 domain controller.
3975 usri11_country_code specifies the country code for the user's language
3976 of choice.
3978 usri11_workstations points to a null terminated ASCII string that
3979 contains the names of workstations the user may log on from.
3980 There may be up to 8 workstations, with the names separated by
3981 commas. A null strings indicates there are no restrictions.
3983 usri11_max_storage specifies the maximum amount of disk space the user
3984 can occupy. A value of 0xffffffff indicates there are no
3985 restrictions.
3987 usri11_units_per_week specifies the equal number of time units into
3988 which a week is divided. This value must be equal to 168.
3990 usri11_logon_hours points to a 21 byte (168 bits) string that
3991 specifies the time during which the user can log on. Each bit
3992 represents one unique hour in a week. The first bit (bit 0, word
3993 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3997 Leach, Naik [Page 29]
4001 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
4004 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
4005 are no restrictions.
4007 usri11_code_page specifies the code page for the user's language of
4008 choice
4010 All of the pointers in this data structure need to be treated
4011 specially. The pointer is a 32 bit pointer. The higher 16 bits need
4012 to be ignored. The converter word returned in the parameters section
4013 needs to be subtracted from the lower 16 bits to calculate an offset
4014 into the return buffer where this ASCII string resides.
4016 There is no auxiliary data in the response.
4018 ****************************************************************************/
4020 #define usri11_name 0
4021 #define usri11_pad 21
4022 #define usri11_comment 22
4023 #define usri11_usr_comment 26
4024 #define usri11_full_name 30
4025 #define usri11_priv 34
4026 #define usri11_auth_flags 36
4027 #define usri11_password_age 40
4028 #define usri11_homedir 44
4029 #define usri11_parms 48
4030 #define usri11_last_logon 52
4031 #define usri11_last_logoff 56
4032 #define usri11_bad_pw_count 60
4033 #define usri11_num_logons 62
4034 #define usri11_logon_server 64
4035 #define usri11_country_code 68
4036 #define usri11_workstations 70
4037 #define usri11_max_storage 74
4038 #define usri11_units_per_week 78
4039 #define usri11_logon_hours 80
4040 #define usri11_code_page 84
4041 #define usri11_end 86
4043 static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn,
4044 connection_struct *conn, uint16 vuid,
4045 char *param, int tpscnt,
4046 char *data, int tdscnt,
4047 int mdrcnt,int mprcnt,
4048 char **rdata,char **rparam,
4049 int *rdata_len,int *rparam_len)
4051 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4052 char *str2 = skip_string(param,tpscnt,str1);
4053 char *UserName = skip_string(param,tpscnt,str2);
4054 char *p = skip_string(param,tpscnt,UserName);
4055 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4056 char *p2;
4057 char *endp;
4058 const char *level_string;
4060 TALLOC_CTX *mem_ctx = talloc_tos();
4061 NTSTATUS status;
4062 struct rpc_pipe_client *cli = NULL;
4063 struct policy_handle connect_handle, domain_handle, user_handle;
4064 struct lsa_String domain_name;
4065 struct dom_sid2 *domain_sid;
4066 struct lsa_String names;
4067 struct samr_Ids rids;
4068 struct samr_Ids types;
4069 int errcode = W_ERROR_V(WERR_USER_NOT_FOUND);
4070 uint32_t rid;
4071 union samr_UserInfo *info;
4073 if (!str1 || !str2 || !UserName || !p) {
4074 return False;
4077 *rparam_len = 6;
4078 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4079 if (!*rparam) {
4080 return False;
4083 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
4085 /* check it's a supported variant */
4086 if (strcmp(str1,"zWrLh") != 0) {
4087 return False;
4089 switch( uLevel ) {
4090 case 0: level_string = "B21"; break;
4091 case 1: level_string = "B21BB16DWzzWz"; break;
4092 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
4093 case 10: level_string = "B21Bzzz"; break;
4094 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
4095 default: return False;
4098 if (strcmp(level_string,str2) != 0) {
4099 return False;
4102 *rdata_len = mdrcnt + 1024;
4103 *rdata = smb_realloc_limit(*rdata,*rdata_len);
4104 if (!*rdata) {
4105 return False;
4108 p = *rdata;
4109 endp = *rdata + *rdata_len;
4110 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
4111 if (!p2) {
4112 return False;
4115 ZERO_STRUCT(connect_handle);
4116 ZERO_STRUCT(domain_handle);
4117 ZERO_STRUCT(user_handle);
4119 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_samr.syntax_id,
4120 conn->server_info,
4121 conn->sconn->msg_ctx,
4122 &cli);
4123 if (!NT_STATUS_IS_OK(status)) {
4124 DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n",
4125 nt_errstr(status)));
4126 errcode = W_ERROR_V(ntstatus_to_werror(status));
4127 goto out;
4130 status = rpccli_samr_Connect2(cli, mem_ctx,
4131 global_myname(),
4132 SAMR_ACCESS_CONNECT_TO_SERVER |
4133 SAMR_ACCESS_ENUM_DOMAINS |
4134 SAMR_ACCESS_LOOKUP_DOMAIN,
4135 &connect_handle);
4136 if (!NT_STATUS_IS_OK(status)) {
4137 errcode = W_ERROR_V(ntstatus_to_werror(status));
4138 goto out;
4141 init_lsa_String(&domain_name, get_global_sam_name());
4143 status = rpccli_samr_LookupDomain(cli, mem_ctx,
4144 &connect_handle,
4145 &domain_name,
4146 &domain_sid);
4147 if (!NT_STATUS_IS_OK(status)) {
4148 errcode = W_ERROR_V(ntstatus_to_werror(status));
4149 goto out;
4152 status = rpccli_samr_OpenDomain(cli, mem_ctx,
4153 &connect_handle,
4154 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
4155 domain_sid,
4156 &domain_handle);
4157 if (!NT_STATUS_IS_OK(status)) {
4158 errcode = W_ERROR_V(ntstatus_to_werror(status));
4159 goto out;
4162 init_lsa_String(&names, UserName);
4164 status = rpccli_samr_LookupNames(cli, mem_ctx,
4165 &domain_handle,
4167 &names,
4168 &rids,
4169 &types);
4170 if (!NT_STATUS_IS_OK(status)) {
4171 errcode = W_ERROR_V(ntstatus_to_werror(status));
4172 goto out;
4175 if (rids.count != 1) {
4176 errcode = W_ERROR_V(WERR_NO_SUCH_USER);
4177 goto out;
4179 if (rids.count != types.count) {
4180 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4181 goto out;
4183 if (types.ids[0] != SID_NAME_USER) {
4184 errcode = W_ERROR_V(WERR_INVALID_PARAM);
4185 goto out;
4188 rid = rids.ids[0];
4190 status = rpccli_samr_OpenUser(cli, mem_ctx,
4191 &domain_handle,
4192 SAMR_USER_ACCESS_GET_LOCALE |
4193 SAMR_USER_ACCESS_GET_LOGONINFO |
4194 SAMR_USER_ACCESS_GET_ATTRIBUTES |
4195 SAMR_USER_ACCESS_GET_GROUPS |
4196 SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
4197 SEC_STD_READ_CONTROL,
4198 rid,
4199 &user_handle);
4200 if (!NT_STATUS_IS_OK(status)) {
4201 errcode = W_ERROR_V(ntstatus_to_werror(status));
4202 goto out;
4205 status = rpccli_samr_QueryUserInfo2(cli, mem_ctx,
4206 &user_handle,
4207 UserAllInformation,
4208 &info);
4209 if (!NT_STATUS_IS_OK(status)) {
4210 errcode = W_ERROR_V(ntstatus_to_werror(status));
4211 goto out;
4214 memset(p,0,21);
4215 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
4217 if (uLevel > 0) {
4218 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
4219 *p2 = 0;
4222 if (uLevel >= 10) {
4223 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
4224 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
4225 p2 = skip_string(*rdata,*rdata_len,p2);
4226 if (!p2) {
4227 return False;
4230 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
4231 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
4232 p2 = skip_string(*rdata,*rdata_len,p2);
4233 if (!p2) {
4234 return False;
4237 /* EEK! the cifsrap.txt doesn't have this in!!!! */
4238 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
4239 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4240 p2 = skip_string(*rdata,*rdata_len,p2);
4241 if (!p2) {
4242 return False;
4246 if (uLevel == 11) {
4247 const char *homedir = info->info21.home_directory.string;
4248 /* modelled after NTAS 3.51 reply */
4249 SSVAL(p,usri11_priv,
4250 (get_current_uid(conn) == sec_initial_uid())?
4251 USER_PRIV_ADMIN:USER_PRIV_USER);
4252 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
4253 SIVALS(p,usri11_password_age,-1); /* password age */
4254 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
4255 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
4256 p2 = skip_string(*rdata,*rdata_len,p2);
4257 if (!p2) {
4258 return False;
4260 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
4261 strlcpy(p2,"",PTR_DIFF(endp,p2));
4262 p2 = skip_string(*rdata,*rdata_len,p2);
4263 if (!p2) {
4264 return False;
4266 SIVAL(p,usri11_last_logon,0); /* last logon */
4267 SIVAL(p,usri11_last_logoff,0); /* last logoff */
4268 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
4269 SSVALS(p,usri11_num_logons,-1); /* num logons */
4270 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
4271 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
4272 p2 = skip_string(*rdata,*rdata_len,p2);
4273 if (!p2) {
4274 return False;
4276 SSVAL(p,usri11_country_code,0); /* country code */
4278 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
4279 strlcpy(p2,"",PTR_DIFF(endp,p2));
4280 p2 = skip_string(*rdata,*rdata_len,p2);
4281 if (!p2) {
4282 return False;
4285 SIVALS(p,usri11_max_storage,-1); /* max storage */
4286 SSVAL(p,usri11_units_per_week,168); /* units per week */
4287 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4289 /* a simple way to get logon hours at all times. */
4290 memset(p2,0xff,21);
4291 SCVAL(p2,21,0); /* fix zero termination */
4292 p2 = skip_string(*rdata,*rdata_len,p2);
4293 if (!p2) {
4294 return False;
4297 SSVAL(p,usri11_code_page,0); /* code page */
4300 if (uLevel == 1 || uLevel == 2) {
4301 memset(p+22,' ',16); /* password */
4302 SIVALS(p,38,-1); /* password age */
4303 SSVAL(p,42,
4304 (get_current_uid(conn) == sec_initial_uid())?
4305 USER_PRIV_ADMIN:USER_PRIV_USER);
4306 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4307 strlcpy(p2, info->info21.home_directory.string,
4308 PTR_DIFF(endp,p2));
4309 p2 = skip_string(*rdata,*rdata_len,p2);
4310 if (!p2) {
4311 return False;
4313 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4314 *p2++ = 0;
4315 SSVAL(p,52,0); /* flags */
4316 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4317 strlcpy(p2, info->info21.logon_script.string,
4318 PTR_DIFF(endp,p2));
4319 p2 = skip_string(*rdata,*rdata_len,p2);
4320 if (!p2) {
4321 return False;
4323 if (uLevel == 2) {
4324 SIVAL(p,58,0); /* auth_flags */
4325 SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */
4326 strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2));
4327 p2 = skip_string(*rdata,*rdata_len,p2);
4328 if (!p2) {
4329 return False;
4331 SIVAL(p,66,0); /* urs_comment */
4332 SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */
4333 strlcpy(p2,"",PTR_DIFF(endp,p2));
4334 p2 = skip_string(*rdata,*rdata_len,p2);
4335 if (!p2) {
4336 return False;
4338 SIVAL(p,74,0); /* workstations */
4339 SIVAL(p,78,0); /* last_logon */
4340 SIVAL(p,82,0); /* last_logoff */
4341 SIVALS(p,86,-1); /* acct_expires */
4342 SIVALS(p,90,-1); /* max_storage */
4343 SSVAL(p,94,168); /* units_per_week */
4344 SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */
4345 memset(p2,-1,21);
4346 p2 += 21;
4347 SSVALS(p,100,-1); /* bad_pw_count */
4348 SSVALS(p,102,-1); /* num_logons */
4349 SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */
4351 TALLOC_CTX *ctx = talloc_tos();
4352 int space_rem = *rdata_len - (p2 - *rdata);
4353 char *tmp;
4355 if (space_rem <= 0) {
4356 return false;
4358 tmp = talloc_strdup(ctx, "\\\\%L");
4359 if (!tmp) {
4360 return false;
4362 tmp = talloc_sub_basic(ctx,
4365 tmp);
4366 if (!tmp) {
4367 return false;
4370 push_ascii(p2,
4371 tmp,
4372 space_rem,
4373 STR_TERMINATE);
4375 p2 = skip_string(*rdata,*rdata_len,p2);
4376 if (!p2) {
4377 return False;
4379 SSVAL(p,108,49); /* country_code */
4380 SSVAL(p,110,860); /* code page */
4384 errcode = NERR_Success;
4386 out:
4387 *rdata_len = PTR_DIFF(p2,*rdata);
4389 if (cli && is_valid_policy_hnd(&user_handle)) {
4390 rpccli_samr_Close(cli, mem_ctx, &user_handle);
4392 if (cli && is_valid_policy_hnd(&domain_handle)) {
4393 rpccli_samr_Close(cli, mem_ctx, &domain_handle);
4395 if (cli && is_valid_policy_hnd(&connect_handle)) {
4396 rpccli_samr_Close(cli, mem_ctx, &connect_handle);
4399 SSVAL(*rparam,0,errcode);
4400 SSVAL(*rparam,2,0); /* converter word */
4401 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4403 return(True);
4406 static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn,
4407 connection_struct *conn,uint16 vuid,
4408 char *param, int tpscnt,
4409 char *data, int tdscnt,
4410 int mdrcnt,int mprcnt,
4411 char **rdata,char **rparam,
4412 int *rdata_len,int *rparam_len)
4414 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4415 char *str2 = skip_string(param,tpscnt,str1);
4416 char *p = skip_string(param,tpscnt,str2);
4417 int uLevel;
4418 struct pack_desc desc;
4419 char* name;
4420 /* With share level security vuid will always be zero.
4421 Don't depend on vuser being non-null !!. JRA */
4422 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4424 if (!str1 || !str2 || !p) {
4425 return False;
4428 if(vuser != NULL) {
4429 DEBUG(3,(" Username of UID %d is %s\n",
4430 (int)vuser->server_info->utok.uid,
4431 vuser->server_info->unix_name));
4434 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4435 name = get_safe_str_ptr(param,tpscnt,p,2);
4436 if (!name) {
4437 return False;
4440 memset((char *)&desc,'\0',sizeof(desc));
4442 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4444 /* check it's a supported varient */
4445 if (strcmp(str1,"OOWb54WrLh") != 0) {
4446 return False;
4448 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4449 return False;
4451 if (mdrcnt > 0) {
4452 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4453 if (!*rdata) {
4454 return False;
4458 desc.base = *rdata;
4459 desc.buflen = mdrcnt;
4460 desc.subformat = NULL;
4461 desc.format = str2;
4463 if (init_package(&desc,1,0)) {
4464 PACKI(&desc,"W",0); /* code */
4465 PACKS(&desc,"B21",name); /* eff. name */
4466 PACKS(&desc,"B",""); /* pad */
4467 PACKI(&desc,"W",
4468 (get_current_uid(conn) == sec_initial_uid())?
4469 USER_PRIV_ADMIN:USER_PRIV_USER);
4470 PACKI(&desc,"D",0); /* auth flags XXX */
4471 PACKI(&desc,"W",0); /* num logons */
4472 PACKI(&desc,"W",0); /* bad pw count */
4473 PACKI(&desc,"D",0); /* last logon */
4474 PACKI(&desc,"D",-1); /* last logoff */
4475 PACKI(&desc,"D",-1); /* logoff time */
4476 PACKI(&desc,"D",-1); /* kickoff time */
4477 PACKI(&desc,"D",0); /* password age */
4478 PACKI(&desc,"D",0); /* password can change */
4479 PACKI(&desc,"D",-1); /* password must change */
4482 fstring mypath;
4483 fstrcpy(mypath,"\\\\");
4484 fstrcat(mypath,get_local_machine_name());
4485 strupper_m(mypath);
4486 PACKS(&desc,"z",mypath); /* computer */
4489 PACKS(&desc,"z",lp_workgroup());/* domain */
4490 PACKS(&desc,"z", vuser ?
4491 vuser->server_info->info3->base.logon_script.string
4492 : ""); /* script path */
4493 PACKI(&desc,"D",0x00000000); /* reserved */
4496 *rdata_len = desc.usedlen;
4497 *rparam_len = 6;
4498 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4499 if (!*rparam) {
4500 return False;
4502 SSVALS(*rparam,0,desc.errcode);
4503 SSVAL(*rparam,2,0);
4504 SSVAL(*rparam,4,desc.neededlen);
4506 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4508 return True;
4511 /****************************************************************************
4512 api_WAccessGetUserPerms
4513 ****************************************************************************/
4515 static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn,
4516 connection_struct *conn,uint16 vuid,
4517 char *param, int tpscnt,
4518 char *data, int tdscnt,
4519 int mdrcnt,int mprcnt,
4520 char **rdata,char **rparam,
4521 int *rdata_len,int *rparam_len)
4523 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4524 char *str2 = skip_string(param,tpscnt,str1);
4525 char *user = skip_string(param,tpscnt,str2);
4526 char *resource = skip_string(param,tpscnt,user);
4528 if (!str1 || !str2 || !user || !resource) {
4529 return False;
4532 if (skip_string(param,tpscnt,resource) == NULL) {
4533 return False;
4535 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4537 /* check it's a supported varient */
4538 if (strcmp(str1,"zzh") != 0) {
4539 return False;
4541 if (strcmp(str2,"") != 0) {
4542 return False;
4545 *rparam_len = 6;
4546 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4547 if (!*rparam) {
4548 return False;
4550 SSVALS(*rparam,0,0); /* errorcode */
4551 SSVAL(*rparam,2,0); /* converter word */
4552 SSVAL(*rparam,4,0x7f); /* permission flags */
4554 return True;
4557 /****************************************************************************
4558 api_WPrintJobEnumerate
4559 ****************************************************************************/
4561 static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn,
4562 connection_struct *conn, uint16 vuid,
4563 char *param, int tpscnt,
4564 char *data, int tdscnt,
4565 int mdrcnt,int mprcnt,
4566 char **rdata,char **rparam,
4567 int *rdata_len,int *rparam_len)
4569 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4570 char *str2 = skip_string(param,tpscnt,str1);
4571 char *p = skip_string(param,tpscnt,str2);
4572 int uLevel;
4573 fstring sharename;
4574 uint32 jobid;
4575 struct pack_desc desc;
4576 char *tmpdata=NULL;
4578 TALLOC_CTX *mem_ctx = talloc_tos();
4579 WERROR werr;
4580 NTSTATUS status;
4581 struct rpc_pipe_client *cli = NULL;
4582 struct policy_handle handle;
4583 struct spoolss_DevmodeContainer devmode_ctr;
4584 union spoolss_JobInfo info;
4586 if (!str1 || !str2 || !p) {
4587 return False;
4590 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4592 memset((char *)&desc,'\0',sizeof(desc));
4593 memset((char *)&status,'\0',sizeof(status));
4595 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4597 /* check it's a supported varient */
4598 if (strcmp(str1,"WWrLh") != 0) {
4599 return False;
4601 if (!check_printjob_info(&desc,uLevel,str2)) {
4602 return False;
4605 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4606 return False;
4609 ZERO_STRUCT(handle);
4611 status = rpc_connect_spoolss_pipe(conn, &cli);
4612 if (!NT_STATUS_IS_OK(status)) {
4613 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4614 nt_errstr(status)));
4615 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4616 goto out;
4619 ZERO_STRUCT(devmode_ctr);
4621 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4622 sharename,
4623 "RAW",
4624 devmode_ctr,
4625 PRINTER_ACCESS_USE,
4626 &handle,
4627 &werr);
4628 if (!NT_STATUS_IS_OK(status)) {
4629 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4630 goto out;
4632 if (!W_ERROR_IS_OK(werr)) {
4633 desc.errcode = W_ERROR_V(werr);
4634 goto out;
4637 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4638 &handle,
4639 jobid,
4640 2, /* level */
4641 0, /* offered */
4642 &info);
4643 if (!W_ERROR_IS_OK(werr)) {
4644 desc.errcode = W_ERROR_V(werr);
4645 goto out;
4648 if (mdrcnt > 0) {
4649 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4650 if (!*rdata) {
4651 return False;
4653 desc.base = *rdata;
4654 desc.buflen = mdrcnt;
4655 } else {
4657 * Don't return data but need to get correct length
4658 * init_package will return wrong size if buflen=0
4660 desc.buflen = getlen(desc.format);
4661 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4664 if (init_package(&desc,1,0)) {
4665 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4666 *rdata_len = desc.usedlen;
4667 } else {
4668 desc.errcode = NERR_JobNotFound;
4669 *rdata_len = 0;
4671 out:
4672 if (cli && is_valid_policy_hnd(&handle)) {
4673 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4676 *rparam_len = 6;
4677 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4678 if (!*rparam) {
4679 return False;
4681 SSVALS(*rparam,0,desc.errcode);
4682 SSVAL(*rparam,2,0);
4683 SSVAL(*rparam,4,desc.neededlen);
4685 SAFE_FREE(tmpdata);
4687 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4689 return True;
4692 static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn,
4693 connection_struct *conn, uint16 vuid,
4694 char *param, int tpscnt,
4695 char *data, int tdscnt,
4696 int mdrcnt,int mprcnt,
4697 char **rdata,char **rparam,
4698 int *rdata_len,int *rparam_len)
4700 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4701 char *str2 = skip_string(param,tpscnt,str1);
4702 char *p = skip_string(param,tpscnt,str2);
4703 char *name = p;
4704 int uLevel;
4705 int i, succnt=0;
4706 struct pack_desc desc;
4708 TALLOC_CTX *mem_ctx = talloc_tos();
4709 WERROR werr;
4710 NTSTATUS status;
4711 struct rpc_pipe_client *cli = NULL;
4712 struct policy_handle handle;
4713 struct spoolss_DevmodeContainer devmode_ctr;
4714 uint32_t count = 0;
4715 union spoolss_JobInfo *info;
4717 if (!str1 || !str2 || !p) {
4718 return False;
4721 memset((char *)&desc,'\0',sizeof(desc));
4723 p = skip_string(param,tpscnt,p);
4724 if (!p) {
4725 return False;
4727 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4729 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4731 /* check it's a supported variant */
4732 if (strcmp(str1,"zWrLeh") != 0) {
4733 return False;
4736 if (uLevel > 2) {
4737 return False; /* defined only for uLevel 0,1,2 */
4740 if (!check_printjob_info(&desc,uLevel,str2)) {
4741 return False;
4744 ZERO_STRUCT(handle);
4746 status = rpc_connect_spoolss_pipe(conn, &cli);
4747 if (!NT_STATUS_IS_OK(status)) {
4748 DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n",
4749 nt_errstr(status)));
4750 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4751 goto out;
4754 ZERO_STRUCT(devmode_ctr);
4756 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4757 name,
4758 NULL,
4759 devmode_ctr,
4760 SEC_FLAG_MAXIMUM_ALLOWED,
4761 &handle,
4762 &werr);
4763 if (!NT_STATUS_IS_OK(status)) {
4764 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4765 goto out;
4767 if (!W_ERROR_IS_OK(werr)) {
4768 desc.errcode = W_ERROR_V(werr);
4769 goto out;
4772 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4773 &handle,
4774 0, /* firstjob */
4775 0xff, /* numjobs */
4776 2, /* level */
4777 0, /* offered */
4778 &count,
4779 &info);
4780 if (!W_ERROR_IS_OK(werr)) {
4781 desc.errcode = W_ERROR_V(werr);
4782 goto out;
4785 if (mdrcnt > 0) {
4786 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4787 if (!*rdata) {
4788 return False;
4791 desc.base = *rdata;
4792 desc.buflen = mdrcnt;
4794 if (init_package(&desc,count,0)) {
4795 succnt = 0;
4796 for (i = 0; i < count; i++) {
4797 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4798 if (desc.errcode == NERR_Success) {
4799 succnt = i+1;
4803 out:
4804 if (cli && is_valid_policy_hnd(&handle)) {
4805 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4808 *rdata_len = desc.usedlen;
4810 *rparam_len = 8;
4811 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4812 if (!*rparam) {
4813 return False;
4815 SSVALS(*rparam,0,desc.errcode);
4816 SSVAL(*rparam,2,0);
4817 SSVAL(*rparam,4,succnt);
4818 SSVAL(*rparam,6,count);
4820 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4822 return True;
4825 static int check_printdest_info(struct pack_desc* desc,
4826 int uLevel, char* id)
4828 desc->subformat = NULL;
4829 switch( uLevel ) {
4830 case 0:
4831 desc->format = "B9";
4832 break;
4833 case 1:
4834 desc->format = "B9B21WWzW";
4835 break;
4836 case 2:
4837 desc->format = "z";
4838 break;
4839 case 3:
4840 desc->format = "zzzWWzzzWW";
4841 break;
4842 default:
4843 DEBUG(0,("check_printdest_info: invalid level %d\n",
4844 uLevel));
4845 return False;
4847 if (id == NULL || strcmp(desc->format,id) != 0) {
4848 DEBUG(0,("check_printdest_info: invalid string %s\n",
4849 id ? id : "<NULL>" ));
4850 return False;
4852 return True;
4855 static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel,
4856 struct pack_desc* desc)
4858 char buf[100];
4860 strncpy(buf, info2->printername, sizeof(buf)-1);
4861 buf[sizeof(buf)-1] = 0;
4862 strupper_m(buf);
4864 if (uLevel <= 1) {
4865 PACKS(desc,"B9",buf); /* szName */
4866 if (uLevel == 1) {
4867 PACKS(desc,"B21",""); /* szUserName */
4868 PACKI(desc,"W",0); /* uJobId */
4869 PACKI(desc,"W",0); /* fsStatus */
4870 PACKS(desc,"z",""); /* pszStatus */
4871 PACKI(desc,"W",0); /* time */
4875 if (uLevel == 2 || uLevel == 3) {
4876 PACKS(desc,"z",buf); /* pszPrinterName */
4877 if (uLevel == 3) {
4878 PACKS(desc,"z",""); /* pszUserName */
4879 PACKS(desc,"z",""); /* pszLogAddr */
4880 PACKI(desc,"W",0); /* uJobId */
4881 PACKI(desc,"W",0); /* fsStatus */
4882 PACKS(desc,"z",""); /* pszStatus */
4883 PACKS(desc,"z",""); /* pszComment */
4884 PACKS(desc,"z","NULL"); /* pszDrivers */
4885 PACKI(desc,"W",0); /* time */
4886 PACKI(desc,"W",0); /* pad1 */
4891 static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn,
4892 connection_struct *conn, uint16 vuid,
4893 char *param, int tpscnt,
4894 char *data, int tdscnt,
4895 int mdrcnt,int mprcnt,
4896 char **rdata,char **rparam,
4897 int *rdata_len,int *rparam_len)
4899 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4900 char *str2 = skip_string(param,tpscnt,str1);
4901 char *p = skip_string(param,tpscnt,str2);
4902 char* PrinterName = p;
4903 int uLevel;
4904 struct pack_desc desc;
4905 char *tmpdata=NULL;
4907 TALLOC_CTX *mem_ctx = talloc_tos();
4908 WERROR werr;
4909 NTSTATUS status;
4910 struct rpc_pipe_client *cli = NULL;
4911 struct policy_handle handle;
4912 struct spoolss_DevmodeContainer devmode_ctr;
4913 union spoolss_PrinterInfo info;
4915 if (!str1 || !str2 || !p) {
4916 return False;
4919 memset((char *)&desc,'\0',sizeof(desc));
4921 p = skip_string(param,tpscnt,p);
4922 if (!p) {
4923 return False;
4925 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4927 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4929 /* check it's a supported varient */
4930 if (strcmp(str1,"zWrLh") != 0) {
4931 return False;
4933 if (!check_printdest_info(&desc,uLevel,str2)) {
4934 return False;
4937 ZERO_STRUCT(handle);
4939 status = rpc_connect_spoolss_pipe(conn, &cli);
4940 if (!NT_STATUS_IS_OK(status)) {
4941 DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n",
4942 nt_errstr(status)));
4943 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4944 goto out;
4947 ZERO_STRUCT(devmode_ctr);
4949 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4950 PrinterName,
4951 NULL,
4952 devmode_ctr,
4953 SEC_FLAG_MAXIMUM_ALLOWED,
4954 &handle,
4955 &werr);
4956 if (!NT_STATUS_IS_OK(status)) {
4957 *rdata_len = 0;
4958 desc.errcode = NERR_DestNotFound;
4959 desc.neededlen = 0;
4960 goto out;
4962 if (!W_ERROR_IS_OK(werr)) {
4963 *rdata_len = 0;
4964 desc.errcode = NERR_DestNotFound;
4965 desc.neededlen = 0;
4966 goto out;
4969 werr = rpccli_spoolss_getprinter(cli, mem_ctx,
4970 &handle,
4973 &info);
4974 if (!W_ERROR_IS_OK(werr)) {
4975 *rdata_len = 0;
4976 desc.errcode = NERR_DestNotFound;
4977 desc.neededlen = 0;
4978 goto out;
4981 if (mdrcnt > 0) {
4982 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4983 if (!*rdata) {
4984 return False;
4986 desc.base = *rdata;
4987 desc.buflen = mdrcnt;
4988 } else {
4990 * Don't return data but need to get correct length
4991 * init_package will return wrong size if buflen=0
4993 desc.buflen = getlen(desc.format);
4994 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4996 if (init_package(&desc,1,0)) {
4997 fill_printdest_info(&info.info2, uLevel,&desc);
5000 out:
5001 if (cli && is_valid_policy_hnd(&handle)) {
5002 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
5005 *rdata_len = desc.usedlen;
5007 *rparam_len = 6;
5008 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5009 if (!*rparam) {
5010 return False;
5012 SSVALS(*rparam,0,desc.errcode);
5013 SSVAL(*rparam,2,0);
5014 SSVAL(*rparam,4,desc.neededlen);
5016 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
5017 SAFE_FREE(tmpdata);
5019 return True;
5022 static bool api_WPrintDestEnum(struct smbd_server_connection *sconn,
5023 connection_struct *conn, uint16 vuid,
5024 char *param, int tpscnt,
5025 char *data, int tdscnt,
5026 int mdrcnt,int mprcnt,
5027 char **rdata,char **rparam,
5028 int *rdata_len,int *rparam_len)
5030 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5031 char *str2 = skip_string(param,tpscnt,str1);
5032 char *p = skip_string(param,tpscnt,str2);
5033 int uLevel;
5034 int queuecnt;
5035 int i, n, succnt=0;
5036 struct pack_desc desc;
5038 TALLOC_CTX *mem_ctx = talloc_tos();
5039 WERROR werr;
5040 NTSTATUS status;
5041 struct rpc_pipe_client *cli = NULL;
5042 union spoolss_PrinterInfo *info;
5043 uint32_t count;
5045 if (!str1 || !str2 || !p) {
5046 return False;
5049 memset((char *)&desc,'\0',sizeof(desc));
5051 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5053 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
5055 /* check it's a supported varient */
5056 if (strcmp(str1,"WrLeh") != 0) {
5057 return False;
5059 if (!check_printdest_info(&desc,uLevel,str2)) {
5060 return False;
5063 queuecnt = 0;
5065 status = rpc_connect_spoolss_pipe(conn, &cli);
5066 if (!NT_STATUS_IS_OK(status)) {
5067 DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n",
5068 nt_errstr(status)));
5069 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
5070 goto out;
5073 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
5074 PRINTER_ENUM_LOCAL,
5075 cli->srv_name_slash,
5078 &count,
5079 &info);
5080 if (!W_ERROR_IS_OK(werr)) {
5081 desc.errcode = W_ERROR_V(werr);
5082 *rdata_len = 0;
5083 desc.errcode = NERR_DestNotFound;
5084 desc.neededlen = 0;
5085 goto out;
5088 queuecnt = count;
5090 if (mdrcnt > 0) {
5091 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5092 if (!*rdata) {
5093 return False;
5097 desc.base = *rdata;
5098 desc.buflen = mdrcnt;
5099 if (init_package(&desc,queuecnt,0)) {
5100 succnt = 0;
5101 n = 0;
5102 for (i = 0; i < count; i++) {
5103 fill_printdest_info(&info[i].info2, uLevel,&desc);
5104 n++;
5105 if (desc.errcode == NERR_Success) {
5106 succnt = n;
5110 out:
5111 *rdata_len = desc.usedlen;
5113 *rparam_len = 8;
5114 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5115 if (!*rparam) {
5116 return False;
5118 SSVALS(*rparam,0,desc.errcode);
5119 SSVAL(*rparam,2,0);
5120 SSVAL(*rparam,4,succnt);
5121 SSVAL(*rparam,6,queuecnt);
5123 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
5125 return True;
5128 static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn,
5129 connection_struct *conn, uint16 vuid,
5130 char *param, int tpscnt,
5131 char *data, int tdscnt,
5132 int mdrcnt,int mprcnt,
5133 char **rdata,char **rparam,
5134 int *rdata_len,int *rparam_len)
5136 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5137 char *str2 = skip_string(param,tpscnt,str1);
5138 char *p = skip_string(param,tpscnt,str2);
5139 int uLevel;
5140 int succnt;
5141 struct pack_desc desc;
5143 if (!str1 || !str2 || !p) {
5144 return False;
5147 memset((char *)&desc,'\0',sizeof(desc));
5149 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5151 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
5153 /* check it's a supported varient */
5154 if (strcmp(str1,"WrLeh") != 0) {
5155 return False;
5157 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
5158 return False;
5161 if (mdrcnt > 0) {
5162 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5163 if (!*rdata) {
5164 return False;
5167 desc.base = *rdata;
5168 desc.buflen = mdrcnt;
5169 if (init_package(&desc,1,0)) {
5170 PACKS(&desc,"B41","NULL");
5173 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5175 *rdata_len = desc.usedlen;
5177 *rparam_len = 8;
5178 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5179 if (!*rparam) {
5180 return False;
5182 SSVALS(*rparam,0,desc.errcode);
5183 SSVAL(*rparam,2,0);
5184 SSVAL(*rparam,4,succnt);
5185 SSVAL(*rparam,6,1);
5187 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
5189 return True;
5192 static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn,
5193 connection_struct *conn, uint16 vuid,
5194 char *param, int tpscnt,
5195 char *data, int tdscnt,
5196 int mdrcnt,int mprcnt,
5197 char **rdata,char **rparam,
5198 int *rdata_len,int *rparam_len)
5200 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5201 char *str2 = skip_string(param,tpscnt,str1);
5202 char *p = skip_string(param,tpscnt,str2);
5203 int uLevel;
5204 int succnt;
5205 struct pack_desc desc;
5207 if (!str1 || !str2 || !p) {
5208 return False;
5210 memset((char *)&desc,'\0',sizeof(desc));
5212 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5214 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
5216 /* check it's a supported varient */
5217 if (strcmp(str1,"WrLeh") != 0) {
5218 return False;
5220 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
5221 return False;
5224 if (mdrcnt > 0) {
5225 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5226 if (!*rdata) {
5227 return False;
5230 desc.base = *rdata;
5231 desc.buflen = mdrcnt;
5232 desc.format = str2;
5233 if (init_package(&desc,1,0)) {
5234 PACKS(&desc,"B13","lpd");
5237 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5239 *rdata_len = desc.usedlen;
5241 *rparam_len = 8;
5242 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5243 if (!*rparam) {
5244 return False;
5246 SSVALS(*rparam,0,desc.errcode);
5247 SSVAL(*rparam,2,0);
5248 SSVAL(*rparam,4,succnt);
5249 SSVAL(*rparam,6,1);
5251 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
5253 return True;
5256 static bool api_WPrintPortEnum(struct smbd_server_connection *sconn,
5257 connection_struct *conn, uint16 vuid,
5258 char *param, int tpscnt,
5259 char *data, int tdscnt,
5260 int mdrcnt,int mprcnt,
5261 char **rdata,char **rparam,
5262 int *rdata_len,int *rparam_len)
5264 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5265 char *str2 = skip_string(param,tpscnt,str1);
5266 char *p = skip_string(param,tpscnt,str2);
5267 int uLevel;
5268 int succnt;
5269 struct pack_desc desc;
5271 if (!str1 || !str2 || !p) {
5272 return False;
5275 memset((char *)&desc,'\0',sizeof(desc));
5277 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5279 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
5281 /* check it's a supported varient */
5282 if (strcmp(str1,"WrLeh") != 0) {
5283 return False;
5285 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
5286 return False;
5289 if (mdrcnt > 0) {
5290 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5291 if (!*rdata) {
5292 return False;
5295 memset((char *)&desc,'\0',sizeof(desc));
5296 desc.base = *rdata;
5297 desc.buflen = mdrcnt;
5298 desc.format = str2;
5299 if (init_package(&desc,1,0)) {
5300 PACKS(&desc,"B13","lp0");
5303 succnt = (desc.errcode == NERR_Success ? 1 : 0);
5305 *rdata_len = desc.usedlen;
5307 *rparam_len = 8;
5308 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5309 if (!*rparam) {
5310 return False;
5312 SSVALS(*rparam,0,desc.errcode);
5313 SSVAL(*rparam,2,0);
5314 SSVAL(*rparam,4,succnt);
5315 SSVAL(*rparam,6,1);
5317 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
5319 return True;
5322 /****************************************************************************
5323 List open sessions
5324 ****************************************************************************/
5326 static bool api_RNetSessionEnum(struct smbd_server_connection *sconn,
5327 connection_struct *conn, uint16 vuid,
5328 char *param, int tpscnt,
5329 char *data, int tdscnt,
5330 int mdrcnt,int mprcnt,
5331 char **rdata,char **rparam,
5332 int *rdata_len,int *rparam_len)
5335 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
5336 char *str2 = skip_string(param,tpscnt,str1);
5337 char *p = skip_string(param,tpscnt,str2);
5338 int uLevel;
5339 struct pack_desc desc;
5340 struct sessionid *session_list;
5341 int i, num_sessions;
5343 if (!str1 || !str2 || !p) {
5344 return False;
5347 memset((char *)&desc,'\0',sizeof(desc));
5349 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
5351 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
5352 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
5353 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
5355 /* check it's a supported varient */
5356 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
5357 return False;
5359 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
5360 return False;
5363 num_sessions = list_sessions(talloc_tos(), &session_list);
5365 if (mdrcnt > 0) {
5366 *rdata = smb_realloc_limit(*rdata,mdrcnt);
5367 if (!*rdata) {
5368 return False;
5371 memset((char *)&desc,'\0',sizeof(desc));
5372 desc.base = *rdata;
5373 desc.buflen = mdrcnt;
5374 desc.format = str2;
5375 if (!init_package(&desc,num_sessions,0)) {
5376 return False;
5379 for(i=0; i<num_sessions; i++) {
5380 PACKS(&desc, "z", session_list[i].remote_machine);
5381 PACKS(&desc, "z", session_list[i].username);
5382 PACKI(&desc, "W", 1); /* num conns */
5383 PACKI(&desc, "W", 0); /* num opens */
5384 PACKI(&desc, "W", 1); /* num users */
5385 PACKI(&desc, "D", 0); /* session time */
5386 PACKI(&desc, "D", 0); /* idle time */
5387 PACKI(&desc, "D", 0); /* flags */
5388 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5391 *rdata_len = desc.usedlen;
5393 *rparam_len = 8;
5394 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5395 if (!*rparam) {
5396 return False;
5398 SSVALS(*rparam,0,desc.errcode);
5399 SSVAL(*rparam,2,0); /* converter */
5400 SSVAL(*rparam,4,num_sessions); /* count */
5402 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5404 return True;
5408 /****************************************************************************
5409 The buffer was too small.
5410 ****************************************************************************/
5412 static bool api_TooSmall(struct smbd_server_connection *sconn,
5413 connection_struct *conn,uint16 vuid, char *param, char *data,
5414 int mdrcnt, int mprcnt,
5415 char **rdata, char **rparam,
5416 int *rdata_len, int *rparam_len)
5418 *rparam_len = MIN(*rparam_len,mprcnt);
5419 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5420 if (!*rparam) {
5421 return False;
5424 *rdata_len = 0;
5426 SSVAL(*rparam,0,NERR_BufTooSmall);
5428 DEBUG(3,("Supplied buffer too small in API command\n"));
5430 return True;
5433 /****************************************************************************
5434 The request is not supported.
5435 ****************************************************************************/
5437 static bool api_Unsupported(struct smbd_server_connection *sconn,
5438 connection_struct *conn, uint16 vuid,
5439 char *param, int tpscnt,
5440 char *data, int tdscnt,
5441 int mdrcnt, int mprcnt,
5442 char **rdata, char **rparam,
5443 int *rdata_len, int *rparam_len)
5445 *rparam_len = 4;
5446 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5447 if (!*rparam) {
5448 return False;
5451 *rdata_len = 0;
5453 SSVAL(*rparam,0,NERR_notsupported);
5454 SSVAL(*rparam,2,0); /* converter word */
5456 DEBUG(3,("Unsupported API command\n"));
5458 return True;
5461 static const struct {
5462 const char *name;
5463 int id;
5464 bool (*fn)(struct smbd_server_connection *sconn,
5465 connection_struct *, uint16,
5466 char *, int,
5467 char *, int,
5468 int,int,char **,char **,int *,int *);
5469 bool auth_user; /* Deny anonymous access? */
5470 } api_commands[] = {
5471 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5472 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5473 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5474 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5475 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5476 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5477 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5478 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5479 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5480 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5481 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5482 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5483 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5484 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5485 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5486 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5487 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5488 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5489 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5490 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5491 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5492 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5493 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5494 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5495 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5496 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5497 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5498 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5499 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5500 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5501 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5502 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5503 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5504 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5505 {NULL, -1, api_Unsupported}
5506 /* The following RAP calls are not implemented by Samba:
5508 RAP_WFileEnum2 - anon not OK
5513 /****************************************************************************
5514 Handle remote api calls.
5515 ****************************************************************************/
5517 void api_reply(connection_struct *conn, uint16 vuid,
5518 struct smb_request *req,
5519 char *data, char *params,
5520 int tdscnt, int tpscnt,
5521 int mdrcnt, int mprcnt)
5523 int api_command;
5524 char *rdata = NULL;
5525 char *rparam = NULL;
5526 const char *name1 = NULL;
5527 const char *name2 = NULL;
5528 int rdata_len = 0;
5529 int rparam_len = 0;
5530 bool reply=False;
5531 int i;
5533 if (!params) {
5534 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5535 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5536 return;
5539 if (tpscnt < 2) {
5540 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5541 return;
5543 api_command = SVAL(params,0);
5544 /* Is there a string at position params+2 ? */
5545 if (skip_string(params,tpscnt,params+2)) {
5546 name1 = params + 2;
5547 } else {
5548 name1 = "";
5550 name2 = skip_string(params,tpscnt,params+2);
5551 if (!name2) {
5552 name2 = "";
5555 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5556 api_command,
5557 name1,
5558 name2,
5559 tdscnt,tpscnt,mdrcnt,mprcnt));
5561 for (i=0;api_commands[i].name;i++) {
5562 if (api_commands[i].id == api_command && api_commands[i].fn) {
5563 DEBUG(3,("Doing %s\n",api_commands[i].name));
5564 break;
5568 /* Check whether this api call can be done anonymously */
5570 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5571 user_struct *user = get_valid_user_struct(req->sconn, vuid);
5573 if (!user || user->server_info->guest) {
5574 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5575 return;
5579 rdata = (char *)SMB_MALLOC(1024);
5580 if (rdata) {
5581 memset(rdata,'\0',1024);
5584 rparam = (char *)SMB_MALLOC(1024);
5585 if (rparam) {
5586 memset(rparam,'\0',1024);
5589 if(!rdata || !rparam) {
5590 DEBUG(0,("api_reply: malloc fail !\n"));
5591 SAFE_FREE(rdata);
5592 SAFE_FREE(rparam);
5593 reply_nterror(req, NT_STATUS_NO_MEMORY);
5594 return;
5597 reply = api_commands[i].fn(req->sconn, conn,
5598 vuid,
5599 params,tpscnt, /* params + length */
5600 data,tdscnt, /* data + length */
5601 mdrcnt,mprcnt,
5602 &rdata,&rparam,&rdata_len,&rparam_len);
5605 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5606 reply = api_TooSmall(req->sconn,conn,vuid,params,data,
5607 mdrcnt,mprcnt,
5608 &rdata,&rparam,&rdata_len,&rparam_len);
5611 /* if we get False back then it's actually unsupported */
5612 if (!reply) {
5613 reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt,
5614 data,
5615 tdscnt,mdrcnt,mprcnt,
5616 &rdata,&rparam,&rdata_len,&rparam_len);
5619 /* If api_Unsupported returns false we can't return anything. */
5620 if (reply) {
5621 send_trans_reply(conn, req, rparam, rparam_len,
5622 rdata, rdata_len, False);
5625 SAFE_FREE(rdata);
5626 SAFE_FREE(rparam);
5627 return;