s3-lanman: remove a unnecessary memset in api_WPrintJobEnumerate().
[Samba/ekacnet.git] / source3 / smbd / lanman.c
blob1970c86c33922c83396ee0feeaac5a87cd5890cb
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 "../librpc/gen_ndr/srv_samr.h"
33 #include "../librpc/gen_ndr/srv_spoolss.h"
34 #include "../librpc/gen_ndr/rap.h"
35 #include "../lib/util/binsearch.h"
37 #ifdef CHECK_TYPES
38 #undef CHECK_TYPES
39 #endif
40 #define CHECK_TYPES 0
42 #define NERR_Success 0
43 #define NERR_badpass 86
44 #define NERR_notsupported 50
46 #define NERR_BASE (2100)
47 #define NERR_BufTooSmall (NERR_BASE+23)
48 #define NERR_JobNotFound (NERR_BASE+51)
49 #define NERR_DestNotFound (NERR_BASE+52)
51 #define ACCESS_READ 0x01
52 #define ACCESS_WRITE 0x02
53 #define ACCESS_CREATE 0x04
55 #define SHPWLEN 8 /* share password length */
57 /* Limit size of ipc replies */
59 static char *smb_realloc_limit(void *ptr, size_t size)
61 char *val;
63 size = MAX((size),4*1024);
64 val = (char *)SMB_REALLOC(ptr,size);
65 if (val) {
66 memset(val,'\0',size);
68 return val;
71 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
72 char *param, int tpscnt,
73 char *data, int tdscnt,
74 int mdrcnt, int mprcnt,
75 char **rdata, char **rparam,
76 int *rdata_len, int *rparam_len);
78 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
79 int mdrcnt, int mprcnt,
80 char **rdata, char **rparam,
81 int *rdata_len, int *rparam_len);
84 static int CopyExpanded(connection_struct *conn,
85 int snum, char **dst, char *src, int *p_space_remaining)
87 TALLOC_CTX *ctx = talloc_tos();
88 char *buf = NULL;
89 int l;
91 if (!src || !dst || !p_space_remaining || !(*dst) ||
92 *p_space_remaining <= 0) {
93 return 0;
96 buf = talloc_strdup(ctx, src);
97 if (!buf) {
98 *p_space_remaining = 0;
99 return 0;
101 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
102 if (!buf) {
103 *p_space_remaining = 0;
104 return 0;
106 buf = talloc_sub_advanced(ctx,
107 lp_servicename(SNUM(conn)),
108 conn->server_info->unix_name,
109 conn->connectpath,
110 conn->server_info->utok.gid,
111 conn->server_info->sanitized_username,
112 pdb_get_domain(conn->server_info->sam_account),
113 buf);
114 if (!buf) {
115 *p_space_remaining = 0;
116 return 0;
118 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
119 if (l == -1) {
120 return 0;
122 (*dst) += l;
123 (*p_space_remaining) -= l;
124 return l;
127 static int CopyAndAdvance(char **dst, char *src, int *n)
129 int l;
130 if (!src || !dst || !n || !(*dst)) {
131 return 0;
133 l = push_ascii(*dst,src,*n, STR_TERMINATE);
134 if (l == -1) {
135 return 0;
137 (*dst) += l;
138 (*n) -= l;
139 return l;
142 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
144 TALLOC_CTX *ctx = talloc_tos();
145 char *buf = NULL;
146 if (!s) {
147 return 0;
149 buf = talloc_strdup(ctx,s);
150 if (!buf) {
151 return 0;
153 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
154 if (!buf) {
155 return 0;
157 buf = talloc_sub_advanced(ctx,
158 lp_servicename(SNUM(conn)),
159 conn->server_info->unix_name,
160 conn->connectpath,
161 conn->server_info->utok.gid,
162 conn->server_info->sanitized_username,
163 pdb_get_domain(conn->server_info->sam_account),
164 buf);
165 if (!buf) {
166 return 0;
168 return strlen(buf) + 1;
171 /*******************************************************************
172 Check a API string for validity when we only need to check the prefix.
173 ******************************************************************/
175 static bool prefix_ok(const char *str, const char *prefix)
177 return(strncmp(str,prefix,strlen(prefix)) == 0);
180 struct pack_desc {
181 const char *format; /* formatstring for structure */
182 const char *subformat; /* subformat for structure */
183 char *base; /* baseaddress of buffer */
184 int buflen; /* remaining size for fixed part; on init: length of base */
185 int subcount; /* count of substructures */
186 char *structbuf; /* pointer into buffer for remaining fixed part */
187 int stringlen; /* remaining size for variable part */
188 char *stringbuf; /* pointer into buffer for remaining variable part */
189 int neededlen; /* total needed size */
190 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
191 const char *curpos; /* current position; pointer into format or subformat */
192 int errcode;
195 static int get_counter(const char **p)
197 int i, n;
198 if (!p || !(*p)) {
199 return 1;
201 if (!isdigit((int)**p)) {
202 return 1;
204 for (n = 0;;) {
205 i = **p;
206 if (isdigit(i)) {
207 n = 10 * n + (i - '0');
208 } else {
209 return n;
211 (*p)++;
215 static int getlen(const char *p)
217 int n = 0;
218 if (!p) {
219 return 0;
222 while (*p) {
223 switch( *p++ ) {
224 case 'W': /* word (2 byte) */
225 n += 2;
226 break;
227 case 'K': /* status word? (2 byte) */
228 n += 2;
229 break;
230 case 'N': /* count of substructures (word) at end */
231 n += 2;
232 break;
233 case 'D': /* double word (4 byte) */
234 case 'z': /* offset to zero terminated string (4 byte) */
235 case 'l': /* offset to user data (4 byte) */
236 n += 4;
237 break;
238 case 'b': /* offset to data (with counter) (4 byte) */
239 n += 4;
240 get_counter(&p);
241 break;
242 case 'B': /* byte (with optional counter) */
243 n += get_counter(&p);
244 break;
247 return n;
250 static bool init_package(struct pack_desc *p, int count, int subcount)
252 int n = p->buflen;
253 int i;
255 if (!p->format || !p->base) {
256 return False;
259 i = count * getlen(p->format);
260 if (p->subformat) {
261 i += subcount * getlen(p->subformat);
263 p->structbuf = p->base;
264 p->neededlen = 0;
265 p->usedlen = 0;
266 p->subcount = 0;
267 p->curpos = p->format;
268 if (i > n) {
269 p->neededlen = i;
270 i = n = 0;
271 #if 0
273 * This is the old error code we used. Aparently
274 * WinNT/2k systems return ERRbuftoosmall (2123) and
275 * OS/2 needs this. I'm leaving this here so we can revert
276 * if needed. JRA.
278 p->errcode = ERRmoredata;
279 #else
280 p->errcode = ERRbuftoosmall;
281 #endif
282 } else {
283 p->errcode = NERR_Success;
285 p->buflen = i;
286 n -= i;
287 p->stringbuf = p->base + i;
288 p->stringlen = n;
289 return (p->errcode == NERR_Success);
292 static int package(struct pack_desc *p, ...)
294 va_list args;
295 int needed=0, stringneeded;
296 const char *str=NULL;
297 int is_string=0, stringused;
298 int32 temp;
300 va_start(args,p);
302 if (!*p->curpos) {
303 if (!p->subcount) {
304 p->curpos = p->format;
305 } else {
306 p->curpos = p->subformat;
307 p->subcount--;
310 #if CHECK_TYPES
311 str = va_arg(args,char*);
312 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
313 #endif
314 stringneeded = -1;
316 if (!p->curpos) {
317 va_end(args);
318 return 0;
321 switch( *p->curpos++ ) {
322 case 'W': /* word (2 byte) */
323 needed = 2;
324 temp = va_arg(args,int);
325 if (p->buflen >= needed) {
326 SSVAL(p->structbuf,0,temp);
328 break;
329 case 'K': /* status word? (2 byte) */
330 needed = 2;
331 temp = va_arg(args,int);
332 if (p->buflen >= needed) {
333 SSVAL(p->structbuf,0,temp);
335 break;
336 case 'N': /* count of substructures (word) at end */
337 needed = 2;
338 p->subcount = va_arg(args,int);
339 if (p->buflen >= needed) {
340 SSVAL(p->structbuf,0,p->subcount);
342 break;
343 case 'D': /* double word (4 byte) */
344 needed = 4;
345 temp = va_arg(args,int);
346 if (p->buflen >= needed) {
347 SIVAL(p->structbuf,0,temp);
349 break;
350 case 'B': /* byte (with optional counter) */
351 needed = get_counter(&p->curpos);
353 char *s = va_arg(args,char*);
354 if (p->buflen >= needed) {
355 StrnCpy(p->structbuf,s?s:"",needed-1);
358 break;
359 case 'z': /* offset to zero terminated string (4 byte) */
360 str = va_arg(args,char*);
361 stringneeded = (str ? strlen(str)+1 : 0);
362 is_string = 1;
363 break;
364 case 'l': /* offset to user data (4 byte) */
365 str = va_arg(args,char*);
366 stringneeded = va_arg(args,int);
367 is_string = 0;
368 break;
369 case 'b': /* offset to data (with counter) (4 byte) */
370 str = va_arg(args,char*);
371 stringneeded = get_counter(&p->curpos);
372 is_string = 0;
373 break;
376 va_end(args);
377 if (stringneeded >= 0) {
378 needed = 4;
379 if (p->buflen >= needed) {
380 stringused = stringneeded;
381 if (stringused > p->stringlen) {
382 stringused = (is_string ? p->stringlen : 0);
383 if (p->errcode == NERR_Success) {
384 p->errcode = ERRmoredata;
387 if (!stringused) {
388 SIVAL(p->structbuf,0,0);
389 } else {
390 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
391 memcpy(p->stringbuf,str?str:"",stringused);
392 if (is_string) {
393 p->stringbuf[stringused-1] = '\0';
395 p->stringbuf += stringused;
396 p->stringlen -= stringused;
397 p->usedlen += stringused;
400 p->neededlen += stringneeded;
403 p->neededlen += needed;
404 if (p->buflen >= needed) {
405 p->structbuf += needed;
406 p->buflen -= needed;
407 p->usedlen += needed;
408 } else {
409 if (p->errcode == NERR_Success) {
410 p->errcode = ERRmoredata;
413 return 1;
416 #if CHECK_TYPES
417 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
418 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
419 #else
420 #define PACK(desc,t,v) package(desc,v)
421 #define PACKl(desc,t,v,l) package(desc,v,l)
422 #endif
424 static void PACKI(struct pack_desc* desc, const char *t,int v)
426 PACK(desc,t,v);
429 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
431 PACK(desc,t,v);
434 /****************************************************************************
435 Get a print queue.
436 ****************************************************************************/
438 static void PackDriverData(struct pack_desc* desc)
440 char drivdata[4+4+32];
441 SIVAL(drivdata,0,sizeof drivdata); /* cb */
442 SIVAL(drivdata,4,1000); /* lVersion */
443 memset(drivdata+8,0,32); /* szDeviceName */
444 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
445 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
448 static int check_printq_info(struct pack_desc* desc,
449 unsigned int uLevel, char *id1, char *id2)
451 desc->subformat = NULL;
452 switch( uLevel ) {
453 case 0:
454 desc->format = "B13";
455 break;
456 case 1:
457 desc->format = "B13BWWWzzzzzWW";
458 break;
459 case 2:
460 desc->format = "B13BWWWzzzzzWN";
461 desc->subformat = "WB21BB16B10zWWzDDz";
462 break;
463 case 3:
464 desc->format = "zWWWWzzzzWWzzl";
465 break;
466 case 4:
467 desc->format = "zWWWWzzzzWNzzl";
468 desc->subformat = "WWzWWDDzz";
469 break;
470 case 5:
471 desc->format = "z";
472 break;
473 case 51:
474 desc->format = "K";
475 break;
476 case 52:
477 desc->format = "WzzzzzzzzN";
478 desc->subformat = "z";
479 break;
480 default:
481 DEBUG(0,("check_printq_info: invalid level %d\n",
482 uLevel ));
483 return False;
485 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
486 DEBUG(0,("check_printq_info: invalid format %s\n",
487 id1 ? id1 : "<NULL>" ));
488 return False;
490 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
491 DEBUG(0,("check_printq_info: invalid subformat %s\n",
492 id2 ? id2 : "<NULL>" ));
493 return False;
495 return True;
499 #define RAP_JOB_STATUS_QUEUED 0
500 #define RAP_JOB_STATUS_PAUSED 1
501 #define RAP_JOB_STATUS_SPOOLING 2
502 #define RAP_JOB_STATUS_PRINTING 3
503 #define RAP_JOB_STATUS_PRINTED 4
505 #define RAP_QUEUE_STATUS_PAUSED 1
506 #define RAP_QUEUE_STATUS_ERROR 2
508 /* turn a print job status into a on the wire status
510 static int printj_spoolss_status(int v)
512 if (v == JOB_STATUS_QUEUED)
513 return RAP_JOB_STATUS_QUEUED;
514 if (v & JOB_STATUS_PAUSED)
515 return RAP_JOB_STATUS_PAUSED;
516 if (v & JOB_STATUS_SPOOLING)
517 return RAP_JOB_STATUS_SPOOLING;
518 if (v & JOB_STATUS_PRINTING)
519 return RAP_JOB_STATUS_PRINTING;
520 return 0;
523 /* turn a print queue status into a on the wire status
525 static int printq_spoolss_status(int v)
527 if (v == PRINTER_STATUS_OK)
528 return 0;
529 if (v & PRINTER_STATUS_PAUSED)
530 return RAP_QUEUE_STATUS_PAUSED;
531 return RAP_QUEUE_STATUS_ERROR;
534 static time_t spoolss_Time_to_time_t(const struct spoolss_Time *r)
536 struct tm unixtime;
538 unixtime.tm_year = r->year - 1900;
539 unixtime.tm_mon = r->month - 1;
540 unixtime.tm_wday = r->day_of_week;
541 unixtime.tm_mday = r->day;
542 unixtime.tm_hour = r->hour;
543 unixtime.tm_min = r->minute;
544 unixtime.tm_sec = r->second;
546 return mktime(&unixtime);
549 static void fill_spoolss_printjob_info(int uLevel,
550 struct pack_desc *desc,
551 struct spoolss_JobInfo2 *info2,
552 int n)
554 time_t t = spoolss_Time_to_time_t(&info2->submitted);
556 /* the client expects localtime */
557 t -= get_time_zone(t);
559 PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */
560 if (uLevel == 1) {
561 PACKS(desc,"B21", info2->user_name); /* szUserName */
562 PACKS(desc,"B",""); /* pad */
563 PACKS(desc,"B16",""); /* szNotifyName */
564 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
565 PACKS(desc,"z",""); /* pszParms */
566 PACKI(desc,"W",n+1); /* uPosition */
567 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
568 PACKS(desc,"z",""); /* pszStatus */
569 PACKI(desc,"D", t); /* ulSubmitted */
570 PACKI(desc,"D", info2->size); /* ulSize */
571 PACKS(desc,"z", info2->document_name); /* pszComment */
573 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
574 PACKI(desc,"W", info2->priority); /* uPriority */
575 PACKS(desc,"z", info2->user_name); /* pszUserName */
576 PACKI(desc,"W",n+1); /* uPosition */
577 PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */
578 PACKI(desc,"D",t); /* ulSubmitted */
579 PACKI(desc,"D", info2->size); /* ulSize */
580 PACKS(desc,"z","Samba"); /* pszComment */
581 PACKS(desc,"z", info2->document_name); /* pszDocument */
582 if (uLevel == 3) {
583 PACKS(desc,"z",""); /* pszNotifyName */
584 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
585 PACKS(desc,"z",""); /* pszParms */
586 PACKS(desc,"z",""); /* pszStatus */
587 PACKS(desc,"z", info2->printer_name); /* pszQueue */
588 PACKS(desc,"z","lpd"); /* pszQProcName */
589 PACKS(desc,"z",""); /* pszQProcParms */
590 PACKS(desc,"z","NULL"); /* pszDriverName */
591 PackDriverData(desc); /* pDriverData */
592 PACKS(desc,"z",""); /* pszPrinterName */
593 } else if (uLevel == 4) { /* OS2 */
594 PACKS(desc,"z",""); /* pszSpoolFileName */
595 PACKS(desc,"z",""); /* pszPortName */
596 PACKS(desc,"z",""); /* pszStatus */
597 PACKI(desc,"D",0); /* ulPagesSpooled */
598 PACKI(desc,"D",0); /* ulPagesSent */
599 PACKI(desc,"D",0); /* ulPagesPrinted */
600 PACKI(desc,"D",0); /* ulTimePrinted */
601 PACKI(desc,"D",0); /* ulExtendJobStatus */
602 PACKI(desc,"D",0); /* ulStartPage */
603 PACKI(desc,"D",0); /* ulEndPage */
608 /********************************************************************
609 Respond to the DosPrintQInfo command with a level of 52
610 This is used to get printer driver information for Win9x clients
611 ********************************************************************/
612 static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver,
613 struct pack_desc* desc, int count,
614 const char *printer_name)
616 int i;
617 fstring location;
618 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
619 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
620 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
622 PACKI(desc, "W", 0x0400); /* don't know */
623 PACKS(desc, "z", driver->driver_name); /* long printer name */
624 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
625 PACKS(desc, "z", driver->data_file); /* Datafile name */
626 PACKS(desc, "z", driver->monitor_name); /* language monitor */
628 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
629 standard_sub_basic( "", "", location, sizeof(location)-1 );
630 PACKS(desc,"z", location); /* share to retrieve files */
632 PACKS(desc,"z", driver->default_datatype); /* default data type */
633 PACKS(desc,"z", driver->help_file); /* helpfile name */
634 PACKS(desc,"z", driver->driver_path); /* driver name */
636 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
637 DEBUG(3,("Driver: %s:\n",driver->driver_path));
638 DEBUG(3,("Data File: %s:\n",driver->data_file));
639 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
640 DEBUG(3,("Driver Location: %s:\n",location));
641 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
642 DEBUG(3,("Help File: %s:\n",driver->help_file));
643 PACKI(desc,"N",count); /* number of files to copy */
645 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
647 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
648 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
649 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
652 /* sanity check */
653 if ( i != count )
654 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
655 count, i));
657 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i));
659 desc->errcode=NERR_Success;
664 static void fill_printq_info(int uLevel,
665 struct pack_desc* desc,
666 int count,
667 union spoolss_JobInfo *job_info,
668 struct spoolss_DriverInfo3 *driver_info,
669 struct spoolss_PrinterInfo2 *printer_info)
671 switch (uLevel) {
672 case 1:
673 case 2:
674 PACKS(desc,"B13", printer_info->printername);
675 break;
676 case 3:
677 case 4:
678 case 5:
679 PACKS(desc,"z", printer_info->printername);
680 break;
681 case 51:
682 PACKI(desc,"K", printq_spoolss_status(printer_info->status));
683 break;
686 if (uLevel == 1 || uLevel == 2) {
687 PACKS(desc,"B",""); /* alignment */
688 PACKI(desc,"W",5); /* priority */
689 PACKI(desc,"W",0); /* start time */
690 PACKI(desc,"W",0); /* until time */
691 PACKS(desc,"z",""); /* pSepFile */
692 PACKS(desc,"z","lpd"); /* pPrProc */
693 PACKS(desc,"z", printer_info->printername); /* pDestinations */
694 PACKS(desc,"z",""); /* pParms */
695 if (printer_info->printername == NULL) {
696 PACKS(desc,"z","UNKNOWN PRINTER");
697 PACKI(desc,"W",LPSTAT_ERROR);
698 } else {
699 PACKS(desc,"z", printer_info->comment);
700 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */
702 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
705 if (uLevel == 3 || uLevel == 4) {
706 PACKI(desc,"W",5); /* uPriority */
707 PACKI(desc,"W",0); /* uStarttime */
708 PACKI(desc,"W",0); /* uUntiltime */
709 PACKI(desc,"W",5); /* pad1 */
710 PACKS(desc,"z",""); /* pszSepFile */
711 PACKS(desc,"z","WinPrint"); /* pszPrProc */
712 PACKS(desc,"z",NULL); /* pszParms */
713 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
714 /* "don't ask" that it's done this way to fix corrupted
715 Win9X/ME printer comments. */
716 PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */
717 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
718 PACKS(desc,"z", printer_info->printername); /* pszPrinters */
719 PACKS(desc,"z", printer_info->drivername); /* pszDriverName */
720 PackDriverData(desc); /* pDriverData */
723 if (uLevel == 2 || uLevel == 4) {
724 int i;
725 for (i = 0; i < count; i++) {
726 fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i);
730 if (uLevel==52)
731 fill_printq_info_52(driver_info, desc, count, printer_info->printername);
734 /* This function returns the number of files for a given driver */
735 static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver)
737 int result = 0;
739 /* count the number of files */
740 while (driver->dependent_files && *driver->dependent_files[result])
741 result++;
743 return result;
746 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
747 char *param, int tpscnt,
748 char *data, int tdscnt,
749 int mdrcnt,int mprcnt,
750 char **rdata,char **rparam,
751 int *rdata_len,int *rparam_len)
753 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
754 char *str2 = skip_string(param,tpscnt,str1);
755 char *p = skip_string(param,tpscnt,str2);
756 char *QueueName = p;
757 unsigned int uLevel;
758 uint32_t count = 0;
759 char *str3;
760 struct pack_desc desc;
761 char* tmpdata=NULL;
763 WERROR werr = WERR_OK;
764 TALLOC_CTX *mem_ctx = talloc_tos();
765 NTSTATUS status;
766 struct rpc_pipe_client *cli = NULL;
767 struct policy_handle handle;
768 struct spoolss_DevmodeContainer devmode_ctr;
769 union spoolss_DriverInfo driver_info;
770 union spoolss_JobInfo *job_info;
771 union spoolss_PrinterInfo printer_info;
773 if (!str1 || !str2 || !p) {
774 return False;
776 memset((char *)&desc,'\0',sizeof(desc));
778 p = skip_string(param,tpscnt,p);
779 if (!p) {
780 return False;
782 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
783 str3 = get_safe_str_ptr(param,tpscnt,p,4);
784 /* str3 may be null here and is checked in check_printq_info(). */
786 /* remove any trailing username */
787 if ((p = strchr_m(QueueName,'%')))
788 *p = 0;
790 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
792 /* check it's a supported varient */
793 if (!prefix_ok(str1,"zWrLh"))
794 return False;
795 if (!check_printq_info(&desc,uLevel,str2,str3)) {
797 * Patch from Scott Moomaw <scott@bridgewater.edu>
798 * to return the 'invalid info level' error if an
799 * unknown level was requested.
801 *rdata_len = 0;
802 *rparam_len = 6;
803 *rparam = smb_realloc_limit(*rparam,*rparam_len);
804 if (!*rparam) {
805 return False;
807 SSVALS(*rparam,0,ERRunknownlevel);
808 SSVAL(*rparam,2,0);
809 SSVAL(*rparam,4,0);
810 return(True);
813 ZERO_STRUCT(handle);
815 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
816 rpc_spoolss_dispatch, conn->server_info,
817 &cli);
818 if (!NT_STATUS_IS_OK(status)) {
819 DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n",
820 nt_errstr(status)));
821 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
822 goto out;
825 ZERO_STRUCT(devmode_ctr);
827 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
828 QueueName,
829 NULL,
830 devmode_ctr,
831 SEC_FLAG_MAXIMUM_ALLOWED,
832 &handle,
833 &werr);
834 if (!NT_STATUS_IS_OK(status)) {
835 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
836 goto out;
838 if (!W_ERROR_IS_OK(werr)) {
839 desc.errcode = W_ERROR_V(werr);
840 goto out;
843 if (uLevel==52) {
844 uint32_t server_major_version;
845 uint32_t server_minor_version;
847 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
848 &handle,
849 "Windows 4.0",
850 3, /* level */
852 0, /* version */
854 &driver_info,
855 &server_major_version,
856 &server_minor_version);
857 if (!W_ERROR_IS_OK(werr)) {
858 desc.errcode = W_ERROR_V(werr);
859 goto out;
862 count = get_printerdrivernumber(&driver_info.info3);
863 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
864 } else {
865 uint32_t num_jobs;
866 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
867 &handle,
868 0, /* firstjob */
869 0xff, /* numjobs */
870 2, /* level */
871 0, /* offered */
872 &num_jobs,
873 &job_info);
874 if (!W_ERROR_IS_OK(werr)) {
875 desc.errcode = W_ERROR_V(werr);
876 goto out;
879 count = num_jobs;
882 if (mdrcnt > 0) {
883 *rdata = smb_realloc_limit(*rdata,mdrcnt);
884 if (!*rdata) {
885 return False;
887 desc.base = *rdata;
888 desc.buflen = mdrcnt;
889 } else {
891 * Don't return data but need to get correct length
892 * init_package will return wrong size if buflen=0
894 desc.buflen = getlen(desc.format);
895 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
898 if (init_package(&desc,1,count)) {
899 desc.subcount = count;
900 fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2);
903 *rdata_len = desc.usedlen;
906 * We must set the return code to ERRbuftoosmall
907 * in order to support lanman style printing with Win NT/2k
908 * clients --jerry
910 if (!mdrcnt && lp_disable_spoolss())
911 desc.errcode = ERRbuftoosmall;
913 out:
914 if (is_valid_policy_hnd(&handle)) {
915 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
918 *rdata_len = desc.usedlen;
919 *rparam_len = 6;
920 *rparam = smb_realloc_limit(*rparam,*rparam_len);
921 if (!*rparam) {
922 SAFE_FREE(tmpdata);
923 return False;
925 SSVALS(*rparam,0,desc.errcode);
926 SSVAL(*rparam,2,0);
927 SSVAL(*rparam,4,desc.neededlen);
929 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
931 SAFE_FREE(tmpdata);
933 return(True);
936 /****************************************************************************
937 View list of all print jobs on all queues.
938 ****************************************************************************/
940 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
941 char *param, int tpscnt,
942 char *data, int tdscnt,
943 int mdrcnt, int mprcnt,
944 char **rdata, char** rparam,
945 int *rdata_len, int *rparam_len)
947 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
948 char *output_format1 = skip_string(param,tpscnt,param_format);
949 char *p = skip_string(param,tpscnt,output_format1);
950 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
951 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
952 int i;
953 struct pack_desc desc;
954 int *subcntarr = NULL;
955 int queuecnt = 0, subcnt = 0, succnt = 0;
957 WERROR werr = WERR_OK;
958 TALLOC_CTX *mem_ctx = talloc_tos();
959 NTSTATUS status;
960 struct rpc_pipe_client *cli = NULL;
961 struct spoolss_DevmodeContainer devmode_ctr;
962 uint32_t num_printers;
963 union spoolss_PrinterInfo *printer_info;
965 if (!param_format || !output_format1 || !p) {
966 return False;
969 memset((char *)&desc,'\0',sizeof(desc));
971 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
973 if (!prefix_ok(param_format,"WrLeh")) {
974 return False;
976 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
978 * Patch from Scott Moomaw <scott@bridgewater.edu>
979 * to return the 'invalid info level' error if an
980 * unknown level was requested.
982 *rdata_len = 0;
983 *rparam_len = 6;
984 *rparam = smb_realloc_limit(*rparam,*rparam_len);
985 if (!*rparam) {
986 return False;
988 SSVALS(*rparam,0,ERRunknownlevel);
989 SSVAL(*rparam,2,0);
990 SSVAL(*rparam,4,0);
991 return(True);
994 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
995 rpc_spoolss_dispatch, conn->server_info,
996 &cli);
997 if (!NT_STATUS_IS_OK(status)) {
998 DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n",
999 nt_errstr(status)));
1000 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1001 goto out;
1004 werr = rpccli_spoolss_enumprinters(cli, mem_ctx,
1005 PRINTER_ENUM_LOCAL,
1006 cli->srv_name_slash,
1009 &num_printers,
1010 &printer_info);
1011 if (!W_ERROR_IS_OK(werr)) {
1012 desc.errcode = W_ERROR_V(werr);
1013 goto out;
1016 queuecnt = num_printers;
1018 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1019 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1020 goto err;
1023 if (mdrcnt > 0) {
1024 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1025 if (!*rdata) {
1026 goto err;
1029 desc.base = *rdata;
1030 desc.buflen = mdrcnt;
1032 subcnt = 0;
1033 for (i = 0; i < num_printers; i++) {
1035 uint32_t num_jobs;
1036 struct policy_handle handle;
1037 union spoolss_DriverInfo driver_info;
1038 union spoolss_JobInfo *job_info;
1040 ZERO_STRUCT(handle);
1041 ZERO_STRUCT(devmode_ctr);
1043 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
1044 printer_info[i].info2.printername,
1045 NULL,
1046 devmode_ctr,
1047 SEC_FLAG_MAXIMUM_ALLOWED,
1048 &handle,
1049 &werr);
1050 if (!NT_STATUS_IS_OK(status)) {
1051 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
1052 goto out;
1054 if (!W_ERROR_IS_OK(werr)) {
1055 desc.errcode = W_ERROR_V(werr);
1056 goto out;
1059 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
1060 &handle,
1061 0, /* firstjob */
1062 0xff, /* numjobs */
1063 2, /* level */
1064 0, /* offered */
1065 &num_jobs,
1066 &job_info);
1067 if (!W_ERROR_IS_OK(werr)) {
1068 desc.errcode = W_ERROR_V(werr);
1069 goto out;
1072 if (uLevel==52) {
1073 uint32_t server_major_version;
1074 uint32_t server_minor_version;
1076 werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1077 &handle,
1078 "Windows 4.0",
1079 3, /* level */
1081 0, /* version */
1083 &driver_info,
1084 &server_major_version,
1085 &server_minor_version);
1086 if (!W_ERROR_IS_OK(werr)) {
1087 desc.errcode = W_ERROR_V(werr);
1088 goto out;
1092 subcntarr[i] = num_jobs;
1093 subcnt += subcntarr[i];
1095 if (init_package(&desc,queuecnt,subcnt)) {
1096 fill_printq_info(uLevel,&desc,subcntarr[i], job_info, &driver_info.info3, &printer_info[i].info2);
1097 if (desc.errcode == NERR_Success) {
1098 succnt = i;
1102 if (is_valid_policy_hnd(&handle)) {
1103 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1107 SAFE_FREE(subcntarr);
1108 out:
1109 *rdata_len = desc.usedlen;
1110 *rparam_len = 8;
1111 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1112 if (!*rparam) {
1113 goto err;
1115 SSVALS(*rparam,0,desc.errcode);
1116 SSVAL(*rparam,2,0);
1117 SSVAL(*rparam,4,succnt);
1118 SSVAL(*rparam,6,queuecnt);
1120 return True;
1122 err:
1124 SAFE_FREE(subcntarr);
1126 return False;
1129 /****************************************************************************
1130 Get info level for a server list query.
1131 ****************************************************************************/
1133 static bool check_server_info(int uLevel, char* id)
1135 switch( uLevel ) {
1136 case 0:
1137 if (strcmp(id,"B16") != 0) {
1138 return False;
1140 break;
1141 case 1:
1142 if (strcmp(id,"B16BBDz") != 0) {
1143 return False;
1145 break;
1146 default:
1147 return False;
1149 return True;
1152 struct srv_info_struct {
1153 fstring name;
1154 uint32 type;
1155 fstring comment;
1156 fstring domain;
1157 bool server_added;
1160 /*******************************************************************
1161 Get server info lists from the files saved by nmbd. Return the
1162 number of entries.
1163 ******************************************************************/
1165 static int get_server_info(uint32 servertype,
1166 struct srv_info_struct **servers,
1167 const char *domain)
1169 int count=0;
1170 int alloced=0;
1171 char **lines;
1172 bool local_list_only;
1173 int i;
1175 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1176 if (!lines) {
1177 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1178 return 0;
1181 /* request for everything is code for request all servers */
1182 if (servertype == SV_TYPE_ALL) {
1183 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1186 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1188 DEBUG(4,("Servertype search: %8x\n",servertype));
1190 for (i=0;lines[i];i++) {
1191 fstring stype;
1192 struct srv_info_struct *s;
1193 const char *ptr = lines[i];
1194 bool ok = True;
1195 TALLOC_CTX *frame = NULL;
1196 char *p;
1198 if (!*ptr) {
1199 continue;
1202 if (count == alloced) {
1203 alloced += 10;
1204 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1205 if (!*servers) {
1206 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1207 TALLOC_FREE(lines);
1208 return 0;
1210 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1212 s = &(*servers)[count];
1214 frame = talloc_stackframe();
1215 s->name[0] = '\0';
1216 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1217 TALLOC_FREE(frame);
1218 continue;
1220 fstrcpy(s->name, p);
1222 stype[0] = '\0';
1223 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1224 TALLOC_FREE(frame);
1225 continue;
1227 fstrcpy(stype, p);
1229 s->comment[0] = '\0';
1230 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1231 TALLOC_FREE(frame);
1232 continue;
1234 fstrcpy(s->comment, p);
1235 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1237 s->domain[0] = '\0';
1238 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1239 /* this allows us to cope with an old nmbd */
1240 fstrcpy(s->domain,lp_workgroup());
1241 } else {
1242 fstrcpy(s->domain, p);
1244 TALLOC_FREE(frame);
1246 if (sscanf(stype,"%X",&s->type) != 1) {
1247 DEBUG(4,("r:host file "));
1248 ok = False;
1251 /* Filter the servers/domains we return based on what was asked for. */
1253 /* Check to see if we are being asked for a local list only. */
1254 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1255 DEBUG(4,("r: local list only"));
1256 ok = False;
1259 /* doesn't match up: don't want it */
1260 if (!(servertype & s->type)) {
1261 DEBUG(4,("r:serv type "));
1262 ok = False;
1265 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1266 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1267 DEBUG(4,("s: dom mismatch "));
1268 ok = False;
1271 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1272 ok = False;
1275 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1276 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1278 if (ok) {
1279 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1280 s->name, s->type, s->comment, s->domain));
1281 s->server_added = True;
1282 count++;
1283 } else {
1284 DEBUG(4,("%20s %8x %25s %15s\n",
1285 s->name, s->type, s->comment, s->domain));
1289 TALLOC_FREE(lines);
1290 return count;
1293 /*******************************************************************
1294 Fill in a server info structure.
1295 ******************************************************************/
1297 static int fill_srv_info(struct srv_info_struct *service,
1298 int uLevel, char **buf, int *buflen,
1299 char **stringbuf, int *stringspace, char *baseaddr)
1301 int struct_len;
1302 char* p;
1303 char* p2;
1304 int l2;
1305 int len;
1307 switch (uLevel) {
1308 case 0:
1309 struct_len = 16;
1310 break;
1311 case 1:
1312 struct_len = 26;
1313 break;
1314 default:
1315 return -1;
1318 if (!buf) {
1319 len = 0;
1320 switch (uLevel) {
1321 case 1:
1322 len = strlen(service->comment)+1;
1323 break;
1326 *buflen = struct_len;
1327 *stringspace = len;
1328 return struct_len + len;
1331 len = struct_len;
1332 p = *buf;
1333 if (*buflen < struct_len) {
1334 return -1;
1336 if (stringbuf) {
1337 p2 = *stringbuf;
1338 l2 = *stringspace;
1339 } else {
1340 p2 = p + struct_len;
1341 l2 = *buflen - struct_len;
1343 if (!baseaddr) {
1344 baseaddr = p;
1347 switch (uLevel) {
1348 case 0:
1349 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1350 break;
1352 case 1:
1353 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1354 SIVAL(p,18,service->type);
1355 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1356 len += CopyAndAdvance(&p2,service->comment,&l2);
1357 break;
1360 if (stringbuf) {
1361 *buf = p + struct_len;
1362 *buflen -= struct_len;
1363 *stringbuf = p2;
1364 *stringspace = l2;
1365 } else {
1366 *buf = p2;
1367 *buflen -= len;
1369 return len;
1373 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1375 return StrCaseCmp(s1->name,s2->name);
1378 /****************************************************************************
1379 View list of servers available (or possibly domains). The info is
1380 extracted from lists saved by nmbd on the local host.
1381 ****************************************************************************/
1383 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1384 char *param, int tpscnt,
1385 char *data, int tdscnt,
1386 int mdrcnt, int mprcnt, char **rdata,
1387 char **rparam, int *rdata_len, int *rparam_len)
1389 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1390 char *str2 = skip_string(param,tpscnt,str1);
1391 char *p = skip_string(param,tpscnt,str2);
1392 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1393 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1394 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1395 char *p2;
1396 int data_len, fixed_len, string_len;
1397 int f_len = 0, s_len = 0;
1398 struct srv_info_struct *servers=NULL;
1399 int counted=0,total=0;
1400 int i,missed;
1401 fstring domain;
1402 bool domain_request;
1403 bool local_request;
1405 if (!str1 || !str2 || !p) {
1406 return False;
1409 /* If someone sets all the bits they don't really mean to set
1410 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1411 known servers. */
1413 if (servertype == SV_TYPE_ALL) {
1414 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1417 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1418 any other bit (they may just set this bit on its own) they
1419 want all the locally seen servers. However this bit can be
1420 set on its own so set the requested servers to be
1421 ALL - DOMAIN_ENUM. */
1423 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1424 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1427 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1428 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1430 p += 8;
1432 if (!prefix_ok(str1,"WrLehD")) {
1433 return False;
1435 if (!check_server_info(uLevel,str2)) {
1436 return False;
1439 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1440 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1441 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1443 if (strcmp(str1, "WrLehDz") == 0) {
1444 if (skip_string(param,tpscnt,p) == NULL) {
1445 return False;
1447 pull_ascii_fstring(domain, p);
1448 } else {
1449 fstrcpy(domain, lp_workgroup());
1452 DEBUG(4, ("domain [%s]\n", domain));
1454 if (lp_browse_list()) {
1455 total = get_server_info(servertype,&servers,domain);
1458 data_len = fixed_len = string_len = 0;
1459 missed = 0;
1461 TYPESAFE_QSORT(servers, total, srv_comp);
1464 char *lastname=NULL;
1466 for (i=0;i<total;i++) {
1467 struct srv_info_struct *s = &servers[i];
1469 if (lastname && strequal(lastname,s->name)) {
1470 continue;
1472 lastname = s->name;
1473 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1474 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1475 i, s->name, s->type, s->comment, s->domain));
1477 if (data_len < buf_len) {
1478 counted++;
1479 fixed_len += f_len;
1480 string_len += s_len;
1481 } else {
1482 missed++;
1487 *rdata_len = fixed_len + string_len;
1488 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1489 if (!*rdata) {
1490 return False;
1493 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1494 p = *rdata;
1495 f_len = fixed_len;
1496 s_len = string_len;
1499 char *lastname=NULL;
1500 int count2 = counted;
1502 for (i = 0; i < total && count2;i++) {
1503 struct srv_info_struct *s = &servers[i];
1505 if (lastname && strequal(lastname,s->name)) {
1506 continue;
1508 lastname = s->name;
1509 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1510 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1511 i, s->name, s->type, s->comment, s->domain));
1512 count2--;
1516 *rparam_len = 8;
1517 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1518 if (!*rparam) {
1519 return False;
1521 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1522 SSVAL(*rparam,2,0);
1523 SSVAL(*rparam,4,counted);
1524 SSVAL(*rparam,6,counted+missed);
1526 SAFE_FREE(servers);
1528 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1529 domain,uLevel,counted,counted+missed));
1531 return True;
1534 static int srv_name_match(const char *n1, const char *n2)
1537 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1539 * In Windows, FirstNameToReturn need not be an exact match:
1540 * the server will return a list of servers that exist on
1541 * the network greater than or equal to the FirstNameToReturn.
1543 int ret = StrCaseCmp(n1, n2);
1545 if (ret <= 0) {
1546 return 0;
1549 return ret;
1552 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1553 char *param, int tpscnt,
1554 char *data, int tdscnt,
1555 int mdrcnt, int mprcnt, char **rdata,
1556 char **rparam, int *rdata_len, int *rparam_len)
1558 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1559 char *str2 = skip_string(param,tpscnt,str1);
1560 char *p = skip_string(param,tpscnt,str2);
1561 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1562 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1563 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1564 char *p2;
1565 int data_len, fixed_len, string_len;
1566 int f_len = 0, s_len = 0;
1567 struct srv_info_struct *servers=NULL;
1568 int counted=0,first=0,total=0;
1569 int i,missed;
1570 fstring domain;
1571 fstring first_name;
1572 bool domain_request;
1573 bool local_request;
1575 if (!str1 || !str2 || !p) {
1576 return False;
1579 /* If someone sets all the bits they don't really mean to set
1580 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1581 known servers. */
1583 if (servertype == SV_TYPE_ALL) {
1584 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1587 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1588 any other bit (they may just set this bit on its own) they
1589 want all the locally seen servers. However this bit can be
1590 set on its own so set the requested servers to be
1591 ALL - DOMAIN_ENUM. */
1593 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1594 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1597 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1598 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1600 p += 8;
1602 if (strcmp(str1, "WrLehDzz") != 0) {
1603 return false;
1605 if (!check_server_info(uLevel,str2)) {
1606 return False;
1609 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1610 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1611 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1613 if (skip_string(param,tpscnt,p) == NULL) {
1614 return False;
1616 pull_ascii_fstring(domain, p);
1617 if (domain[0] == '\0') {
1618 fstrcpy(domain, lp_workgroup());
1620 p = skip_string(param,tpscnt,p);
1621 if (skip_string(param,tpscnt,p) == NULL) {
1622 return False;
1624 pull_ascii_fstring(first_name, p);
1626 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1627 domain, first_name));
1629 if (lp_browse_list()) {
1630 total = get_server_info(servertype,&servers,domain);
1633 data_len = fixed_len = string_len = 0;
1634 missed = 0;
1636 TYPESAFE_QSORT(servers, total, srv_comp);
1638 if (first_name[0] != '\0') {
1639 struct srv_info_struct *first_server = NULL;
1641 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1642 srv_name_match, first_server);
1643 if (first_server) {
1644 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1646 * The binary search may not find the exact match
1647 * so we need to search backward to find the first match
1649 * This implements the strange matching windows
1650 * implements. (see the comment in srv_name_match().
1652 for (;first > 0;) {
1653 int ret;
1654 ret = StrCaseCmp(first_name,
1655 servers[first-1].name);
1656 if (ret > 0) {
1657 break;
1659 first--;
1661 } else {
1662 /* we should return no entries */
1663 first = total;
1668 char *lastname=NULL;
1670 for (i=first;i<total;i++) {
1671 struct srv_info_struct *s = &servers[i];
1673 if (lastname && strequal(lastname,s->name)) {
1674 continue;
1676 lastname = s->name;
1677 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1678 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1679 i, s->name, s->type, s->comment, s->domain));
1681 if (data_len < buf_len) {
1682 counted++;
1683 fixed_len += f_len;
1684 string_len += s_len;
1685 } else {
1686 missed++;
1691 *rdata_len = fixed_len + string_len;
1692 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1693 if (!*rdata) {
1694 return False;
1697 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1698 p = *rdata;
1699 f_len = fixed_len;
1700 s_len = string_len;
1703 char *lastname=NULL;
1704 int count2 = counted;
1706 for (i = first; i < total && count2;i++) {
1707 struct srv_info_struct *s = &servers[i];
1709 if (lastname && strequal(lastname,s->name)) {
1710 continue;
1712 lastname = s->name;
1713 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1714 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1715 i, s->name, s->type, s->comment, s->domain));
1716 count2--;
1720 *rparam_len = 8;
1721 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1722 if (!*rparam) {
1723 return False;
1725 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1726 SSVAL(*rparam,2,0);
1727 SSVAL(*rparam,4,counted);
1728 SSVAL(*rparam,6,counted+missed);
1730 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1731 domain,uLevel,first,first_name,
1732 first < total ? servers[first].name : "",
1733 counted,counted+missed));
1735 SAFE_FREE(servers);
1737 return True;
1740 /****************************************************************************
1741 command 0x34 - suspected of being a "Lookup Names" stub api
1742 ****************************************************************************/
1744 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1745 char *param, int tpscnt,
1746 char *data, int tdscnt,
1747 int mdrcnt, int mprcnt, char **rdata,
1748 char **rparam, int *rdata_len, int *rparam_len)
1750 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1751 char *str2 = skip_string(param,tpscnt,str1);
1752 char *p = skip_string(param,tpscnt,str2);
1753 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1754 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1755 int counted=0;
1756 int missed=0;
1758 if (!str1 || !str2 || !p) {
1759 return False;
1762 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1763 str1, str2, p, uLevel, buf_len));
1765 if (!prefix_ok(str1,"zWrLeh")) {
1766 return False;
1769 *rdata_len = 0;
1771 *rparam_len = 8;
1772 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1773 if (!*rparam) {
1774 return False;
1777 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1778 SSVAL(*rparam,2,0);
1779 SSVAL(*rparam,4,counted);
1780 SSVAL(*rparam,6,counted+missed);
1782 return True;
1785 /****************************************************************************
1786 get info about a share
1787 ****************************************************************************/
1789 static bool check_share_info(int uLevel, char* id)
1791 switch( uLevel ) {
1792 case 0:
1793 if (strcmp(id,"B13") != 0) {
1794 return False;
1796 break;
1797 case 1:
1798 /* Level-2 descriptor is allowed (and ignored) */
1799 if (strcmp(id,"B13BWz") != 0 &&
1800 strcmp(id,"B13BWzWWWzB9B") != 0) {
1801 return False;
1803 break;
1804 case 2:
1805 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1806 return False;
1808 break;
1809 case 91:
1810 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1811 return False;
1813 break;
1814 default:
1815 return False;
1817 return True;
1820 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1821 char** buf, int* buflen,
1822 char** stringbuf, int* stringspace, char* baseaddr)
1824 int struct_len;
1825 char* p;
1826 char* p2;
1827 int l2;
1828 int len;
1830 switch( uLevel ) {
1831 case 0:
1832 struct_len = 13;
1833 break;
1834 case 1:
1835 struct_len = 20;
1836 break;
1837 case 2:
1838 struct_len = 40;
1839 break;
1840 case 91:
1841 struct_len = 68;
1842 break;
1843 default:
1844 return -1;
1847 if (!buf) {
1848 len = 0;
1850 if (uLevel > 0) {
1851 len += StrlenExpanded(conn,snum,lp_comment(snum));
1853 if (uLevel > 1) {
1854 len += strlen(lp_pathname(snum)) + 1;
1856 if (buflen) {
1857 *buflen = struct_len;
1859 if (stringspace) {
1860 *stringspace = len;
1862 return struct_len + len;
1865 len = struct_len;
1866 p = *buf;
1867 if ((*buflen) < struct_len) {
1868 return -1;
1871 if (stringbuf) {
1872 p2 = *stringbuf;
1873 l2 = *stringspace;
1874 } else {
1875 p2 = p + struct_len;
1876 l2 = (*buflen) - struct_len;
1879 if (!baseaddr) {
1880 baseaddr = p;
1883 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1885 if (uLevel > 0) {
1886 int type;
1888 SCVAL(p,13,0);
1889 type = STYPE_DISKTREE;
1890 if (lp_print_ok(snum)) {
1891 type = STYPE_PRINTQ;
1893 if (strequal("IPC",lp_fstype(snum))) {
1894 type = STYPE_IPC;
1896 SSVAL(p,14,type); /* device type */
1897 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1898 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1901 if (uLevel > 1) {
1902 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1903 SSVALS(p,22,-1); /* max uses */
1904 SSVAL(p,24,1); /* current uses */
1905 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1906 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1907 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1910 if (uLevel > 2) {
1911 memset(p+40,0,SHPWLEN+2);
1912 SSVAL(p,50,0);
1913 SIVAL(p,52,0);
1914 SSVAL(p,56,0);
1915 SSVAL(p,58,0);
1916 SIVAL(p,60,0);
1917 SSVAL(p,64,0);
1918 SSVAL(p,66,0);
1921 if (stringbuf) {
1922 (*buf) = p + struct_len;
1923 (*buflen) -= struct_len;
1924 (*stringbuf) = p2;
1925 (*stringspace) = l2;
1926 } else {
1927 (*buf) = p2;
1928 (*buflen) -= len;
1931 return len;
1934 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1935 char *param, int tpscnt,
1936 char *data, int tdscnt,
1937 int mdrcnt,int mprcnt,
1938 char **rdata,char **rparam,
1939 int *rdata_len,int *rparam_len)
1941 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1942 char *str2 = skip_string(param,tpscnt,str1);
1943 char *netname = skip_string(param,tpscnt,str2);
1944 char *p = skip_string(param,tpscnt,netname);
1945 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1946 int snum;
1948 if (!str1 || !str2 || !netname || !p) {
1949 return False;
1952 snum = find_service(netname);
1953 if (snum < 0) {
1954 return False;
1957 /* check it's a supported varient */
1958 if (!prefix_ok(str1,"zWrLh")) {
1959 return False;
1961 if (!check_share_info(uLevel,str2)) {
1962 return False;
1965 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1966 if (!*rdata) {
1967 return False;
1969 p = *rdata;
1970 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1971 if (*rdata_len < 0) {
1972 return False;
1975 *rparam_len = 6;
1976 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1977 if (!*rparam) {
1978 return False;
1980 SSVAL(*rparam,0,NERR_Success);
1981 SSVAL(*rparam,2,0); /* converter word */
1982 SSVAL(*rparam,4,*rdata_len);
1984 return True;
1987 /****************************************************************************
1988 View the list of available shares.
1990 This function is the server side of the NetShareEnum() RAP call.
1991 It fills the return buffer with share names and share comments.
1992 Note that the return buffer normally (in all known cases) allows only
1993 twelve byte strings for share names (plus one for a nul terminator).
1994 Share names longer than 12 bytes must be skipped.
1995 ****************************************************************************/
1997 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1998 char *param, int tpscnt,
1999 char *data, int tdscnt,
2000 int mdrcnt,
2001 int mprcnt,
2002 char **rdata,
2003 char **rparam,
2004 int *rdata_len,
2005 int *rparam_len )
2007 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2008 char *str2 = skip_string(param,tpscnt,str1);
2009 char *p = skip_string(param,tpscnt,str2);
2010 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2011 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
2012 char *p2;
2013 int count = 0;
2014 int total=0,counted=0;
2015 bool missed = False;
2016 int i;
2017 int data_len, fixed_len, string_len;
2018 int f_len = 0, s_len = 0;
2020 if (!str1 || !str2 || !p) {
2021 return False;
2024 if (!prefix_ok(str1,"WrLeh")) {
2025 return False;
2027 if (!check_share_info(uLevel,str2)) {
2028 return False;
2031 /* Ensure all the usershares are loaded. */
2032 become_root();
2033 load_registry_shares();
2034 count = load_usershare_shares();
2035 unbecome_root();
2037 data_len = fixed_len = string_len = 0;
2038 for (i=0;i<count;i++) {
2039 fstring servicename_dos;
2040 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2041 continue;
2043 push_ascii_fstring(servicename_dos, lp_servicename(i));
2044 /* Maximum name length = 13. */
2045 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2046 total++;
2047 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2048 if (data_len < buf_len) {
2049 counted++;
2050 fixed_len += f_len;
2051 string_len += s_len;
2052 } else {
2053 missed = True;
2058 *rdata_len = fixed_len + string_len;
2059 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2060 if (!*rdata) {
2061 return False;
2064 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2065 p = *rdata;
2066 f_len = fixed_len;
2067 s_len = string_len;
2069 for( i = 0; i < count; i++ ) {
2070 fstring servicename_dos;
2071 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2072 continue;
2075 push_ascii_fstring(servicename_dos, lp_servicename(i));
2076 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2077 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2078 break;
2083 *rparam_len = 8;
2084 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2085 if (!*rparam) {
2086 return False;
2088 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2089 SSVAL(*rparam,2,0);
2090 SSVAL(*rparam,4,counted);
2091 SSVAL(*rparam,6,total);
2093 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2094 counted,total,uLevel,
2095 buf_len,*rdata_len,mdrcnt));
2097 return True;
2100 /****************************************************************************
2101 Add a share
2102 ****************************************************************************/
2104 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2105 char *param, int tpscnt,
2106 char *data, int tdscnt,
2107 int mdrcnt,int mprcnt,
2108 char **rdata,char **rparam,
2109 int *rdata_len,int *rparam_len)
2111 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2112 char *str2 = skip_string(param,tpscnt,str1);
2113 char *p = skip_string(param,tpscnt,str2);
2114 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2115 fstring sharename;
2116 fstring comment;
2117 char *pathname = NULL;
2118 char *command, *cmdname;
2119 unsigned int offset;
2120 int snum;
2121 int res = ERRunsup;
2122 size_t converted_size;
2124 if (!str1 || !str2 || !p) {
2125 return False;
2128 /* check it's a supported varient */
2129 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2130 return False;
2132 if (!check_share_info(uLevel,str2)) {
2133 return False;
2135 if (uLevel != 2) {
2136 return False;
2139 /* Do we have a string ? */
2140 if (skip_string(data,mdrcnt,data) == NULL) {
2141 return False;
2143 pull_ascii_fstring(sharename,data);
2144 snum = find_service(sharename);
2145 if (snum >= 0) { /* already exists */
2146 res = ERRfilexists;
2147 goto error_exit;
2150 if (mdrcnt < 28) {
2151 return False;
2154 /* only support disk share adds */
2155 if (SVAL(data,14)!=STYPE_DISKTREE) {
2156 return False;
2159 offset = IVAL(data, 16);
2160 if (offset >= mdrcnt) {
2161 res = ERRinvalidparam;
2162 goto error_exit;
2165 /* Do we have a string ? */
2166 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2167 return False;
2169 pull_ascii_fstring(comment, offset? (data+offset) : "");
2171 offset = IVAL(data, 26);
2173 if (offset >= mdrcnt) {
2174 res = ERRinvalidparam;
2175 goto error_exit;
2178 /* Do we have a string ? */
2179 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2180 return False;
2183 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2184 offset ? (data+offset) : "", &converted_size))
2186 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2187 strerror(errno)));
2190 if (!pathname) {
2191 return false;
2194 string_replace(sharename, '"', ' ');
2195 string_replace(pathname, '"', ' ');
2196 string_replace(comment, '"', ' ');
2198 cmdname = lp_add_share_cmd();
2200 if (!cmdname || *cmdname == '\0') {
2201 return False;
2204 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
2205 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
2206 pathname, comment) == -1) {
2207 return false;
2210 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
2212 if ((res = smbrun(command, NULL)) != 0) {
2213 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
2214 command, res ));
2215 SAFE_FREE(command);
2216 res = ERRnoaccess;
2217 goto error_exit;
2218 } else {
2219 SAFE_FREE(command);
2220 message_send_all(smbd_messaging_context(),
2221 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2224 *rparam_len = 6;
2225 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2226 if (!*rparam) {
2227 return False;
2229 SSVAL(*rparam,0,NERR_Success);
2230 SSVAL(*rparam,2,0); /* converter word */
2231 SSVAL(*rparam,4,*rdata_len);
2232 *rdata_len = 0;
2234 return True;
2236 error_exit:
2238 *rparam_len = 4;
2239 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2240 if (!*rparam) {
2241 return False;
2243 *rdata_len = 0;
2244 SSVAL(*rparam,0,res);
2245 SSVAL(*rparam,2,0);
2246 return True;
2249 /****************************************************************************
2250 view list of groups available
2251 ****************************************************************************/
2253 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2254 char *param, int tpscnt,
2255 char *data, int tdscnt,
2256 int mdrcnt,int mprcnt,
2257 char **rdata,char **rparam,
2258 int *rdata_len,int *rparam_len)
2260 int i;
2261 int errflags=0;
2262 int resume_context, cli_buf_size;
2263 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2264 char *str2 = skip_string(param,tpscnt,str1);
2265 char *p = skip_string(param,tpscnt,str2);
2267 uint32_t num_groups;
2268 uint32_t resume_handle;
2269 struct rpc_pipe_client *samr_pipe;
2270 struct policy_handle samr_handle, domain_handle;
2271 NTSTATUS status;
2273 if (!str1 || !str2 || !p) {
2274 return False;
2277 if (strcmp(str1,"WrLeh") != 0) {
2278 return False;
2281 /* parameters
2282 * W-> resume context (number of users to skip)
2283 * r -> return parameter pointer to receive buffer
2284 * L -> length of receive buffer
2285 * e -> return parameter number of entries
2286 * h -> return parameter total number of users
2289 if (strcmp("B21",str2) != 0) {
2290 return False;
2293 status = rpc_pipe_open_internal(
2294 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2295 conn->server_info, &samr_pipe);
2296 if (!NT_STATUS_IS_OK(status)) {
2297 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2298 nt_errstr(status)));
2299 return false;
2302 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2303 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2304 if (!NT_STATUS_IS_OK(status)) {
2305 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2306 nt_errstr(status)));
2307 return false;
2310 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2311 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2312 get_global_sam_sid(), &domain_handle);
2313 if (!NT_STATUS_IS_OK(status)) {
2314 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2315 nt_errstr(status)));
2316 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2317 return false;
2320 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2321 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2322 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2323 "%d\n", resume_context, cli_buf_size));
2325 *rdata_len = cli_buf_size;
2326 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2327 if (!*rdata) {
2328 return False;
2331 p = *rdata;
2333 errflags = NERR_Success;
2334 num_groups = 0;
2335 resume_handle = 0;
2337 while (true) {
2338 struct samr_SamArray *sam_entries;
2339 uint32_t num_entries;
2341 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2342 &domain_handle,
2343 &resume_handle,
2344 &sam_entries, 1,
2345 &num_entries);
2346 if (!NT_STATUS_IS_OK(status)) {
2347 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2348 "%s\n", nt_errstr(status)));
2349 break;
2352 if (num_entries == 0) {
2353 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2354 "no entries -- done\n"));
2355 break;
2358 for(i=0; i<num_entries; i++) {
2359 const char *name;
2361 name = sam_entries->entries[i].name.string;
2363 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2364 /* set overflow error */
2365 DEBUG(3,("overflow on entry %d group %s\n", i,
2366 name));
2367 errflags=234;
2368 break;
2371 /* truncate the name at 21 chars. */
2372 memset(p, 0, 21);
2373 strlcpy(p, name, 21);
2374 DEBUG(10,("adding entry %d group %s\n", i, p));
2375 p += 21;
2376 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2377 * idea why... */
2378 num_groups += 1;
2381 if (errflags != NERR_Success) {
2382 break;
2385 TALLOC_FREE(sam_entries);
2388 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2389 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2391 *rdata_len = PTR_DIFF(p,*rdata);
2393 *rparam_len = 8;
2394 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2395 if (!*rparam) {
2396 return False;
2398 SSVAL(*rparam, 0, errflags);
2399 SSVAL(*rparam, 2, 0); /* converter word */
2400 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2401 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2403 return(True);
2406 /*******************************************************************
2407 Get groups that a user is a member of.
2408 ******************************************************************/
2410 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2411 char *param, int tpscnt,
2412 char *data, int tdscnt,
2413 int mdrcnt,int mprcnt,
2414 char **rdata,char **rparam,
2415 int *rdata_len,int *rparam_len)
2417 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2418 char *str2 = skip_string(param,tpscnt,str1);
2419 char *UserName = skip_string(param,tpscnt,str2);
2420 char *p = skip_string(param,tpscnt,UserName);
2421 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2422 const char *level_string;
2423 int count=0;
2424 bool ret = False;
2425 uint32_t i;
2426 char *endp = NULL;
2428 struct rpc_pipe_client *samr_pipe;
2429 struct policy_handle samr_handle, domain_handle, user_handle;
2430 struct lsa_String name;
2431 struct lsa_Strings names;
2432 struct samr_Ids type, rid;
2433 struct samr_RidWithAttributeArray *rids;
2434 NTSTATUS status;
2436 if (!str1 || !str2 || !UserName || !p) {
2437 return False;
2440 *rparam_len = 8;
2441 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2442 if (!*rparam) {
2443 return False;
2446 /* check it's a supported varient */
2448 if ( strcmp(str1,"zWrLeh") != 0 )
2449 return False;
2451 switch( uLevel ) {
2452 case 0:
2453 level_string = "B21";
2454 break;
2455 default:
2456 return False;
2459 if (strcmp(level_string,str2) != 0)
2460 return False;
2462 *rdata_len = mdrcnt + 1024;
2463 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2464 if (!*rdata) {
2465 return False;
2468 SSVAL(*rparam,0,NERR_Success);
2469 SSVAL(*rparam,2,0); /* converter word */
2471 p = *rdata;
2472 endp = *rdata + *rdata_len;
2474 status = rpc_pipe_open_internal(
2475 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2476 conn->server_info, &samr_pipe);
2477 if (!NT_STATUS_IS_OK(status)) {
2478 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2479 nt_errstr(status)));
2480 return false;
2483 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2484 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2485 if (!NT_STATUS_IS_OK(status)) {
2486 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2487 nt_errstr(status)));
2488 return false;
2491 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2492 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2493 get_global_sam_sid(), &domain_handle);
2494 if (!NT_STATUS_IS_OK(status)) {
2495 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2496 nt_errstr(status)));
2497 goto close_sam;
2500 name.string = UserName;
2502 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2503 &domain_handle, 1, &name,
2504 &rid, &type);
2505 if (!NT_STATUS_IS_OK(status)) {
2506 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2507 nt_errstr(status)));
2508 goto close_domain;
2511 if (type.ids[0] != SID_NAME_USER) {
2512 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2513 sid_type_lookup(type.ids[0])));
2514 goto close_domain;
2517 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2518 &domain_handle,
2519 SAMR_USER_ACCESS_GET_GROUPS,
2520 rid.ids[0], &user_handle);
2521 if (!NT_STATUS_IS_OK(status)) {
2522 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2523 nt_errstr(status)));
2524 goto close_domain;
2527 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2528 &user_handle, &rids);
2529 if (!NT_STATUS_IS_OK(status)) {
2530 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2531 nt_errstr(status)));
2532 goto close_user;
2535 for (i=0; i<rids->count; i++) {
2537 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2538 &domain_handle,
2539 1, &rids->rids[i].rid,
2540 &names, &type);
2541 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2542 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2543 p += 21;
2544 count++;
2548 *rdata_len = PTR_DIFF(p,*rdata);
2550 SSVAL(*rparam,4,count); /* is this right?? */
2551 SSVAL(*rparam,6,count); /* is this right?? */
2553 ret = True;
2555 close_user:
2556 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2557 close_domain:
2558 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2559 close_sam:
2560 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2562 return ret;
2565 /*******************************************************************
2566 Get all users.
2567 ******************************************************************/
2569 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2570 char *param, int tpscnt,
2571 char *data, int tdscnt,
2572 int mdrcnt,int mprcnt,
2573 char **rdata,char **rparam,
2574 int *rdata_len,int *rparam_len)
2576 int count_sent=0;
2577 int num_users=0;
2578 int errflags=0;
2579 int i, resume_context, cli_buf_size;
2580 uint32_t resume_handle;
2582 struct rpc_pipe_client *samr_pipe;
2583 struct policy_handle samr_handle, domain_handle;
2584 NTSTATUS status;
2586 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2587 char *str2 = skip_string(param,tpscnt,str1);
2588 char *p = skip_string(param,tpscnt,str2);
2589 char *endp = NULL;
2591 if (!str1 || !str2 || !p) {
2592 return False;
2595 if (strcmp(str1,"WrLeh") != 0)
2596 return False;
2597 /* parameters
2598 * W-> resume context (number of users to skip)
2599 * r -> return parameter pointer to receive buffer
2600 * L -> length of receive buffer
2601 * e -> return parameter number of entries
2602 * h -> return parameter total number of users
2605 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2606 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2607 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2608 resume_context, cli_buf_size));
2610 *rparam_len = 8;
2611 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2612 if (!*rparam) {
2613 return False;
2616 /* check it's a supported varient */
2617 if (strcmp("B21",str2) != 0)
2618 return False;
2620 *rdata_len = cli_buf_size;
2621 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2622 if (!*rdata) {
2623 return False;
2626 p = *rdata;
2627 endp = *rdata + *rdata_len;
2629 status = rpc_pipe_open_internal(
2630 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2631 conn->server_info, &samr_pipe);
2632 if (!NT_STATUS_IS_OK(status)) {
2633 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2634 nt_errstr(status)));
2635 return false;
2638 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2639 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2640 if (!NT_STATUS_IS_OK(status)) {
2641 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2642 nt_errstr(status)));
2643 return false;
2646 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2647 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2648 get_global_sam_sid(), &domain_handle);
2649 if (!NT_STATUS_IS_OK(status)) {
2650 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2651 nt_errstr(status)));
2652 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2653 return false;
2656 errflags=NERR_Success;
2658 resume_handle = 0;
2660 while (true) {
2661 struct samr_SamArray *sam_entries;
2662 uint32_t num_entries;
2664 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2665 &domain_handle,
2666 &resume_handle,
2667 0, &sam_entries, 1,
2668 &num_entries);
2670 if (!NT_STATUS_IS_OK(status)) {
2671 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2672 "%s\n", nt_errstr(status)));
2673 break;
2676 if (num_entries == 0) {
2677 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2678 "no entries -- done\n"));
2679 break;
2682 for (i=0; i<num_entries; i++) {
2683 const char *name;
2685 name = sam_entries->entries[i].name.string;
2687 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2688 &&(strlen(name)<=21)) {
2689 strlcpy(p,name,PTR_DIFF(endp,p));
2690 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2691 "username %s\n",count_sent,p));
2692 p += 21;
2693 count_sent++;
2694 } else {
2695 /* set overflow error */
2696 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2697 "username %s\n",count_sent,name));
2698 errflags=234;
2699 break;
2703 if (errflags != NERR_Success) {
2704 break;
2707 TALLOC_FREE(sam_entries);
2710 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2711 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2713 *rdata_len = PTR_DIFF(p,*rdata);
2715 SSVAL(*rparam,0,errflags);
2716 SSVAL(*rparam,2,0); /* converter word */
2717 SSVAL(*rparam,4,count_sent); /* is this right?? */
2718 SSVAL(*rparam,6,num_users); /* is this right?? */
2720 return True;
2723 /****************************************************************************
2724 Get the time of day info.
2725 ****************************************************************************/
2727 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2728 char *param, int tpscnt,
2729 char *data, int tdscnt,
2730 int mdrcnt,int mprcnt,
2731 char **rdata,char **rparam,
2732 int *rdata_len,int *rparam_len)
2734 struct tm *t;
2735 time_t unixdate = time(NULL);
2736 char *p;
2738 *rparam_len = 4;
2739 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2740 if (!*rparam) {
2741 return False;
2744 *rdata_len = 21;
2745 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2746 if (!*rdata) {
2747 return False;
2750 SSVAL(*rparam,0,NERR_Success);
2751 SSVAL(*rparam,2,0); /* converter word */
2753 p = *rdata;
2755 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2756 by NT in a "net time" operation,
2757 it seems to ignore the one below */
2759 /* the client expects to get localtime, not GMT, in this bit
2760 (I think, this needs testing) */
2761 t = localtime(&unixdate);
2762 if (!t) {
2763 return False;
2766 SIVAL(p,4,0); /* msecs ? */
2767 SCVAL(p,8,t->tm_hour);
2768 SCVAL(p,9,t->tm_min);
2769 SCVAL(p,10,t->tm_sec);
2770 SCVAL(p,11,0); /* hundredths of seconds */
2771 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2772 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2773 SCVAL(p,16,t->tm_mday);
2774 SCVAL(p,17,t->tm_mon + 1);
2775 SSVAL(p,18,1900+t->tm_year);
2776 SCVAL(p,20,t->tm_wday);
2778 return True;
2781 /****************************************************************************
2782 Set the user password.
2783 *****************************************************************************/
2785 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2786 char *param, int tpscnt,
2787 char *data, int tdscnt,
2788 int mdrcnt,int mprcnt,
2789 char **rdata,char **rparam,
2790 int *rdata_len,int *rparam_len)
2792 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2793 char *p = NULL;
2794 fstring user;
2795 fstring pass1,pass2;
2797 /* Skip 2 strings. */
2798 p = skip_string(param,tpscnt,np);
2799 p = skip_string(param,tpscnt,p);
2801 if (!np || !p) {
2802 return False;
2805 /* Do we have a string ? */
2806 if (skip_string(param,tpscnt,p) == NULL) {
2807 return False;
2809 pull_ascii_fstring(user,p);
2811 p = skip_string(param,tpscnt,p);
2812 if (!p) {
2813 return False;
2816 memset(pass1,'\0',sizeof(pass1));
2817 memset(pass2,'\0',sizeof(pass2));
2819 * We use 31 here not 32 as we're checking
2820 * the last byte we want to access is safe.
2822 if (!is_offset_safe(param,tpscnt,p,31)) {
2823 return False;
2825 memcpy(pass1,p,16);
2826 memcpy(pass2,p+16,16);
2828 *rparam_len = 4;
2829 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2830 if (!*rparam) {
2831 return False;
2834 *rdata_len = 0;
2836 SSVAL(*rparam,0,NERR_badpass);
2837 SSVAL(*rparam,2,0); /* converter word */
2839 DEBUG(3,("Set password for <%s>\n",user));
2842 * Attempt to verify the old password against smbpasswd entries
2843 * Win98 clients send old and new password in plaintext for this call.
2847 struct auth_serversupplied_info *server_info = NULL;
2848 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2850 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2852 become_root();
2853 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2854 SSVAL(*rparam,0,NERR_Success);
2856 unbecome_root();
2858 TALLOC_FREE(server_info);
2860 data_blob_clear_free(&password);
2864 * If the plaintext change failed, attempt
2865 * the old encrypted method. NT will generate this
2866 * after trying the samr method. Note that this
2867 * method is done as a last resort as this
2868 * password change method loses the NT password hash
2869 * and cannot change the UNIX password as no plaintext
2870 * is received.
2873 if(SVAL(*rparam,0) != NERR_Success) {
2874 struct samu *hnd = NULL;
2876 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2877 become_root();
2878 if (change_lanman_password(hnd,(uchar *)pass2)) {
2879 SSVAL(*rparam,0,NERR_Success);
2881 unbecome_root();
2882 TALLOC_FREE(hnd);
2886 memset((char *)pass1,'\0',sizeof(fstring));
2887 memset((char *)pass2,'\0',sizeof(fstring));
2889 return(True);
2892 /****************************************************************************
2893 Set the user password (SamOEM version - gets plaintext).
2894 ****************************************************************************/
2896 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2897 char *param, int tpscnt,
2898 char *data, int tdscnt,
2899 int mdrcnt,int mprcnt,
2900 char **rdata,char **rparam,
2901 int *rdata_len,int *rparam_len)
2903 struct smbd_server_connection *sconn = smbd_server_conn;
2904 fstring user;
2905 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2906 *rparam_len = 2;
2907 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2908 if (!*rparam) {
2909 return False;
2912 if (!p) {
2913 return False;
2915 *rdata_len = 0;
2917 SSVAL(*rparam,0,NERR_badpass);
2920 * Check the parameter definition is correct.
2923 /* Do we have a string ? */
2924 if (skip_string(param,tpscnt,p) == 0) {
2925 return False;
2927 if(!strequal(p, "zsT")) {
2928 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2929 return False;
2931 p = skip_string(param, tpscnt, p);
2932 if (!p) {
2933 return False;
2936 /* Do we have a string ? */
2937 if (skip_string(param,tpscnt,p) == 0) {
2938 return False;
2940 if(!strequal(p, "B516B16")) {
2941 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2942 return False;
2944 p = skip_string(param,tpscnt,p);
2945 if (!p) {
2946 return False;
2948 /* Do we have a string ? */
2949 if (skip_string(param,tpscnt,p) == 0) {
2950 return False;
2952 p += pull_ascii_fstring(user,p);
2954 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2957 * Pass the user through the NT -> unix user mapping
2958 * function.
2961 (void)map_username(sconn, user);
2963 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2964 SSVAL(*rparam,0,NERR_Success);
2967 return(True);
2970 /****************************************************************************
2971 delete a print job
2972 Form: <W> <>
2973 ****************************************************************************/
2975 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2976 char *param, int tpscnt,
2977 char *data, int tdscnt,
2978 int mdrcnt,int mprcnt,
2979 char **rdata,char **rparam,
2980 int *rdata_len,int *rparam_len)
2982 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2983 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2984 char *str2 = skip_string(param,tpscnt,str1);
2985 char *p = skip_string(param,tpscnt,str2);
2986 uint32 jobid;
2987 fstring sharename;
2988 int errcode;
2989 WERROR werr = WERR_OK;
2991 TALLOC_CTX *mem_ctx = talloc_tos();
2992 NTSTATUS status;
2993 struct rpc_pipe_client *cli = NULL;
2994 struct policy_handle handle;
2995 struct spoolss_DevmodeContainer devmode_ctr;
2996 enum spoolss_JobControl command;
2998 if (!str1 || !str2 || !p) {
2999 return False;
3002 * We use 1 here not 2 as we're checking
3003 * the last byte we want to access is safe.
3005 if (!is_offset_safe(param,tpscnt,p,1)) {
3006 return False;
3008 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3009 return False;
3011 /* check it's a supported varient */
3012 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
3013 return(False);
3015 *rparam_len = 4;
3016 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3017 if (!*rparam) {
3018 return False;
3020 *rdata_len = 0;
3022 ZERO_STRUCT(handle);
3024 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3025 rpc_spoolss_dispatch, conn->server_info,
3026 &cli);
3027 if (!NT_STATUS_IS_OK(status)) {
3028 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
3029 nt_errstr(status)));
3030 errcode = W_ERROR_V(ntstatus_to_werror(status));
3031 goto out;
3034 ZERO_STRUCT(devmode_ctr);
3036 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3037 sharename,
3038 NULL,
3039 devmode_ctr,
3040 SEC_FLAG_MAXIMUM_ALLOWED,
3041 &handle,
3042 &werr);
3043 if (!NT_STATUS_IS_OK(status)) {
3044 errcode = W_ERROR_V(ntstatus_to_werror(status));
3045 goto out;
3047 if (!W_ERROR_IS_OK(werr)) {
3048 errcode = W_ERROR_V(werr);
3049 goto out;
3052 /* FIXME: formerly NERR_JobNotFound was returned if job did not exist
3053 * and NERR_DestNotFound if share did not exist */
3055 errcode = NERR_Success;
3057 switch (function) {
3058 case 81: /* delete */
3059 command = SPOOLSS_JOB_CONTROL_DELETE;
3060 break;
3061 case 82: /* pause */
3062 command = SPOOLSS_JOB_CONTROL_PAUSE;
3063 break;
3064 case 83: /* resume */
3065 command = SPOOLSS_JOB_CONTROL_RESUME;
3066 break;
3067 default:
3068 errcode = NERR_notsupported;
3069 goto out;
3072 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3073 &handle,
3074 jobid,
3075 NULL, /* unique ptr ctr */
3076 command,
3077 &werr);
3078 if (!NT_STATUS_IS_OK(status)) {
3079 errcode = W_ERROR_V(ntstatus_to_werror(status));
3080 goto out;
3082 if (!W_ERROR_IS_OK(werr)) {
3083 errcode = W_ERROR_V(werr);
3084 goto out;
3087 out:
3088 if (is_valid_policy_hnd(&handle)) {
3089 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3092 SSVAL(*rparam,0,errcode);
3093 SSVAL(*rparam,2,0); /* converter word */
3095 return(True);
3098 /****************************************************************************
3099 Purge a print queue - or pause or resume it.
3100 ****************************************************************************/
3102 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3103 char *param, int tpscnt,
3104 char *data, int tdscnt,
3105 int mdrcnt,int mprcnt,
3106 char **rdata,char **rparam,
3107 int *rdata_len,int *rparam_len)
3109 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3110 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3111 char *str2 = skip_string(param,tpscnt,str1);
3112 char *QueueName = skip_string(param,tpscnt,str2);
3113 int errcode = NERR_notsupported;
3114 WERROR werr = WERR_OK;
3115 NTSTATUS status;
3117 TALLOC_CTX *mem_ctx = talloc_tos();
3118 struct rpc_pipe_client *cli = NULL;
3119 struct policy_handle handle;
3120 struct spoolss_SetPrinterInfoCtr info_ctr;
3121 struct spoolss_DevmodeContainer devmode_ctr;
3122 struct sec_desc_buf secdesc_ctr;
3123 enum spoolss_PrinterControl command;
3125 if (!str1 || !str2 || !QueueName) {
3126 return False;
3129 /* check it's a supported varient */
3130 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3131 return(False);
3133 *rparam_len = 4;
3134 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3135 if (!*rparam) {
3136 return False;
3138 *rdata_len = 0;
3140 if (skip_string(param,tpscnt,QueueName) == NULL) {
3141 return False;
3144 ZERO_STRUCT(handle);
3146 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3147 rpc_spoolss_dispatch, conn->server_info,
3148 &cli);
3149 if (!NT_STATUS_IS_OK(status)) {
3150 DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n",
3151 nt_errstr(status)));
3152 errcode = W_ERROR_V(ntstatus_to_werror(status));
3153 goto out;
3156 ZERO_STRUCT(devmode_ctr);
3158 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3159 QueueName,
3160 NULL,
3161 devmode_ctr,
3162 SEC_FLAG_MAXIMUM_ALLOWED,
3163 &handle,
3164 &werr);
3165 if (!NT_STATUS_IS_OK(status)) {
3166 errcode = W_ERROR_V(ntstatus_to_werror(status));
3167 goto out;
3169 if (!W_ERROR_IS_OK(werr)) {
3170 errcode = W_ERROR_V(werr);
3171 goto out;
3174 switch (function) {
3175 case 74: /* Pause queue */
3176 command = SPOOLSS_PRINTER_CONTROL_PAUSE;
3177 break;
3178 case 75: /* Resume queue */
3179 command = SPOOLSS_PRINTER_CONTROL_RESUME;
3180 break;
3181 case 103: /* Purge */
3182 command = SPOOLSS_PRINTER_CONTROL_PURGE;
3183 break;
3184 default:
3185 werr = WERR_NOT_SUPPORTED;
3186 break;
3189 if (!W_ERROR_IS_OK(werr)) {
3190 errcode = W_ERROR_V(werr);
3191 goto out;
3194 ZERO_STRUCT(info_ctr);
3195 ZERO_STRUCT(secdesc_ctr);
3197 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
3198 &handle,
3199 &info_ctr,
3200 &devmode_ctr,
3201 &secdesc_ctr,
3202 command,
3203 &werr);
3204 if (!NT_STATUS_IS_OK(status)) {
3205 errcode = W_ERROR_V(ntstatus_to_werror(status));
3206 goto out;
3208 if (!W_ERROR_IS_OK(werr)) {
3209 errcode = W_ERROR_V(werr);
3210 goto out;
3213 errcode = W_ERROR_V(werr);
3215 out:
3217 if (is_valid_policy_hnd(&handle)) {
3218 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3221 SSVAL(*rparam,0,errcode);
3222 SSVAL(*rparam,2,0); /* converter word */
3224 return(True);
3227 /****************************************************************************
3228 set the property of a print job (undocumented?)
3229 ? function = 0xb -> set name of print job
3230 ? function = 0x6 -> move print job up/down
3231 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3232 or <WWsTP> <WB21BB16B10zWWzDDz>
3233 ****************************************************************************/
3235 static int check_printjob_info(struct pack_desc* desc,
3236 int uLevel, char* id)
3238 desc->subformat = NULL;
3239 switch( uLevel ) {
3240 case 0: desc->format = "W"; break;
3241 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3242 case 2: desc->format = "WWzWWDDzz"; break;
3243 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3244 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3245 default:
3246 DEBUG(0,("check_printjob_info: invalid level %d\n",
3247 uLevel ));
3248 return False;
3250 if (id == NULL || strcmp(desc->format,id) != 0) {
3251 DEBUG(0,("check_printjob_info: invalid format %s\n",
3252 id ? id : "<NULL>" ));
3253 return False;
3255 return True;
3258 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3259 char *param, int tpscnt,
3260 char *data, int tdscnt,
3261 int mdrcnt,int mprcnt,
3262 char **rdata,char **rparam,
3263 int *rdata_len,int *rparam_len)
3265 struct pack_desc desc;
3266 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3267 char *str2 = skip_string(param,tpscnt,str1);
3268 char *p = skip_string(param,tpscnt,str2);
3269 uint32 jobid;
3270 fstring sharename;
3271 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3272 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3273 int errcode;
3275 TALLOC_CTX *mem_ctx = talloc_tos();
3276 WERROR werr;
3277 NTSTATUS status;
3278 struct rpc_pipe_client *cli = NULL;
3279 struct policy_handle handle;
3280 struct spoolss_DevmodeContainer devmode_ctr;
3281 struct spoolss_JobInfoContainer ctr;
3282 union spoolss_JobInfo info;
3283 struct spoolss_SetJobInfo1 info1;
3285 if (!str1 || !str2 || !p) {
3286 return False;
3289 * We use 1 here not 2 as we're checking
3290 * the last byte we want to access is safe.
3292 if (!is_offset_safe(param,tpscnt,p,1)) {
3293 return False;
3295 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3296 return False;
3297 *rparam_len = 4;
3298 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3299 if (!*rparam) {
3300 return False;
3303 ZERO_STRUCT(handle);
3305 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
3306 rpc_spoolss_dispatch, conn->server_info,
3307 &cli);
3308 if (!NT_STATUS_IS_OK(status)) {
3309 DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n",
3310 nt_errstr(status)));
3311 errcode = W_ERROR_V(ntstatus_to_werror(status));
3312 goto out;
3315 ZERO_STRUCT(devmode_ctr);
3317 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
3318 sharename,
3319 NULL,
3320 devmode_ctr,
3321 SEC_FLAG_MAXIMUM_ALLOWED,
3322 &handle,
3323 &werr);
3324 if (!NT_STATUS_IS_OK(status)) {
3325 errcode = W_ERROR_V(ntstatus_to_werror(status));
3326 goto out;
3328 if (!W_ERROR_IS_OK(werr)) {
3329 errcode = W_ERROR_V(werr);
3330 goto out;
3333 *rdata_len = 0;
3335 /* check it's a supported varient */
3336 if ((strcmp(str1,"WWsTP")) ||
3337 (!check_printjob_info(&desc,uLevel,str2)))
3338 return(False);
3340 werr = rpccli_spoolss_getjob(cli, mem_ctx,
3341 &handle,
3342 jobid,
3343 1, /* level */
3344 0, /* offered */
3345 &info);
3346 if (!W_ERROR_IS_OK(werr)) {
3347 errcode = W_ERROR_V(werr);
3348 goto out;
3351 errcode = NERR_notsupported;
3353 switch (function) {
3354 case 0xb:
3355 /* change print job name, data gives the name */
3356 break;
3357 default:
3358 goto out;
3361 ZERO_STRUCT(ctr);
3363 info1.job_id = info.info1.job_id;
3364 info1.printer_name = info.info1.printer_name;
3365 info1.user_name = info.info1.user_name;
3366 info1.document_name = data;
3367 info1.data_type = info.info1.data_type;
3368 info1.text_status = info.info1.text_status;
3369 info1.status = info.info1.status;
3370 info1.priority = info.info1.priority;
3371 info1.position = info.info1.position;
3372 info1.total_pages = info.info1.total_pages;
3373 info1.pages_printed = info.info1.pages_printed;
3374 info1.submitted = info.info1.submitted;
3376 ctr.level = 1;
3377 ctr.info.info1 = &info1;
3379 status = rpccli_spoolss_SetJob(cli, mem_ctx,
3380 &handle,
3381 jobid,
3382 &ctr,
3384 &werr);
3385 if (!NT_STATUS_IS_OK(status)) {
3386 errcode = W_ERROR_V(ntstatus_to_werror(status));
3387 goto out;
3389 if (!W_ERROR_IS_OK(werr)) {
3390 errcode = W_ERROR_V(werr);
3391 goto out;
3394 errcode = NERR_Success;
3395 out:
3397 if (is_valid_policy_hnd(&handle)) {
3398 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3401 SSVALS(*rparam,0,errcode);
3402 SSVAL(*rparam,2,0); /* converter word */
3404 return(True);
3408 /****************************************************************************
3409 Get info about the server.
3410 ****************************************************************************/
3412 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3413 char *param, int tpscnt,
3414 char *data, int tdscnt,
3415 int mdrcnt,int mprcnt,
3416 char **rdata,char **rparam,
3417 int *rdata_len,int *rparam_len)
3419 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3420 char *str2 = skip_string(param,tpscnt,str1);
3421 char *p = skip_string(param,tpscnt,str2);
3422 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3423 char *p2;
3424 int struct_len;
3426 if (!str1 || !str2 || !p) {
3427 return False;
3430 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3432 /* check it's a supported varient */
3433 if (!prefix_ok(str1,"WrLh")) {
3434 return False;
3437 switch( uLevel ) {
3438 case 0:
3439 if (strcmp(str2,"B16") != 0) {
3440 return False;
3442 struct_len = 16;
3443 break;
3444 case 1:
3445 if (strcmp(str2,"B16BBDz") != 0) {
3446 return False;
3448 struct_len = 26;
3449 break;
3450 case 2:
3451 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3452 return False;
3454 struct_len = 134;
3455 break;
3456 case 3:
3457 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3458 return False;
3460 struct_len = 144;
3461 break;
3462 case 20:
3463 if (strcmp(str2,"DN") != 0) {
3464 return False;
3466 struct_len = 6;
3467 break;
3468 case 50:
3469 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3470 return False;
3472 struct_len = 42;
3473 break;
3474 default:
3475 return False;
3478 *rdata_len = mdrcnt;
3479 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3480 if (!*rdata) {
3481 return False;
3484 p = *rdata;
3485 p2 = p + struct_len;
3486 if (uLevel != 20) {
3487 srvstr_push(NULL, 0, p,global_myname(),16,
3488 STR_ASCII|STR_UPPER|STR_TERMINATE);
3490 p += 16;
3491 if (uLevel > 0) {
3492 struct srv_info_struct *servers=NULL;
3493 int i,count;
3494 char *comment = NULL;
3495 TALLOC_CTX *ctx = talloc_tos();
3496 uint32 servertype= lp_default_server_announce();
3498 comment = talloc_strdup(ctx,lp_serverstring());
3499 if (!comment) {
3500 return false;
3503 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3504 for (i=0;i<count;i++) {
3505 if (strequal(servers[i].name,global_myname())) {
3506 servertype = servers[i].type;
3507 TALLOC_FREE(comment);
3508 comment = talloc_strdup(ctx,
3509 servers[i].comment);
3510 if (comment) {
3511 return false;
3517 SAFE_FREE(servers);
3519 SCVAL(p,0,lp_major_announce_version());
3520 SCVAL(p,1,lp_minor_announce_version());
3521 SIVAL(p,2,servertype);
3523 if (mdrcnt == struct_len) {
3524 SIVAL(p,6,0);
3525 } else {
3526 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3527 comment = talloc_sub_advanced(
3528 ctx,
3529 lp_servicename(SNUM(conn)),
3530 conn->server_info->unix_name,
3531 conn->connectpath,
3532 conn->server_info->utok.gid,
3533 conn->server_info->sanitized_username,
3534 pdb_get_domain(conn->server_info->sam_account),
3535 comment);
3536 if (comment) {
3537 return false;
3539 if (mdrcnt - struct_len <= 0) {
3540 return false;
3542 push_ascii(p2,
3543 comment,
3544 MIN(mdrcnt - struct_len,
3545 MAX_SERVER_STRING_LENGTH),
3546 STR_TERMINATE);
3547 p2 = skip_string(*rdata,*rdata_len,p2);
3548 if (!p2) {
3549 return False;
3554 if (uLevel > 1) {
3555 return False; /* not yet implemented */
3558 *rdata_len = PTR_DIFF(p2,*rdata);
3560 *rparam_len = 6;
3561 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3562 if (!*rparam) {
3563 return False;
3565 SSVAL(*rparam,0,NERR_Success);
3566 SSVAL(*rparam,2,0); /* converter word */
3567 SSVAL(*rparam,4,*rdata_len);
3569 return True;
3572 /****************************************************************************
3573 Get info about the server.
3574 ****************************************************************************/
3576 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3577 char *param, int tpscnt,
3578 char *data, int tdscnt,
3579 int mdrcnt,int mprcnt,
3580 char **rdata,char **rparam,
3581 int *rdata_len,int *rparam_len)
3583 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3584 char *str2 = skip_string(param,tpscnt,str1);
3585 char *p = skip_string(param,tpscnt,str2);
3586 char *p2;
3587 char *endp;
3588 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3590 if (!str1 || !str2 || !p) {
3591 return False;
3594 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3596 *rparam_len = 6;
3597 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3598 if (!*rparam) {
3599 return False;
3602 /* check it's a supported varient */
3603 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3604 return False;
3607 *rdata_len = mdrcnt + 1024;
3608 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3609 if (!*rdata) {
3610 return False;
3613 SSVAL(*rparam,0,NERR_Success);
3614 SSVAL(*rparam,2,0); /* converter word */
3616 p = *rdata;
3617 endp = *rdata + *rdata_len;
3619 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3620 if (!p2) {
3621 return False;
3624 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3625 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3626 strupper_m(p2);
3627 p2 = skip_string(*rdata,*rdata_len,p2);
3628 if (!p2) {
3629 return False;
3631 p += 4;
3633 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3634 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3635 p2 = skip_string(*rdata,*rdata_len,p2);
3636 if (!p2) {
3637 return False;
3639 p += 4;
3641 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3642 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3643 strupper_m(p2);
3644 p2 = skip_string(*rdata,*rdata_len,p2);
3645 if (!p2) {
3646 return False;
3648 p += 4;
3650 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3651 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3652 p += 2;
3654 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3655 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3656 p2 = skip_string(*rdata,*rdata_len,p2);
3657 if (!p2) {
3658 return False;
3660 p += 4;
3662 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3663 strlcpy(p2,"",PTR_DIFF(endp,p2));
3664 p2 = skip_string(*rdata,*rdata_len,p2);
3665 if (!p2) {
3666 return False;
3668 p += 4;
3670 *rdata_len = PTR_DIFF(p2,*rdata);
3672 SSVAL(*rparam,4,*rdata_len);
3674 return True;
3677 /****************************************************************************
3678 get info about a user
3680 struct user_info_11 {
3681 char usri11_name[21]; 0-20
3682 char usri11_pad; 21
3683 char *usri11_comment; 22-25
3684 char *usri11_usr_comment; 26-29
3685 unsigned short usri11_priv; 30-31
3686 unsigned long usri11_auth_flags; 32-35
3687 long usri11_password_age; 36-39
3688 char *usri11_homedir; 40-43
3689 char *usri11_parms; 44-47
3690 long usri11_last_logon; 48-51
3691 long usri11_last_logoff; 52-55
3692 unsigned short usri11_bad_pw_count; 56-57
3693 unsigned short usri11_num_logons; 58-59
3694 char *usri11_logon_server; 60-63
3695 unsigned short usri11_country_code; 64-65
3696 char *usri11_workstations; 66-69
3697 unsigned long usri11_max_storage; 70-73
3698 unsigned short usri11_units_per_week; 74-75
3699 unsigned char *usri11_logon_hours; 76-79
3700 unsigned short usri11_code_page; 80-81
3703 where:
3705 usri11_name specifies the user name for which information is retrieved
3707 usri11_pad aligns the next data structure element to a word boundary
3709 usri11_comment is a null terminated ASCII comment
3711 usri11_user_comment is a null terminated ASCII comment about the user
3713 usri11_priv specifies the level of the privilege assigned to the user.
3714 The possible values are:
3716 Name Value Description
3717 USER_PRIV_GUEST 0 Guest privilege
3718 USER_PRIV_USER 1 User privilege
3719 USER_PRV_ADMIN 2 Administrator privilege
3721 usri11_auth_flags specifies the account operator privileges. The
3722 possible values are:
3724 Name Value Description
3725 AF_OP_PRINT 0 Print operator
3728 Leach, Naik [Page 28]
3732 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3735 AF_OP_COMM 1 Communications operator
3736 AF_OP_SERVER 2 Server operator
3737 AF_OP_ACCOUNTS 3 Accounts operator
3740 usri11_password_age specifies how many seconds have elapsed since the
3741 password was last changed.
3743 usri11_home_dir points to a null terminated ASCII string that contains
3744 the path name of the user's home directory.
3746 usri11_parms points to a null terminated ASCII string that is set
3747 aside for use by applications.
3749 usri11_last_logon specifies the time when the user last logged on.
3750 This value is stored as the number of seconds elapsed since
3751 00:00:00, January 1, 1970.
3753 usri11_last_logoff specifies the time when the user last logged off.
3754 This value is stored as the number of seconds elapsed since
3755 00:00:00, January 1, 1970. A value of 0 means the last logoff
3756 time is unknown.
3758 usri11_bad_pw_count specifies the number of incorrect passwords
3759 entered since the last successful logon.
3761 usri11_log1_num_logons specifies the number of times this user has
3762 logged on. A value of -1 means the number of logons is unknown.
3764 usri11_logon_server points to a null terminated ASCII string that
3765 contains the name of the server to which logon requests are sent.
3766 A null string indicates logon requests should be sent to the
3767 domain controller.
3769 usri11_country_code specifies the country code for the user's language
3770 of choice.
3772 usri11_workstations points to a null terminated ASCII string that
3773 contains the names of workstations the user may log on from.
3774 There may be up to 8 workstations, with the names separated by
3775 commas. A null strings indicates there are no restrictions.
3777 usri11_max_storage specifies the maximum amount of disk space the user
3778 can occupy. A value of 0xffffffff indicates there are no
3779 restrictions.
3781 usri11_units_per_week specifies the equal number of time units into
3782 which a week is divided. This value must be equal to 168.
3784 usri11_logon_hours points to a 21 byte (168 bits) string that
3785 specifies the time during which the user can log on. Each bit
3786 represents one unique hour in a week. The first bit (bit 0, word
3787 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3791 Leach, Naik [Page 29]
3795 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3798 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3799 are no restrictions.
3801 usri11_code_page specifies the code page for the user's language of
3802 choice
3804 All of the pointers in this data structure need to be treated
3805 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3806 to be ignored. The converter word returned in the parameters section
3807 needs to be subtracted from the lower 16 bits to calculate an offset
3808 into the return buffer where this ASCII string resides.
3810 There is no auxiliary data in the response.
3812 ****************************************************************************/
3814 #define usri11_name 0
3815 #define usri11_pad 21
3816 #define usri11_comment 22
3817 #define usri11_usr_comment 26
3818 #define usri11_full_name 30
3819 #define usri11_priv 34
3820 #define usri11_auth_flags 36
3821 #define usri11_password_age 40
3822 #define usri11_homedir 44
3823 #define usri11_parms 48
3824 #define usri11_last_logon 52
3825 #define usri11_last_logoff 56
3826 #define usri11_bad_pw_count 60
3827 #define usri11_num_logons 62
3828 #define usri11_logon_server 64
3829 #define usri11_country_code 68
3830 #define usri11_workstations 70
3831 #define usri11_max_storage 74
3832 #define usri11_units_per_week 78
3833 #define usri11_logon_hours 80
3834 #define usri11_code_page 84
3835 #define usri11_end 86
3837 #define USER_PRIV_GUEST 0
3838 #define USER_PRIV_USER 1
3839 #define USER_PRIV_ADMIN 2
3841 #define AF_OP_PRINT 0
3842 #define AF_OP_COMM 1
3843 #define AF_OP_SERVER 2
3844 #define AF_OP_ACCOUNTS 3
3847 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3848 char *param, int tpscnt,
3849 char *data, int tdscnt,
3850 int mdrcnt,int mprcnt,
3851 char **rdata,char **rparam,
3852 int *rdata_len,int *rparam_len)
3854 struct smbd_server_connection *sconn = smbd_server_conn;
3855 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3856 char *str2 = skip_string(param,tpscnt,str1);
3857 char *UserName = skip_string(param,tpscnt,str2);
3858 char *p = skip_string(param,tpscnt,UserName);
3859 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3860 char *p2;
3861 char *endp;
3862 const char *level_string;
3864 /* get NIS home of a previously validated user - simeon */
3865 /* With share level security vuid will always be zero.
3866 Don't depend on vuser being non-null !!. JRA */
3867 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3868 if(vuser != NULL) {
3869 DEBUG(3,(" Username of UID %d is %s\n",
3870 (int)vuser->server_info->utok.uid,
3871 vuser->server_info->unix_name));
3874 if (!str1 || !str2 || !UserName || !p) {
3875 return False;
3878 *rparam_len = 6;
3879 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3880 if (!*rparam) {
3881 return False;
3884 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3886 /* check it's a supported variant */
3887 if (strcmp(str1,"zWrLh") != 0) {
3888 return False;
3890 switch( uLevel ) {
3891 case 0: level_string = "B21"; break;
3892 case 1: level_string = "B21BB16DWzzWz"; break;
3893 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3894 case 10: level_string = "B21Bzzz"; break;
3895 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3896 default: return False;
3899 if (strcmp(level_string,str2) != 0) {
3900 return False;
3903 *rdata_len = mdrcnt + 1024;
3904 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3905 if (!*rdata) {
3906 return False;
3909 SSVAL(*rparam,0,NERR_Success);
3910 SSVAL(*rparam,2,0); /* converter word */
3912 p = *rdata;
3913 endp = *rdata + *rdata_len;
3914 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3915 if (!p2) {
3916 return False;
3919 memset(p,0,21);
3920 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3922 if (uLevel > 0) {
3923 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3924 *p2 = 0;
3927 if (uLevel >= 10) {
3928 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3929 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3930 p2 = skip_string(*rdata,*rdata_len,p2);
3931 if (!p2) {
3932 return False;
3935 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3936 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3937 p2 = skip_string(*rdata,*rdata_len,p2);
3938 if (!p2) {
3939 return False;
3942 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3943 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3944 strlcpy(p2,((vuser != NULL)
3945 ? pdb_get_fullname(vuser->server_info->sam_account)
3946 : UserName),PTR_DIFF(endp,p2));
3947 p2 = skip_string(*rdata,*rdata_len,p2);
3948 if (!p2) {
3949 return False;
3953 if (uLevel == 11) {
3954 const char *homedir = "";
3955 if (vuser != NULL) {
3956 homedir = pdb_get_homedir(
3957 vuser->server_info->sam_account);
3959 /* modelled after NTAS 3.51 reply */
3960 SSVAL(p,usri11_priv,
3961 (get_current_uid(conn) == sec_initial_uid())?
3962 USER_PRIV_ADMIN:USER_PRIV_USER);
3963 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3964 SIVALS(p,usri11_password_age,-1); /* password age */
3965 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3966 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3967 p2 = skip_string(*rdata,*rdata_len,p2);
3968 if (!p2) {
3969 return False;
3971 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3972 strlcpy(p2,"",PTR_DIFF(endp,p2));
3973 p2 = skip_string(*rdata,*rdata_len,p2);
3974 if (!p2) {
3975 return False;
3977 SIVAL(p,usri11_last_logon,0); /* last logon */
3978 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3979 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3980 SSVALS(p,usri11_num_logons,-1); /* num logons */
3981 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3982 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3983 p2 = skip_string(*rdata,*rdata_len,p2);
3984 if (!p2) {
3985 return False;
3987 SSVAL(p,usri11_country_code,0); /* country code */
3989 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3990 strlcpy(p2,"",PTR_DIFF(endp,p2));
3991 p2 = skip_string(*rdata,*rdata_len,p2);
3992 if (!p2) {
3993 return False;
3996 SIVALS(p,usri11_max_storage,-1); /* max storage */
3997 SSVAL(p,usri11_units_per_week,168); /* units per week */
3998 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
4000 /* a simple way to get logon hours at all times. */
4001 memset(p2,0xff,21);
4002 SCVAL(p2,21,0); /* fix zero termination */
4003 p2 = skip_string(*rdata,*rdata_len,p2);
4004 if (!p2) {
4005 return False;
4008 SSVAL(p,usri11_code_page,0); /* code page */
4011 if (uLevel == 1 || uLevel == 2) {
4012 memset(p+22,' ',16); /* password */
4013 SIVALS(p,38,-1); /* password age */
4014 SSVAL(p,42,
4015 (get_current_uid(conn) == sec_initial_uid())?
4016 USER_PRIV_ADMIN:USER_PRIV_USER);
4017 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
4018 strlcpy(p2, vuser ? pdb_get_homedir(
4019 vuser->server_info->sam_account) : "",
4020 PTR_DIFF(endp,p2));
4021 p2 = skip_string(*rdata,*rdata_len,p2);
4022 if (!p2) {
4023 return False;
4025 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
4026 *p2++ = 0;
4027 SSVAL(p,52,0); /* flags */
4028 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
4029 strlcpy(p2, vuser ? pdb_get_logon_script(
4030 vuser->server_info->sam_account) : "",
4031 PTR_DIFF(endp,p2));
4032 p2 = skip_string(*rdata,*rdata_len,p2);
4033 if (!p2) {
4034 return False;
4036 if (uLevel == 2) {
4037 SIVAL(p,60,0); /* auth_flags */
4038 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
4039 strlcpy(p2,((vuser != NULL)
4040 ? pdb_get_fullname(vuser->server_info->sam_account)
4041 : UserName),PTR_DIFF(endp,p2));
4042 p2 = skip_string(*rdata,*rdata_len,p2);
4043 if (!p2) {
4044 return False;
4046 SIVAL(p,68,0); /* urs_comment */
4047 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
4048 strlcpy(p2,"",PTR_DIFF(endp,p2));
4049 p2 = skip_string(*rdata,*rdata_len,p2);
4050 if (!p2) {
4051 return False;
4053 SIVAL(p,76,0); /* workstations */
4054 SIVAL(p,80,0); /* last_logon */
4055 SIVAL(p,84,0); /* last_logoff */
4056 SIVALS(p,88,-1); /* acct_expires */
4057 SIVALS(p,92,-1); /* max_storage */
4058 SSVAL(p,96,168); /* units_per_week */
4059 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
4060 memset(p2,-1,21);
4061 p2 += 21;
4062 SSVALS(p,102,-1); /* bad_pw_count */
4063 SSVALS(p,104,-1); /* num_logons */
4064 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
4066 TALLOC_CTX *ctx = talloc_tos();
4067 int space_rem = *rdata_len - (p2 - *rdata);
4068 char *tmp;
4070 if (space_rem <= 0) {
4071 return false;
4073 tmp = talloc_strdup(ctx, "\\\\%L");
4074 if (!tmp) {
4075 return false;
4077 tmp = talloc_sub_basic(ctx,
4080 tmp);
4081 if (!tmp) {
4082 return false;
4085 push_ascii(p2,
4086 tmp,
4087 space_rem,
4088 STR_TERMINATE);
4090 p2 = skip_string(*rdata,*rdata_len,p2);
4091 if (!p2) {
4092 return False;
4094 SSVAL(p,110,49); /* country_code */
4095 SSVAL(p,112,860); /* code page */
4099 *rdata_len = PTR_DIFF(p2,*rdata);
4101 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
4103 return(True);
4106 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
4107 char *param, int tpscnt,
4108 char *data, int tdscnt,
4109 int mdrcnt,int mprcnt,
4110 char **rdata,char **rparam,
4111 int *rdata_len,int *rparam_len)
4113 struct smbd_server_connection *sconn = smbd_server_conn;
4114 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4115 char *str2 = skip_string(param,tpscnt,str1);
4116 char *p = skip_string(param,tpscnt,str2);
4117 int uLevel;
4118 struct pack_desc desc;
4119 char* name;
4120 /* With share level security vuid will always be zero.
4121 Don't depend on vuser being non-null !!. JRA */
4122 user_struct *vuser = get_valid_user_struct(sconn, vuid);
4124 if (!str1 || !str2 || !p) {
4125 return False;
4128 if(vuser != NULL) {
4129 DEBUG(3,(" Username of UID %d is %s\n",
4130 (int)vuser->server_info->utok.uid,
4131 vuser->server_info->unix_name));
4134 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4135 name = get_safe_str_ptr(param,tpscnt,p,2);
4136 if (!name) {
4137 return False;
4140 memset((char *)&desc,'\0',sizeof(desc));
4142 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
4144 /* check it's a supported varient */
4145 if (strcmp(str1,"OOWb54WrLh") != 0) {
4146 return False;
4148 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
4149 return False;
4151 if (mdrcnt > 0) {
4152 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4153 if (!*rdata) {
4154 return False;
4158 desc.base = *rdata;
4159 desc.buflen = mdrcnt;
4160 desc.subformat = NULL;
4161 desc.format = str2;
4163 if (init_package(&desc,1,0)) {
4164 PACKI(&desc,"W",0); /* code */
4165 PACKS(&desc,"B21",name); /* eff. name */
4166 PACKS(&desc,"B",""); /* pad */
4167 PACKI(&desc,"W",
4168 (get_current_uid(conn) == sec_initial_uid())?
4169 USER_PRIV_ADMIN:USER_PRIV_USER);
4170 PACKI(&desc,"D",0); /* auth flags XXX */
4171 PACKI(&desc,"W",0); /* num logons */
4172 PACKI(&desc,"W",0); /* bad pw count */
4173 PACKI(&desc,"D",0); /* last logon */
4174 PACKI(&desc,"D",-1); /* last logoff */
4175 PACKI(&desc,"D",-1); /* logoff time */
4176 PACKI(&desc,"D",-1); /* kickoff time */
4177 PACKI(&desc,"D",0); /* password age */
4178 PACKI(&desc,"D",0); /* password can change */
4179 PACKI(&desc,"D",-1); /* password must change */
4182 fstring mypath;
4183 fstrcpy(mypath,"\\\\");
4184 fstrcat(mypath,get_local_machine_name());
4185 strupper_m(mypath);
4186 PACKS(&desc,"z",mypath); /* computer */
4189 PACKS(&desc,"z",lp_workgroup());/* domain */
4190 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4191 vuser->server_info->sam_account) : ""); /* script path */
4192 PACKI(&desc,"D",0x00000000); /* reserved */
4195 *rdata_len = desc.usedlen;
4196 *rparam_len = 6;
4197 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4198 if (!*rparam) {
4199 return False;
4201 SSVALS(*rparam,0,desc.errcode);
4202 SSVAL(*rparam,2,0);
4203 SSVAL(*rparam,4,desc.neededlen);
4205 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4207 return True;
4210 /****************************************************************************
4211 api_WAccessGetUserPerms
4212 ****************************************************************************/
4214 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4215 char *param, int tpscnt,
4216 char *data, int tdscnt,
4217 int mdrcnt,int mprcnt,
4218 char **rdata,char **rparam,
4219 int *rdata_len,int *rparam_len)
4221 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4222 char *str2 = skip_string(param,tpscnt,str1);
4223 char *user = skip_string(param,tpscnt,str2);
4224 char *resource = skip_string(param,tpscnt,user);
4226 if (!str1 || !str2 || !user || !resource) {
4227 return False;
4230 if (skip_string(param,tpscnt,resource) == NULL) {
4231 return False;
4233 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4235 /* check it's a supported varient */
4236 if (strcmp(str1,"zzh") != 0) {
4237 return False;
4239 if (strcmp(str2,"") != 0) {
4240 return False;
4243 *rparam_len = 6;
4244 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4245 if (!*rparam) {
4246 return False;
4248 SSVALS(*rparam,0,0); /* errorcode */
4249 SSVAL(*rparam,2,0); /* converter word */
4250 SSVAL(*rparam,4,0x7f); /* permission flags */
4252 return True;
4255 /****************************************************************************
4256 api_WPrintJobEnumerate
4257 ****************************************************************************/
4259 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4260 char *param, int tpscnt,
4261 char *data, int tdscnt,
4262 int mdrcnt,int mprcnt,
4263 char **rdata,char **rparam,
4264 int *rdata_len,int *rparam_len)
4266 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4267 char *str2 = skip_string(param,tpscnt,str1);
4268 char *p = skip_string(param,tpscnt,str2);
4269 int uLevel;
4270 fstring sharename;
4271 uint32 jobid;
4272 struct pack_desc desc;
4273 char *tmpdata=NULL;
4275 TALLOC_CTX *mem_ctx = talloc_tos();
4276 WERROR werr;
4277 NTSTATUS status;
4278 struct rpc_pipe_client *cli = NULL;
4279 struct policy_handle handle;
4280 struct spoolss_DevmodeContainer devmode_ctr;
4281 union spoolss_JobInfo info;
4283 if (!str1 || !str2 || !p) {
4284 return False;
4287 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4289 memset((char *)&desc,'\0',sizeof(desc));
4290 memset((char *)&status,'\0',sizeof(status));
4292 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4294 /* check it's a supported varient */
4295 if (strcmp(str1,"WWrLh") != 0) {
4296 return False;
4298 if (!check_printjob_info(&desc,uLevel,str2)) {
4299 return False;
4302 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4303 return False;
4306 ZERO_STRUCT(handle);
4308 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4309 rpc_spoolss_dispatch, conn->server_info,
4310 &cli);
4311 if (!NT_STATUS_IS_OK(status)) {
4312 DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n",
4313 nt_errstr(status)));
4314 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4315 goto out;
4318 ZERO_STRUCT(devmode_ctr);
4320 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4321 sharename,
4322 NULL,
4323 devmode_ctr,
4324 SEC_FLAG_MAXIMUM_ALLOWED,
4325 &handle,
4326 &werr);
4327 if (!NT_STATUS_IS_OK(status)) {
4328 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4329 goto out;
4331 if (!W_ERROR_IS_OK(werr)) {
4332 desc.errcode = W_ERROR_V(werr);
4333 goto out;
4336 werr = rpccli_spoolss_getjob(cli, mem_ctx,
4337 &handle,
4338 jobid,
4339 2, /* level */
4340 0, /* offered */
4341 &info);
4342 if (!W_ERROR_IS_OK(werr)) {
4343 desc.errcode = W_ERROR_V(werr);
4344 goto out;
4347 if (mdrcnt > 0) {
4348 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4349 if (!*rdata) {
4350 return False;
4352 desc.base = *rdata;
4353 desc.buflen = mdrcnt;
4354 } else {
4356 * Don't return data but need to get correct length
4357 * init_package will return wrong size if buflen=0
4359 desc.buflen = getlen(desc.format);
4360 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4363 if (init_package(&desc,1,0)) {
4364 fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position);
4365 *rdata_len = desc.usedlen;
4366 } else {
4367 desc.errcode = NERR_JobNotFound;
4368 *rdata_len = 0;
4370 out:
4371 if (is_valid_policy_hnd(&handle)) {
4372 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4375 *rparam_len = 6;
4376 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4377 if (!*rparam) {
4378 return False;
4380 SSVALS(*rparam,0,desc.errcode);
4381 SSVAL(*rparam,2,0);
4382 SSVAL(*rparam,4,desc.neededlen);
4384 SAFE_FREE(tmpdata);
4386 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4388 return True;
4391 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4392 char *param, int tpscnt,
4393 char *data, int tdscnt,
4394 int mdrcnt,int mprcnt,
4395 char **rdata,char **rparam,
4396 int *rdata_len,int *rparam_len)
4398 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4399 char *str2 = skip_string(param,tpscnt,str1);
4400 char *p = skip_string(param,tpscnt,str2);
4401 char *name = p;
4402 int uLevel;
4403 int i, succnt=0;
4404 struct pack_desc desc;
4406 TALLOC_CTX *mem_ctx = talloc_tos();
4407 WERROR werr;
4408 NTSTATUS status;
4409 struct rpc_pipe_client *cli = NULL;
4410 struct policy_handle handle;
4411 struct spoolss_DevmodeContainer devmode_ctr;
4412 uint32_t count;
4413 union spoolss_JobInfo *info;
4415 if (!str1 || !str2 || !p) {
4416 return False;
4419 memset((char *)&desc,'\0',sizeof(desc));
4421 p = skip_string(param,tpscnt,p);
4422 if (!p) {
4423 return False;
4425 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4427 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4429 /* check it's a supported variant */
4430 if (strcmp(str1,"zWrLeh") != 0) {
4431 return False;
4434 if (uLevel > 2) {
4435 return False; /* defined only for uLevel 0,1,2 */
4438 if (!check_printjob_info(&desc,uLevel,str2)) {
4439 return False;
4442 ZERO_STRUCT(handle);
4444 status = rpc_pipe_open_internal(mem_ctx, &ndr_table_spoolss.syntax_id,
4445 rpc_spoolss_dispatch, conn->server_info,
4446 &cli);
4447 if (!NT_STATUS_IS_OK(status)) {
4448 DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n",
4449 nt_errstr(status)));
4450 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4451 goto out;
4454 ZERO_STRUCT(devmode_ctr);
4456 status = rpccli_spoolss_OpenPrinter(cli, mem_ctx,
4457 name,
4458 NULL,
4459 devmode_ctr,
4460 SEC_FLAG_MAXIMUM_ALLOWED,
4461 &handle,
4462 &werr);
4463 if (!NT_STATUS_IS_OK(status)) {
4464 desc.errcode = W_ERROR_V(ntstatus_to_werror(status));
4465 goto out;
4467 if (!W_ERROR_IS_OK(werr)) {
4468 desc.errcode = W_ERROR_V(werr);
4469 goto out;
4472 werr = rpccli_spoolss_enumjobs(cli, mem_ctx,
4473 &handle,
4474 0, /* firstjob */
4475 0xff, /* numjobs */
4476 2, /* level */
4477 0, /* offered */
4478 &count,
4479 &info);
4480 if (!W_ERROR_IS_OK(werr)) {
4481 desc.errcode = W_ERROR_V(werr);
4482 goto out;
4485 if (mdrcnt > 0) {
4486 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4487 if (!*rdata) {
4488 return False;
4491 desc.base = *rdata;
4492 desc.buflen = mdrcnt;
4494 if (init_package(&desc,count,0)) {
4495 succnt = 0;
4496 for (i = 0; i < count; i++) {
4497 fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i);
4498 if (desc.errcode == NERR_Success) {
4499 succnt = i+1;
4503 out:
4504 if (is_valid_policy_hnd(&handle)) {
4505 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
4508 *rdata_len = desc.usedlen;
4510 *rparam_len = 8;
4511 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4512 if (!*rparam) {
4513 return False;
4515 SSVALS(*rparam,0,desc.errcode);
4516 SSVAL(*rparam,2,0);
4517 SSVAL(*rparam,4,succnt);
4518 SSVAL(*rparam,6,count);
4520 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4522 return True;
4525 static int check_printdest_info(struct pack_desc* desc,
4526 int uLevel, char* id)
4528 desc->subformat = NULL;
4529 switch( uLevel ) {
4530 case 0:
4531 desc->format = "B9";
4532 break;
4533 case 1:
4534 desc->format = "B9B21WWzW";
4535 break;
4536 case 2:
4537 desc->format = "z";
4538 break;
4539 case 3:
4540 desc->format = "zzzWWzzzWW";
4541 break;
4542 default:
4543 DEBUG(0,("check_printdest_info: invalid level %d\n",
4544 uLevel));
4545 return False;
4547 if (id == NULL || strcmp(desc->format,id) != 0) {
4548 DEBUG(0,("check_printdest_info: invalid string %s\n",
4549 id ? id : "<NULL>" ));
4550 return False;
4552 return True;
4555 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4556 struct pack_desc* desc)
4558 char buf[100];
4560 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4561 buf[sizeof(buf)-1] = 0;
4562 strupper_m(buf);
4564 if (uLevel <= 1) {
4565 PACKS(desc,"B9",buf); /* szName */
4566 if (uLevel == 1) {
4567 PACKS(desc,"B21",""); /* szUserName */
4568 PACKI(desc,"W",0); /* uJobId */
4569 PACKI(desc,"W",0); /* fsStatus */
4570 PACKS(desc,"z",""); /* pszStatus */
4571 PACKI(desc,"W",0); /* time */
4575 if (uLevel == 2 || uLevel == 3) {
4576 PACKS(desc,"z",buf); /* pszPrinterName */
4577 if (uLevel == 3) {
4578 PACKS(desc,"z",""); /* pszUserName */
4579 PACKS(desc,"z",""); /* pszLogAddr */
4580 PACKI(desc,"W",0); /* uJobId */
4581 PACKI(desc,"W",0); /* fsStatus */
4582 PACKS(desc,"z",""); /* pszStatus */
4583 PACKS(desc,"z",""); /* pszComment */
4584 PACKS(desc,"z","NULL"); /* pszDrivers */
4585 PACKI(desc,"W",0); /* time */
4586 PACKI(desc,"W",0); /* pad1 */
4591 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4592 char *param, int tpscnt,
4593 char *data, int tdscnt,
4594 int mdrcnt,int mprcnt,
4595 char **rdata,char **rparam,
4596 int *rdata_len,int *rparam_len)
4598 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4599 char *str2 = skip_string(param,tpscnt,str1);
4600 char *p = skip_string(param,tpscnt,str2);
4601 char* PrinterName = p;
4602 int uLevel;
4603 struct pack_desc desc;
4604 int snum;
4605 char *tmpdata=NULL;
4607 if (!str1 || !str2 || !p) {
4608 return False;
4611 memset((char *)&desc,'\0',sizeof(desc));
4613 p = skip_string(param,tpscnt,p);
4614 if (!p) {
4615 return False;
4617 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4619 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4621 /* check it's a supported varient */
4622 if (strcmp(str1,"zWrLh") != 0) {
4623 return False;
4625 if (!check_printdest_info(&desc,uLevel,str2)) {
4626 return False;
4629 snum = find_service(PrinterName);
4630 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4631 *rdata_len = 0;
4632 desc.errcode = NERR_DestNotFound;
4633 desc.neededlen = 0;
4634 } else {
4635 if (mdrcnt > 0) {
4636 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4637 if (!*rdata) {
4638 return False;
4640 desc.base = *rdata;
4641 desc.buflen = mdrcnt;
4642 } else {
4644 * Don't return data but need to get correct length
4645 * init_package will return wrong size if buflen=0
4647 desc.buflen = getlen(desc.format);
4648 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4650 if (init_package(&desc,1,0)) {
4651 fill_printdest_info(conn,snum,uLevel,&desc);
4653 *rdata_len = desc.usedlen;
4656 *rparam_len = 6;
4657 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4658 if (!*rparam) {
4659 return False;
4661 SSVALS(*rparam,0,desc.errcode);
4662 SSVAL(*rparam,2,0);
4663 SSVAL(*rparam,4,desc.neededlen);
4665 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4666 SAFE_FREE(tmpdata);
4668 return True;
4671 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4672 char *param, int tpscnt,
4673 char *data, int tdscnt,
4674 int mdrcnt,int mprcnt,
4675 char **rdata,char **rparam,
4676 int *rdata_len,int *rparam_len)
4678 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4679 char *str2 = skip_string(param,tpscnt,str1);
4680 char *p = skip_string(param,tpscnt,str2);
4681 int uLevel;
4682 int queuecnt;
4683 int i, n, succnt=0;
4684 struct pack_desc desc;
4685 int services = lp_numservices();
4687 if (!str1 || !str2 || !p) {
4688 return False;
4691 memset((char *)&desc,'\0',sizeof(desc));
4693 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4695 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4697 /* check it's a supported varient */
4698 if (strcmp(str1,"WrLeh") != 0) {
4699 return False;
4701 if (!check_printdest_info(&desc,uLevel,str2)) {
4702 return False;
4705 queuecnt = 0;
4706 for (i = 0; i < services; i++) {
4707 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4708 queuecnt++;
4712 if (mdrcnt > 0) {
4713 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4714 if (!*rdata) {
4715 return False;
4719 desc.base = *rdata;
4720 desc.buflen = mdrcnt;
4721 if (init_package(&desc,queuecnt,0)) {
4722 succnt = 0;
4723 n = 0;
4724 for (i = 0; i < services; i++) {
4725 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4726 fill_printdest_info(conn,i,uLevel,&desc);
4727 n++;
4728 if (desc.errcode == NERR_Success) {
4729 succnt = n;
4735 *rdata_len = desc.usedlen;
4737 *rparam_len = 8;
4738 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4739 if (!*rparam) {
4740 return False;
4742 SSVALS(*rparam,0,desc.errcode);
4743 SSVAL(*rparam,2,0);
4744 SSVAL(*rparam,4,succnt);
4745 SSVAL(*rparam,6,queuecnt);
4747 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4749 return True;
4752 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4753 char *param, int tpscnt,
4754 char *data, int tdscnt,
4755 int mdrcnt,int mprcnt,
4756 char **rdata,char **rparam,
4757 int *rdata_len,int *rparam_len)
4759 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4760 char *str2 = skip_string(param,tpscnt,str1);
4761 char *p = skip_string(param,tpscnt,str2);
4762 int uLevel;
4763 int succnt;
4764 struct pack_desc desc;
4766 if (!str1 || !str2 || !p) {
4767 return False;
4770 memset((char *)&desc,'\0',sizeof(desc));
4772 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4774 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4776 /* check it's a supported varient */
4777 if (strcmp(str1,"WrLeh") != 0) {
4778 return False;
4780 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4781 return False;
4784 if (mdrcnt > 0) {
4785 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4786 if (!*rdata) {
4787 return False;
4790 desc.base = *rdata;
4791 desc.buflen = mdrcnt;
4792 if (init_package(&desc,1,0)) {
4793 PACKS(&desc,"B41","NULL");
4796 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4798 *rdata_len = desc.usedlen;
4800 *rparam_len = 8;
4801 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4802 if (!*rparam) {
4803 return False;
4805 SSVALS(*rparam,0,desc.errcode);
4806 SSVAL(*rparam,2,0);
4807 SSVAL(*rparam,4,succnt);
4808 SSVAL(*rparam,6,1);
4810 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4812 return True;
4815 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4816 char *param, int tpscnt,
4817 char *data, int tdscnt,
4818 int mdrcnt,int mprcnt,
4819 char **rdata,char **rparam,
4820 int *rdata_len,int *rparam_len)
4822 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4823 char *str2 = skip_string(param,tpscnt,str1);
4824 char *p = skip_string(param,tpscnt,str2);
4825 int uLevel;
4826 int succnt;
4827 struct pack_desc desc;
4829 if (!str1 || !str2 || !p) {
4830 return False;
4832 memset((char *)&desc,'\0',sizeof(desc));
4834 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4836 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4838 /* check it's a supported varient */
4839 if (strcmp(str1,"WrLeh") != 0) {
4840 return False;
4842 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4843 return False;
4846 if (mdrcnt > 0) {
4847 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4848 if (!*rdata) {
4849 return False;
4852 desc.base = *rdata;
4853 desc.buflen = mdrcnt;
4854 desc.format = str2;
4855 if (init_package(&desc,1,0)) {
4856 PACKS(&desc,"B13","lpd");
4859 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4861 *rdata_len = desc.usedlen;
4863 *rparam_len = 8;
4864 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4865 if (!*rparam) {
4866 return False;
4868 SSVALS(*rparam,0,desc.errcode);
4869 SSVAL(*rparam,2,0);
4870 SSVAL(*rparam,4,succnt);
4871 SSVAL(*rparam,6,1);
4873 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4875 return True;
4878 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4879 char *param, int tpscnt,
4880 char *data, int tdscnt,
4881 int mdrcnt,int mprcnt,
4882 char **rdata,char **rparam,
4883 int *rdata_len,int *rparam_len)
4885 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4886 char *str2 = skip_string(param,tpscnt,str1);
4887 char *p = skip_string(param,tpscnt,str2);
4888 int uLevel;
4889 int succnt;
4890 struct pack_desc desc;
4892 if (!str1 || !str2 || !p) {
4893 return False;
4896 memset((char *)&desc,'\0',sizeof(desc));
4898 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4900 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4902 /* check it's a supported varient */
4903 if (strcmp(str1,"WrLeh") != 0) {
4904 return False;
4906 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4907 return False;
4910 if (mdrcnt > 0) {
4911 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4912 if (!*rdata) {
4913 return False;
4916 memset((char *)&desc,'\0',sizeof(desc));
4917 desc.base = *rdata;
4918 desc.buflen = mdrcnt;
4919 desc.format = str2;
4920 if (init_package(&desc,1,0)) {
4921 PACKS(&desc,"B13","lp0");
4924 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4926 *rdata_len = desc.usedlen;
4928 *rparam_len = 8;
4929 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4930 if (!*rparam) {
4931 return False;
4933 SSVALS(*rparam,0,desc.errcode);
4934 SSVAL(*rparam,2,0);
4935 SSVAL(*rparam,4,succnt);
4936 SSVAL(*rparam,6,1);
4938 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4940 return True;
4943 /****************************************************************************
4944 List open sessions
4945 ****************************************************************************/
4947 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4948 char *param, int tpscnt,
4949 char *data, int tdscnt,
4950 int mdrcnt,int mprcnt,
4951 char **rdata,char **rparam,
4952 int *rdata_len,int *rparam_len)
4955 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4956 char *str2 = skip_string(param,tpscnt,str1);
4957 char *p = skip_string(param,tpscnt,str2);
4958 int uLevel;
4959 struct pack_desc desc;
4960 struct sessionid *session_list;
4961 int i, num_sessions;
4963 if (!str1 || !str2 || !p) {
4964 return False;
4967 memset((char *)&desc,'\0',sizeof(desc));
4969 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4971 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4972 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4973 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4975 /* check it's a supported varient */
4976 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4977 return False;
4979 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4980 return False;
4983 num_sessions = list_sessions(talloc_tos(), &session_list);
4985 if (mdrcnt > 0) {
4986 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4987 if (!*rdata) {
4988 return False;
4991 memset((char *)&desc,'\0',sizeof(desc));
4992 desc.base = *rdata;
4993 desc.buflen = mdrcnt;
4994 desc.format = str2;
4995 if (!init_package(&desc,num_sessions,0)) {
4996 return False;
4999 for(i=0; i<num_sessions; i++) {
5000 PACKS(&desc, "z", session_list[i].remote_machine);
5001 PACKS(&desc, "z", session_list[i].username);
5002 PACKI(&desc, "W", 1); /* num conns */
5003 PACKI(&desc, "W", 0); /* num opens */
5004 PACKI(&desc, "W", 1); /* num users */
5005 PACKI(&desc, "D", 0); /* session time */
5006 PACKI(&desc, "D", 0); /* idle time */
5007 PACKI(&desc, "D", 0); /* flags */
5008 PACKS(&desc, "z", "Unknown Client"); /* client type string */
5011 *rdata_len = desc.usedlen;
5013 *rparam_len = 8;
5014 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5015 if (!*rparam) {
5016 return False;
5018 SSVALS(*rparam,0,desc.errcode);
5019 SSVAL(*rparam,2,0); /* converter */
5020 SSVAL(*rparam,4,num_sessions); /* count */
5022 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
5024 return True;
5028 /****************************************************************************
5029 The buffer was too small.
5030 ****************************************************************************/
5032 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
5033 int mdrcnt, int mprcnt,
5034 char **rdata, char **rparam,
5035 int *rdata_len, int *rparam_len)
5037 *rparam_len = MIN(*rparam_len,mprcnt);
5038 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5039 if (!*rparam) {
5040 return False;
5043 *rdata_len = 0;
5045 SSVAL(*rparam,0,NERR_BufTooSmall);
5047 DEBUG(3,("Supplied buffer too small in API command\n"));
5049 return True;
5052 /****************************************************************************
5053 The request is not supported.
5054 ****************************************************************************/
5056 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
5057 char *param, int tpscnt,
5058 char *data, int tdscnt,
5059 int mdrcnt, int mprcnt,
5060 char **rdata, char **rparam,
5061 int *rdata_len, int *rparam_len)
5063 *rparam_len = 4;
5064 *rparam = smb_realloc_limit(*rparam,*rparam_len);
5065 if (!*rparam) {
5066 return False;
5069 *rdata_len = 0;
5071 SSVAL(*rparam,0,NERR_notsupported);
5072 SSVAL(*rparam,2,0); /* converter word */
5074 DEBUG(3,("Unsupported API command\n"));
5076 return True;
5079 static const struct {
5080 const char *name;
5081 int id;
5082 bool (*fn)(connection_struct *, uint16,
5083 char *, int,
5084 char *, int,
5085 int,int,char **,char **,int *,int *);
5086 bool auth_user; /* Deny anonymous access? */
5087 } api_commands[] = {
5088 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
5089 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
5090 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
5091 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
5092 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
5093 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
5094 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
5095 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
5096 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
5097 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
5098 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
5099 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
5100 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
5101 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
5102 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
5103 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
5104 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
5105 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
5106 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
5107 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
5108 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
5109 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
5110 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
5111 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
5112 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
5113 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
5114 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
5115 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
5116 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
5117 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
5118 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
5119 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
5120 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
5121 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
5122 {NULL, -1, api_Unsupported}
5123 /* The following RAP calls are not implemented by Samba:
5125 RAP_WFileEnum2 - anon not OK
5130 /****************************************************************************
5131 Handle remote api calls.
5132 ****************************************************************************/
5134 void api_reply(connection_struct *conn, uint16 vuid,
5135 struct smb_request *req,
5136 char *data, char *params,
5137 int tdscnt, int tpscnt,
5138 int mdrcnt, int mprcnt)
5140 struct smbd_server_connection *sconn = smbd_server_conn;
5141 int api_command;
5142 char *rdata = NULL;
5143 char *rparam = NULL;
5144 const char *name1 = NULL;
5145 const char *name2 = NULL;
5146 int rdata_len = 0;
5147 int rparam_len = 0;
5148 bool reply=False;
5149 int i;
5151 if (!params) {
5152 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
5153 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5154 return;
5157 if (tpscnt < 2) {
5158 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5159 return;
5161 api_command = SVAL(params,0);
5162 /* Is there a string at position params+2 ? */
5163 if (skip_string(params,tpscnt,params+2)) {
5164 name1 = params + 2;
5165 } else {
5166 name1 = "";
5168 name2 = skip_string(params,tpscnt,params+2);
5169 if (!name2) {
5170 name2 = "";
5173 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
5174 api_command,
5175 name1,
5176 name2,
5177 tdscnt,tpscnt,mdrcnt,mprcnt));
5179 for (i=0;api_commands[i].name;i++) {
5180 if (api_commands[i].id == api_command && api_commands[i].fn) {
5181 DEBUG(3,("Doing %s\n",api_commands[i].name));
5182 break;
5186 /* Check whether this api call can be done anonymously */
5188 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
5189 user_struct *user = get_valid_user_struct(sconn, vuid);
5191 if (!user || user->server_info->guest) {
5192 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
5193 return;
5197 rdata = (char *)SMB_MALLOC(1024);
5198 if (rdata) {
5199 memset(rdata,'\0',1024);
5202 rparam = (char *)SMB_MALLOC(1024);
5203 if (rparam) {
5204 memset(rparam,'\0',1024);
5207 if(!rdata || !rparam) {
5208 DEBUG(0,("api_reply: malloc fail !\n"));
5209 SAFE_FREE(rdata);
5210 SAFE_FREE(rparam);
5211 reply_nterror(req, NT_STATUS_NO_MEMORY);
5212 return;
5215 reply = api_commands[i].fn(conn,
5216 vuid,
5217 params,tpscnt, /* params + length */
5218 data,tdscnt, /* data + length */
5219 mdrcnt,mprcnt,
5220 &rdata,&rparam,&rdata_len,&rparam_len);
5223 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
5224 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
5225 &rdata,&rparam,&rdata_len,&rparam_len);
5228 /* if we get False back then it's actually unsupported */
5229 if (!reply) {
5230 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
5231 &rdata,&rparam,&rdata_len,&rparam_len);
5234 /* If api_Unsupported returns false we can't return anything. */
5235 if (reply) {
5236 send_trans_reply(conn, req, rparam, rparam_len,
5237 rdata, rdata_len, False);
5240 SAFE_FREE(rdata);
5241 SAFE_FREE(rparam);
5242 return;