s3:smbd: Fix really ugly bool vs. int bug!!!
[Samba/gbeck.git] / source3 / smbd / lanman.c
blobc34b8672a53b1eac4ea2a2ac8eb2a27833c19fd0
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/srv_samr.h"
32 #include "../lib/util/binsearch.h"
34 #ifdef CHECK_TYPES
35 #undef CHECK_TYPES
36 #endif
37 #define CHECK_TYPES 0
39 #define NERR_Success 0
40 #define NERR_badpass 86
41 #define NERR_notsupported 50
43 #define NERR_BASE (2100)
44 #define NERR_BufTooSmall (NERR_BASE+23)
45 #define NERR_JobNotFound (NERR_BASE+51)
46 #define NERR_DestNotFound (NERR_BASE+52)
48 #define ACCESS_READ 0x01
49 #define ACCESS_WRITE 0x02
50 #define ACCESS_CREATE 0x04
52 #define SHPWLEN 8 /* share password length */
54 /* Limit size of ipc replies */
56 static char *smb_realloc_limit(void *ptr, size_t size)
58 char *val;
60 size = MAX((size),4*1024);
61 val = (char *)SMB_REALLOC(ptr,size);
62 if (val) {
63 memset(val,'\0',size);
65 return val;
68 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
69 char *param, int tpscnt,
70 char *data, int tdscnt,
71 int mdrcnt, int mprcnt,
72 char **rdata, char **rparam,
73 int *rdata_len, int *rparam_len);
75 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
76 int mdrcnt, int mprcnt,
77 char **rdata, char **rparam,
78 int *rdata_len, int *rparam_len);
81 static int CopyExpanded(connection_struct *conn,
82 int snum, char **dst, char *src, int *p_space_remaining)
84 TALLOC_CTX *ctx = talloc_tos();
85 char *buf = NULL;
86 int l;
88 if (!src || !dst || !p_space_remaining || !(*dst) ||
89 *p_space_remaining <= 0) {
90 return 0;
93 buf = talloc_strdup(ctx, src);
94 if (!buf) {
95 *p_space_remaining = 0;
96 return 0;
98 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
99 if (!buf) {
100 *p_space_remaining = 0;
101 return 0;
103 buf = talloc_sub_advanced(ctx,
104 lp_servicename(SNUM(conn)),
105 conn->server_info->unix_name,
106 conn->connectpath,
107 conn->server_info->utok.gid,
108 conn->server_info->sanitized_username,
109 pdb_get_domain(conn->server_info->sam_account),
110 buf);
111 if (!buf) {
112 *p_space_remaining = 0;
113 return 0;
115 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
116 if (l == -1) {
117 return 0;
119 (*dst) += l;
120 (*p_space_remaining) -= l;
121 return l;
124 static int CopyAndAdvance(char **dst, char *src, int *n)
126 int l;
127 if (!src || !dst || !n || !(*dst)) {
128 return 0;
130 l = push_ascii(*dst,src,*n, STR_TERMINATE);
131 if (l == -1) {
132 return 0;
134 (*dst) += l;
135 (*n) -= l;
136 return l;
139 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
141 TALLOC_CTX *ctx = talloc_tos();
142 char *buf = NULL;
143 if (!s) {
144 return 0;
146 buf = talloc_strdup(ctx,s);
147 if (!buf) {
148 return 0;
150 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
151 if (!buf) {
152 return 0;
154 buf = talloc_sub_advanced(ctx,
155 lp_servicename(SNUM(conn)),
156 conn->server_info->unix_name,
157 conn->connectpath,
158 conn->server_info->utok.gid,
159 conn->server_info->sanitized_username,
160 pdb_get_domain(conn->server_info->sam_account),
161 buf);
162 if (!buf) {
163 return 0;
165 return strlen(buf) + 1;
168 static char *Expand(connection_struct *conn, int snum, char *s)
170 TALLOC_CTX *ctx = talloc_tos();
171 char *buf = NULL;
173 if (!s) {
174 return NULL;
176 buf = talloc_strdup(ctx,s);
177 if (!buf) {
178 return 0;
180 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
181 if (!buf) {
182 return 0;
184 return talloc_sub_advanced(ctx,
185 lp_servicename(SNUM(conn)),
186 conn->server_info->unix_name,
187 conn->connectpath,
188 conn->server_info->utok.gid,
189 conn->server_info->sanitized_username,
190 pdb_get_domain(conn->server_info->sam_account),
191 buf);
194 /*******************************************************************
195 Check a API string for validity when we only need to check the prefix.
196 ******************************************************************/
198 static bool prefix_ok(const char *str, const char *prefix)
200 return(strncmp(str,prefix,strlen(prefix)) == 0);
203 struct pack_desc {
204 const char *format; /* formatstring for structure */
205 const char *subformat; /* subformat for structure */
206 char *base; /* baseaddress of buffer */
207 int buflen; /* remaining size for fixed part; on init: length of base */
208 int subcount; /* count of substructures */
209 char *structbuf; /* pointer into buffer for remaining fixed part */
210 int stringlen; /* remaining size for variable part */
211 char *stringbuf; /* pointer into buffer for remaining variable part */
212 int neededlen; /* total needed size */
213 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
214 const char *curpos; /* current position; pointer into format or subformat */
215 int errcode;
218 static int get_counter(const char **p)
220 int i, n;
221 if (!p || !(*p)) {
222 return 1;
224 if (!isdigit((int)**p)) {
225 return 1;
227 for (n = 0;;) {
228 i = **p;
229 if (isdigit(i)) {
230 n = 10 * n + (i - '0');
231 } else {
232 return n;
234 (*p)++;
238 static int getlen(const char *p)
240 int n = 0;
241 if (!p) {
242 return 0;
245 while (*p) {
246 switch( *p++ ) {
247 case 'W': /* word (2 byte) */
248 n += 2;
249 break;
250 case 'K': /* status word? (2 byte) */
251 n += 2;
252 break;
253 case 'N': /* count of substructures (word) at end */
254 n += 2;
255 break;
256 case 'D': /* double word (4 byte) */
257 case 'z': /* offset to zero terminated string (4 byte) */
258 case 'l': /* offset to user data (4 byte) */
259 n += 4;
260 break;
261 case 'b': /* offset to data (with counter) (4 byte) */
262 n += 4;
263 get_counter(&p);
264 break;
265 case 'B': /* byte (with optional counter) */
266 n += get_counter(&p);
267 break;
270 return n;
273 static bool init_package(struct pack_desc *p, int count, int subcount)
275 int n = p->buflen;
276 int i;
278 if (!p->format || !p->base) {
279 return False;
282 i = count * getlen(p->format);
283 if (p->subformat) {
284 i += subcount * getlen(p->subformat);
286 p->structbuf = p->base;
287 p->neededlen = 0;
288 p->usedlen = 0;
289 p->subcount = 0;
290 p->curpos = p->format;
291 if (i > n) {
292 p->neededlen = i;
293 i = n = 0;
294 #if 0
296 * This is the old error code we used. Aparently
297 * WinNT/2k systems return ERRbuftoosmall (2123) and
298 * OS/2 needs this. I'm leaving this here so we can revert
299 * if needed. JRA.
301 p->errcode = ERRmoredata;
302 #else
303 p->errcode = ERRbuftoosmall;
304 #endif
305 } else {
306 p->errcode = NERR_Success;
308 p->buflen = i;
309 n -= i;
310 p->stringbuf = p->base + i;
311 p->stringlen = n;
312 return (p->errcode == NERR_Success);
315 static int package(struct pack_desc *p, ...)
317 va_list args;
318 int needed=0, stringneeded;
319 const char *str=NULL;
320 int is_string=0, stringused;
321 int32 temp;
323 va_start(args,p);
325 if (!*p->curpos) {
326 if (!p->subcount) {
327 p->curpos = p->format;
328 } else {
329 p->curpos = p->subformat;
330 p->subcount--;
333 #if CHECK_TYPES
334 str = va_arg(args,char*);
335 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
336 #endif
337 stringneeded = -1;
339 if (!p->curpos) {
340 va_end(args);
341 return 0;
344 switch( *p->curpos++ ) {
345 case 'W': /* word (2 byte) */
346 needed = 2;
347 temp = va_arg(args,int);
348 if (p->buflen >= needed) {
349 SSVAL(p->structbuf,0,temp);
351 break;
352 case 'K': /* status word? (2 byte) */
353 needed = 2;
354 temp = va_arg(args,int);
355 if (p->buflen >= needed) {
356 SSVAL(p->structbuf,0,temp);
358 break;
359 case 'N': /* count of substructures (word) at end */
360 needed = 2;
361 p->subcount = va_arg(args,int);
362 if (p->buflen >= needed) {
363 SSVAL(p->structbuf,0,p->subcount);
365 break;
366 case 'D': /* double word (4 byte) */
367 needed = 4;
368 temp = va_arg(args,int);
369 if (p->buflen >= needed) {
370 SIVAL(p->structbuf,0,temp);
372 break;
373 case 'B': /* byte (with optional counter) */
374 needed = get_counter(&p->curpos);
376 char *s = va_arg(args,char*);
377 if (p->buflen >= needed) {
378 StrnCpy(p->structbuf,s?s:"",needed-1);
381 break;
382 case 'z': /* offset to zero terminated string (4 byte) */
383 str = va_arg(args,char*);
384 stringneeded = (str ? strlen(str)+1 : 0);
385 is_string = 1;
386 break;
387 case 'l': /* offset to user data (4 byte) */
388 str = va_arg(args,char*);
389 stringneeded = va_arg(args,int);
390 is_string = 0;
391 break;
392 case 'b': /* offset to data (with counter) (4 byte) */
393 str = va_arg(args,char*);
394 stringneeded = get_counter(&p->curpos);
395 is_string = 0;
396 break;
399 va_end(args);
400 if (stringneeded >= 0) {
401 needed = 4;
402 if (p->buflen >= needed) {
403 stringused = stringneeded;
404 if (stringused > p->stringlen) {
405 stringused = (is_string ? p->stringlen : 0);
406 if (p->errcode == NERR_Success) {
407 p->errcode = ERRmoredata;
410 if (!stringused) {
411 SIVAL(p->structbuf,0,0);
412 } else {
413 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
414 memcpy(p->stringbuf,str?str:"",stringused);
415 if (is_string) {
416 p->stringbuf[stringused-1] = '\0';
418 p->stringbuf += stringused;
419 p->stringlen -= stringused;
420 p->usedlen += stringused;
423 p->neededlen += stringneeded;
426 p->neededlen += needed;
427 if (p->buflen >= needed) {
428 p->structbuf += needed;
429 p->buflen -= needed;
430 p->usedlen += needed;
431 } else {
432 if (p->errcode == NERR_Success) {
433 p->errcode = ERRmoredata;
436 return 1;
439 #if CHECK_TYPES
440 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
441 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
442 #else
443 #define PACK(desc,t,v) package(desc,v)
444 #define PACKl(desc,t,v,l) package(desc,v,l)
445 #endif
447 static void PACKI(struct pack_desc* desc, const char *t,int v)
449 PACK(desc,t,v);
452 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
454 PACK(desc,t,v);
457 /****************************************************************************
458 Get a print queue.
459 ****************************************************************************/
461 static void PackDriverData(struct pack_desc* desc)
463 char drivdata[4+4+32];
464 SIVAL(drivdata,0,sizeof drivdata); /* cb */
465 SIVAL(drivdata,4,1000); /* lVersion */
466 memset(drivdata+8,0,32); /* szDeviceName */
467 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
468 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
471 static int check_printq_info(struct pack_desc* desc,
472 unsigned int uLevel, char *id1, char *id2)
474 desc->subformat = NULL;
475 switch( uLevel ) {
476 case 0:
477 desc->format = "B13";
478 break;
479 case 1:
480 desc->format = "B13BWWWzzzzzWW";
481 break;
482 case 2:
483 desc->format = "B13BWWWzzzzzWN";
484 desc->subformat = "WB21BB16B10zWWzDDz";
485 break;
486 case 3:
487 desc->format = "zWWWWzzzzWWzzl";
488 break;
489 case 4:
490 desc->format = "zWWWWzzzzWNzzl";
491 desc->subformat = "WWzWWDDzz";
492 break;
493 case 5:
494 desc->format = "z";
495 break;
496 case 51:
497 desc->format = "K";
498 break;
499 case 52:
500 desc->format = "WzzzzzzzzN";
501 desc->subformat = "z";
502 break;
503 default:
504 DEBUG(0,("check_printq_info: invalid level %d\n",
505 uLevel ));
506 return False;
508 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
509 DEBUG(0,("check_printq_info: invalid format %s\n",
510 id1 ? id1 : "<NULL>" ));
511 return False;
513 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
514 DEBUG(0,("check_printq_info: invalid subformat %s\n",
515 id2 ? id2 : "<NULL>" ));
516 return False;
518 return True;
522 #define RAP_JOB_STATUS_QUEUED 0
523 #define RAP_JOB_STATUS_PAUSED 1
524 #define RAP_JOB_STATUS_SPOOLING 2
525 #define RAP_JOB_STATUS_PRINTING 3
526 #define RAP_JOB_STATUS_PRINTED 4
528 #define RAP_QUEUE_STATUS_PAUSED 1
529 #define RAP_QUEUE_STATUS_ERROR 2
531 /* turn a print job status into a on the wire status
533 static int printj_status(int v)
535 switch (v) {
536 case LPQ_QUEUED:
537 return RAP_JOB_STATUS_QUEUED;
538 case LPQ_PAUSED:
539 return RAP_JOB_STATUS_PAUSED;
540 case LPQ_SPOOLING:
541 return RAP_JOB_STATUS_SPOOLING;
542 case LPQ_PRINTING:
543 return RAP_JOB_STATUS_PRINTING;
545 return 0;
548 /* turn a print queue status into a on the wire status
550 static int printq_status(int v)
552 switch (v) {
553 case LPQ_QUEUED:
554 return 0;
555 case LPQ_PAUSED:
556 return RAP_QUEUE_STATUS_PAUSED;
558 return RAP_QUEUE_STATUS_ERROR;
561 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
562 struct pack_desc *desc,
563 print_queue_struct *queue, int n)
565 time_t t = queue->time;
567 /* the client expects localtime */
568 t -= get_time_zone(t);
570 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
571 if (uLevel == 1) {
572 PACKS(desc,"B21",queue->fs_user); /* szUserName */
573 PACKS(desc,"B",""); /* pad */
574 PACKS(desc,"B16",""); /* szNotifyName */
575 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
576 PACKS(desc,"z",""); /* pszParms */
577 PACKI(desc,"W",n+1); /* uPosition */
578 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
579 PACKS(desc,"z",""); /* pszStatus */
580 PACKI(desc,"D",t); /* ulSubmitted */
581 PACKI(desc,"D",queue->size); /* ulSize */
582 PACKS(desc,"z",queue->fs_file); /* pszComment */
584 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
585 PACKI(desc,"W",queue->priority); /* uPriority */
586 PACKS(desc,"z",queue->fs_user); /* pszUserName */
587 PACKI(desc,"W",n+1); /* uPosition */
588 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
589 PACKI(desc,"D",t); /* ulSubmitted */
590 PACKI(desc,"D",queue->size); /* ulSize */
591 PACKS(desc,"z","Samba"); /* pszComment */
592 PACKS(desc,"z",queue->fs_file); /* pszDocument */
593 if (uLevel == 3) {
594 PACKS(desc,"z",""); /* pszNotifyName */
595 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
596 PACKS(desc,"z",""); /* pszParms */
597 PACKS(desc,"z",""); /* pszStatus */
598 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
599 PACKS(desc,"z","lpd"); /* pszQProcName */
600 PACKS(desc,"z",""); /* pszQProcParms */
601 PACKS(desc,"z","NULL"); /* pszDriverName */
602 PackDriverData(desc); /* pDriverData */
603 PACKS(desc,"z",""); /* pszPrinterName */
604 } else if (uLevel == 4) { /* OS2 */
605 PACKS(desc,"z",""); /* pszSpoolFileName */
606 PACKS(desc,"z",""); /* pszPortName */
607 PACKS(desc,"z",""); /* pszStatus */
608 PACKI(desc,"D",0); /* ulPagesSpooled */
609 PACKI(desc,"D",0); /* ulPagesSent */
610 PACKI(desc,"D",0); /* ulPagesPrinted */
611 PACKI(desc,"D",0); /* ulTimePrinted */
612 PACKI(desc,"D",0); /* ulExtendJobStatus */
613 PACKI(desc,"D",0); /* ulStartPage */
614 PACKI(desc,"D",0); /* ulEndPage */
619 /********************************************************************
620 Return a driver name given an snum.
621 Returns True if from tdb, False otherwise.
622 ********************************************************************/
624 static bool get_driver_name(int snum, char **pp_drivername)
626 NT_PRINTER_INFO_LEVEL *info = NULL;
627 bool in_tdb = false;
629 get_a_printer (NULL, &info, 2, lp_servicename(snum));
630 if (info != NULL) {
631 *pp_drivername = talloc_strdup(talloc_tos(),
632 info->info_2->drivername);
633 in_tdb = true;
634 free_a_printer(&info, 2);
635 if (!*pp_drivername) {
636 return false;
640 return in_tdb;
643 /********************************************************************
644 Respond to the DosPrintQInfo command with a level of 52
645 This is used to get printer driver information for Win9x clients
646 ********************************************************************/
647 static void fill_printq_info_52(connection_struct *conn, int snum,
648 struct pack_desc* desc, int count )
650 int i;
651 fstring location;
652 struct spoolss_DriverInfo8 *driver = NULL;
653 NT_PRINTER_INFO_LEVEL *printer = NULL;
655 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
656 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
657 lp_servicename(snum)));
658 goto err;
661 if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
662 "Windows 4.0", 0)) )
664 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
665 printer->info_2->drivername));
666 goto err;
669 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
670 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
671 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
673 PACKI(desc, "W", 0x0400); /* don't know */
674 PACKS(desc, "z", driver->driver_name); /* long printer name */
675 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
676 PACKS(desc, "z", driver->data_file); /* Datafile name */
677 PACKS(desc, "z", driver->monitor_name); /* language monitor */
679 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
680 standard_sub_basic( "", "", location, sizeof(location)-1 );
681 PACKS(desc,"z", location); /* share to retrieve files */
683 PACKS(desc,"z", driver->default_datatype); /* default data type */
684 PACKS(desc,"z", driver->help_file); /* helpfile name */
685 PACKS(desc,"z", driver->driver_path); /* driver name */
687 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
688 DEBUG(3,("Driver: %s:\n",driver->driver_path));
689 DEBUG(3,("Data File: %s:\n",driver->data_file));
690 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
691 DEBUG(3,("Driver Location: %s:\n",location));
692 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
693 DEBUG(3,("Help File: %s:\n",driver->help_file));
694 PACKI(desc,"N",count); /* number of files to copy */
696 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
698 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
699 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
700 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
703 /* sanity check */
704 if ( i != count )
705 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
706 count, i));
708 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
710 desc->errcode=NERR_Success;
711 goto done;
713 err:
714 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
715 desc->errcode=NERR_notsupported;
717 done:
718 if ( printer )
719 free_a_printer( &printer, 2 );
721 free_a_printer_driver(driver);
725 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
726 struct pack_desc* desc,
727 int count, print_queue_struct* queue,
728 print_status_struct* status)
730 switch (uLevel) {
731 case 1:
732 case 2:
733 PACKS(desc,"B13",SERVICE(snum));
734 break;
735 case 3:
736 case 4:
737 case 5:
738 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
739 break;
740 case 51:
741 PACKI(desc,"K",printq_status(status->status));
742 break;
745 if (uLevel == 1 || uLevel == 2) {
746 PACKS(desc,"B",""); /* alignment */
747 PACKI(desc,"W",5); /* priority */
748 PACKI(desc,"W",0); /* start time */
749 PACKI(desc,"W",0); /* until time */
750 PACKS(desc,"z",""); /* pSepFile */
751 PACKS(desc,"z","lpd"); /* pPrProc */
752 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
753 PACKS(desc,"z",""); /* pParms */
754 if (snum < 0) {
755 PACKS(desc,"z","UNKNOWN PRINTER");
756 PACKI(desc,"W",LPSTAT_ERROR);
758 else if (!status || !status->message[0]) {
759 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
760 PACKI(desc,"W",LPSTAT_OK); /* status */
761 } else {
762 PACKS(desc,"z",status->message);
763 PACKI(desc,"W",printq_status(status->status)); /* status */
765 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
768 if (uLevel == 3 || uLevel == 4) {
769 char *drivername = NULL;
771 PACKI(desc,"W",5); /* uPriority */
772 PACKI(desc,"W",0); /* uStarttime */
773 PACKI(desc,"W",0); /* uUntiltime */
774 PACKI(desc,"W",5); /* pad1 */
775 PACKS(desc,"z",""); /* pszSepFile */
776 PACKS(desc,"z","WinPrint"); /* pszPrProc */
777 PACKS(desc,"z",NULL); /* pszParms */
778 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
779 /* "don't ask" that it's done this way to fix corrupted
780 Win9X/ME printer comments. */
781 if (!status) {
782 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
783 } else {
784 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
786 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
787 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
788 get_driver_name(snum,&drivername);
789 if (!drivername) {
790 return;
792 PACKS(desc,"z",drivername); /* pszDriverName */
793 PackDriverData(desc); /* pDriverData */
796 if (uLevel == 2 || uLevel == 4) {
797 int i;
798 for (i=0;i<count;i++)
799 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
802 if (uLevel==52)
803 fill_printq_info_52( conn, snum, desc, count );
806 /* This function returns the number of files for a given driver */
807 static int get_printerdrivernumber(int snum)
809 int result = 0;
810 struct spoolss_DriverInfo8 *driver;
811 NT_PRINTER_INFO_LEVEL *printer = NULL;
813 ZERO_STRUCT(driver);
815 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
816 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
817 lp_servicename(snum)));
818 goto done;
821 if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
822 "Windows 4.0", 0)) )
824 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
825 printer->info_2->drivername));
826 goto done;
829 /* count the number of files */
830 while (driver->dependent_files && *driver->dependent_files[result])
831 result++;
832 done:
833 if ( printer )
834 free_a_printer( &printer, 2 );
836 free_a_printer_driver(driver);
838 return result;
841 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
842 char *param, int tpscnt,
843 char *data, int tdscnt,
844 int mdrcnt,int mprcnt,
845 char **rdata,char **rparam,
846 int *rdata_len,int *rparam_len)
848 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
849 char *str2 = skip_string(param,tpscnt,str1);
850 char *p = skip_string(param,tpscnt,str2);
851 char *QueueName = p;
852 unsigned int uLevel;
853 int count=0;
854 int snum;
855 char *str3;
856 struct pack_desc desc;
857 print_queue_struct *queue=NULL;
858 print_status_struct status;
859 char* tmpdata=NULL;
861 if (!str1 || !str2 || !p) {
862 return False;
864 memset((char *)&status,'\0',sizeof(status));
865 memset((char *)&desc,'\0',sizeof(desc));
867 p = skip_string(param,tpscnt,p);
868 if (!p) {
869 return False;
871 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
872 str3 = get_safe_str_ptr(param,tpscnt,p,4);
873 /* str3 may be null here and is checked in check_printq_info(). */
875 /* remove any trailing username */
876 if ((p = strchr_m(QueueName,'%')))
877 *p = 0;
879 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
881 /* check it's a supported varient */
882 if (!prefix_ok(str1,"zWrLh"))
883 return False;
884 if (!check_printq_info(&desc,uLevel,str2,str3)) {
886 * Patch from Scott Moomaw <scott@bridgewater.edu>
887 * to return the 'invalid info level' error if an
888 * unknown level was requested.
890 *rdata_len = 0;
891 *rparam_len = 6;
892 *rparam = smb_realloc_limit(*rparam,*rparam_len);
893 if (!*rparam) {
894 return False;
896 SSVALS(*rparam,0,ERRunknownlevel);
897 SSVAL(*rparam,2,0);
898 SSVAL(*rparam,4,0);
899 return(True);
902 snum = find_service(QueueName);
903 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
904 return False;
906 if (uLevel==52) {
907 count = get_printerdrivernumber(snum);
908 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
909 } else {
910 count = print_queue_status(snum, &queue,&status);
913 if (mdrcnt > 0) {
914 *rdata = smb_realloc_limit(*rdata,mdrcnt);
915 if (!*rdata) {
916 SAFE_FREE(queue);
917 return False;
919 desc.base = *rdata;
920 desc.buflen = mdrcnt;
921 } else {
923 * Don't return data but need to get correct length
924 * init_package will return wrong size if buflen=0
926 desc.buflen = getlen(desc.format);
927 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
930 if (init_package(&desc,1,count)) {
931 desc.subcount = count;
932 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
935 *rdata_len = desc.usedlen;
938 * We must set the return code to ERRbuftoosmall
939 * in order to support lanman style printing with Win NT/2k
940 * clients --jerry
942 if (!mdrcnt && lp_disable_spoolss())
943 desc.errcode = ERRbuftoosmall;
945 *rdata_len = desc.usedlen;
946 *rparam_len = 6;
947 *rparam = smb_realloc_limit(*rparam,*rparam_len);
948 if (!*rparam) {
949 SAFE_FREE(queue);
950 SAFE_FREE(tmpdata);
951 return False;
953 SSVALS(*rparam,0,desc.errcode);
954 SSVAL(*rparam,2,0);
955 SSVAL(*rparam,4,desc.neededlen);
957 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
959 SAFE_FREE(queue);
960 SAFE_FREE(tmpdata);
962 return(True);
965 /****************************************************************************
966 View list of all print jobs on all queues.
967 ****************************************************************************/
969 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
970 char *param, int tpscnt,
971 char *data, int tdscnt,
972 int mdrcnt, int mprcnt,
973 char **rdata, char** rparam,
974 int *rdata_len, int *rparam_len)
976 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
977 char *output_format1 = skip_string(param,tpscnt,param_format);
978 char *p = skip_string(param,tpscnt,output_format1);
979 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
980 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
981 int services = lp_numservices();
982 int i, n;
983 struct pack_desc desc;
984 print_queue_struct **queue = NULL;
985 print_status_struct *status = NULL;
986 int *subcntarr = NULL;
987 int queuecnt = 0, subcnt = 0, succnt = 0;
989 if (!param_format || !output_format1 || !p) {
990 return False;
993 memset((char *)&desc,'\0',sizeof(desc));
995 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
997 if (!prefix_ok(param_format,"WrLeh")) {
998 return False;
1000 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1002 * Patch from Scott Moomaw <scott@bridgewater.edu>
1003 * to return the 'invalid info level' error if an
1004 * unknown level was requested.
1006 *rdata_len = 0;
1007 *rparam_len = 6;
1008 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1009 if (!*rparam) {
1010 return False;
1012 SSVALS(*rparam,0,ERRunknownlevel);
1013 SSVAL(*rparam,2,0);
1014 SSVAL(*rparam,4,0);
1015 return(True);
1018 for (i = 0; i < services; i++) {
1019 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1020 queuecnt++;
1024 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1025 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1026 goto err;
1028 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1029 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1030 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1031 goto err;
1033 memset(status,0,queuecnt*sizeof(print_status_struct));
1034 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1035 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1036 goto err;
1039 subcnt = 0;
1040 n = 0;
1041 for (i = 0; i < services; i++) {
1042 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1043 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1044 subcnt += subcntarr[n];
1045 n++;
1049 if (mdrcnt > 0) {
1050 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1051 if (!*rdata) {
1052 goto err;
1055 desc.base = *rdata;
1056 desc.buflen = mdrcnt;
1058 if (init_package(&desc,queuecnt,subcnt)) {
1059 n = 0;
1060 succnt = 0;
1061 for (i = 0; i < services; i++) {
1062 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1063 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1064 n++;
1065 if (desc.errcode == NERR_Success) {
1066 succnt = n;
1072 SAFE_FREE(subcntarr);
1074 *rdata_len = desc.usedlen;
1075 *rparam_len = 8;
1076 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1077 if (!*rparam) {
1078 goto err;
1080 SSVALS(*rparam,0,desc.errcode);
1081 SSVAL(*rparam,2,0);
1082 SSVAL(*rparam,4,succnt);
1083 SSVAL(*rparam,6,queuecnt);
1085 for (i = 0; i < queuecnt; i++) {
1086 if (queue) {
1087 SAFE_FREE(queue[i]);
1091 SAFE_FREE(queue);
1092 SAFE_FREE(status);
1094 return True;
1096 err:
1098 SAFE_FREE(subcntarr);
1099 for (i = 0; i < queuecnt; i++) {
1100 if (queue) {
1101 SAFE_FREE(queue[i]);
1104 SAFE_FREE(queue);
1105 SAFE_FREE(status);
1107 return False;
1110 /****************************************************************************
1111 Get info level for a server list query.
1112 ****************************************************************************/
1114 static bool check_server_info(int uLevel, char* id)
1116 switch( uLevel ) {
1117 case 0:
1118 if (strcmp(id,"B16") != 0) {
1119 return False;
1121 break;
1122 case 1:
1123 if (strcmp(id,"B16BBDz") != 0) {
1124 return False;
1126 break;
1127 default:
1128 return False;
1130 return True;
1133 struct srv_info_struct {
1134 fstring name;
1135 uint32 type;
1136 fstring comment;
1137 fstring domain;
1138 bool server_added;
1141 /*******************************************************************
1142 Get server info lists from the files saved by nmbd. Return the
1143 number of entries.
1144 ******************************************************************/
1146 static int get_server_info(uint32 servertype,
1147 struct srv_info_struct **servers,
1148 const char *domain)
1150 int count=0;
1151 int alloced=0;
1152 char **lines;
1153 bool local_list_only;
1154 int i;
1156 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1157 if (!lines) {
1158 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1159 return 0;
1162 /* request for everything is code for request all servers */
1163 if (servertype == SV_TYPE_ALL) {
1164 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1167 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1169 DEBUG(4,("Servertype search: %8x\n",servertype));
1171 for (i=0;lines[i];i++) {
1172 fstring stype;
1173 struct srv_info_struct *s;
1174 const char *ptr = lines[i];
1175 bool ok = True;
1176 TALLOC_CTX *frame = NULL;
1177 char *p;
1179 if (!*ptr) {
1180 continue;
1183 if (count == alloced) {
1184 alloced += 10;
1185 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1186 if (!*servers) {
1187 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1188 TALLOC_FREE(lines);
1189 return 0;
1191 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1193 s = &(*servers)[count];
1195 frame = talloc_stackframe();
1196 s->name[0] = '\0';
1197 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1198 TALLOC_FREE(frame);
1199 continue;
1201 fstrcpy(s->name, p);
1203 stype[0] = '\0';
1204 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1205 TALLOC_FREE(frame);
1206 continue;
1208 fstrcpy(stype, p);
1210 s->comment[0] = '\0';
1211 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1212 TALLOC_FREE(frame);
1213 continue;
1215 fstrcpy(s->comment, p);
1216 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1218 s->domain[0] = '\0';
1219 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1220 /* this allows us to cope with an old nmbd */
1221 fstrcpy(s->domain,lp_workgroup());
1222 } else {
1223 fstrcpy(s->domain, p);
1225 TALLOC_FREE(frame);
1227 if (sscanf(stype,"%X",&s->type) != 1) {
1228 DEBUG(4,("r:host file "));
1229 ok = False;
1232 /* Filter the servers/domains we return based on what was asked for. */
1234 /* Check to see if we are being asked for a local list only. */
1235 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1236 DEBUG(4,("r: local list only"));
1237 ok = False;
1240 /* doesn't match up: don't want it */
1241 if (!(servertype & s->type)) {
1242 DEBUG(4,("r:serv type "));
1243 ok = False;
1246 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1247 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1248 DEBUG(4,("s: dom mismatch "));
1249 ok = False;
1252 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1253 ok = False;
1256 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1257 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1259 if (ok) {
1260 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1261 s->name, s->type, s->comment, s->domain));
1262 s->server_added = True;
1263 count++;
1264 } else {
1265 DEBUG(4,("%20s %8x %25s %15s\n",
1266 s->name, s->type, s->comment, s->domain));
1270 TALLOC_FREE(lines);
1271 return count;
1274 /*******************************************************************
1275 Fill in a server info structure.
1276 ******************************************************************/
1278 static int fill_srv_info(struct srv_info_struct *service,
1279 int uLevel, char **buf, int *buflen,
1280 char **stringbuf, int *stringspace, char *baseaddr)
1282 int struct_len;
1283 char* p;
1284 char* p2;
1285 int l2;
1286 int len;
1288 switch (uLevel) {
1289 case 0:
1290 struct_len = 16;
1291 break;
1292 case 1:
1293 struct_len = 26;
1294 break;
1295 default:
1296 return -1;
1299 if (!buf) {
1300 len = 0;
1301 switch (uLevel) {
1302 case 1:
1303 len = strlen(service->comment)+1;
1304 break;
1307 *buflen = struct_len;
1308 *stringspace = len;
1309 return struct_len + len;
1312 len = struct_len;
1313 p = *buf;
1314 if (*buflen < struct_len) {
1315 return -1;
1317 if (stringbuf) {
1318 p2 = *stringbuf;
1319 l2 = *stringspace;
1320 } else {
1321 p2 = p + struct_len;
1322 l2 = *buflen - struct_len;
1324 if (!baseaddr) {
1325 baseaddr = p;
1328 switch (uLevel) {
1329 case 0:
1330 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1331 break;
1333 case 1:
1334 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1335 SIVAL(p,18,service->type);
1336 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1337 len += CopyAndAdvance(&p2,service->comment,&l2);
1338 break;
1341 if (stringbuf) {
1342 *buf = p + struct_len;
1343 *buflen -= struct_len;
1344 *stringbuf = p2;
1345 *stringspace = l2;
1346 } else {
1347 *buf = p2;
1348 *buflen -= len;
1350 return len;
1354 static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1356 #undef strcasecmp
1357 return strcasecmp(s1->name,s2->name);
1360 /****************************************************************************
1361 View list of servers available (or possibly domains). The info is
1362 extracted from lists saved by nmbd on the local host.
1363 ****************************************************************************/
1365 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1366 char *param, int tpscnt,
1367 char *data, int tdscnt,
1368 int mdrcnt, int mprcnt, char **rdata,
1369 char **rparam, int *rdata_len, int *rparam_len)
1371 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1372 char *str2 = skip_string(param,tpscnt,str1);
1373 char *p = skip_string(param,tpscnt,str2);
1374 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1375 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1376 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1377 char *p2;
1378 int data_len, fixed_len, string_len;
1379 int f_len = 0, s_len = 0;
1380 struct srv_info_struct *servers=NULL;
1381 int counted=0,total=0;
1382 int i,missed;
1383 fstring domain;
1384 bool domain_request;
1385 bool local_request;
1387 if (!str1 || !str2 || !p) {
1388 return False;
1391 /* If someone sets all the bits they don't really mean to set
1392 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1393 known servers. */
1395 if (servertype == SV_TYPE_ALL) {
1396 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1399 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1400 any other bit (they may just set this bit on its own) they
1401 want all the locally seen servers. However this bit can be
1402 set on its own so set the requested servers to be
1403 ALL - DOMAIN_ENUM. */
1405 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1406 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1409 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1410 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1412 p += 8;
1414 if (!prefix_ok(str1,"WrLehD")) {
1415 return False;
1417 if (!check_server_info(uLevel,str2)) {
1418 return False;
1421 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1422 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1423 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1425 if (strcmp(str1, "WrLehDz") == 0) {
1426 if (skip_string(param,tpscnt,p) == NULL) {
1427 return False;
1429 pull_ascii_fstring(domain, p);
1430 } else {
1431 fstrcpy(domain, lp_workgroup());
1434 DEBUG(4, ("domain [%s]\n", domain));
1436 if (lp_browse_list()) {
1437 total = get_server_info(servertype,&servers,domain);
1440 data_len = fixed_len = string_len = 0;
1441 missed = 0;
1443 if (total > 0) {
1444 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1448 char *lastname=NULL;
1450 for (i=0;i<total;i++) {
1451 struct srv_info_struct *s = &servers[i];
1453 if (lastname && strequal(lastname,s->name)) {
1454 continue;
1456 lastname = s->name;
1457 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1458 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1459 i, s->name, s->type, s->comment, s->domain));
1461 if (data_len <= buf_len) {
1462 counted++;
1463 fixed_len += f_len;
1464 string_len += s_len;
1465 } else {
1466 missed++;
1471 *rdata_len = fixed_len + string_len;
1472 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1473 if (!*rdata) {
1474 return False;
1477 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1478 p = *rdata;
1479 f_len = fixed_len;
1480 s_len = string_len;
1483 char *lastname=NULL;
1484 int count2 = counted;
1486 for (i = 0; i < total && count2;i++) {
1487 struct srv_info_struct *s = &servers[i];
1489 if (lastname && strequal(lastname,s->name)) {
1490 continue;
1492 lastname = s->name;
1493 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1494 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1495 i, s->name, s->type, s->comment, s->domain));
1496 count2--;
1500 *rparam_len = 8;
1501 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1502 if (!*rparam) {
1503 return False;
1505 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1506 SSVAL(*rparam,2,0);
1507 SSVAL(*rparam,4,counted);
1508 SSVAL(*rparam,6,counted+missed);
1510 SAFE_FREE(servers);
1512 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1513 domain,uLevel,counted,counted+missed));
1515 return True;
1518 static int srv_name_match(const char *n1, const char *n2)
1521 * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
1523 * In Windows, FirstNameToReturn need not be an exact match:
1524 * the server will return a list of servers that exist on
1525 * the network greater than or equal to the FirstNameToReturn.
1527 int ret = strcasecmp(n1, n2);
1529 if (ret <= 0) {
1530 return 0;
1533 return ret;
1536 static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
1537 char *param, int tpscnt,
1538 char *data, int tdscnt,
1539 int mdrcnt, int mprcnt, char **rdata,
1540 char **rparam, int *rdata_len, int *rparam_len)
1542 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1543 char *str2 = skip_string(param,tpscnt,str1);
1544 char *p = skip_string(param,tpscnt,str2);
1545 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1546 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1547 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1548 char *p2;
1549 int data_len, fixed_len, string_len;
1550 int f_len = 0, s_len = 0;
1551 struct srv_info_struct *servers=NULL;
1552 int counted=0,first=0,total=0;
1553 int i,missed;
1554 fstring domain;
1555 fstring first_name;
1556 bool domain_request;
1557 bool local_request;
1559 if (!str1 || !str2 || !p) {
1560 return False;
1563 /* If someone sets all the bits they don't really mean to set
1564 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1565 known servers. */
1567 if (servertype == SV_TYPE_ALL) {
1568 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1571 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1572 any other bit (they may just set this bit on its own) they
1573 want all the locally seen servers. However this bit can be
1574 set on its own so set the requested servers to be
1575 ALL - DOMAIN_ENUM. */
1577 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1578 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1581 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1582 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1584 p += 8;
1586 if (strcmp(str1, "WrLehDzz") != 0) {
1587 return false;
1589 if (!check_server_info(uLevel,str2)) {
1590 return False;
1593 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1594 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1595 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1597 if (skip_string(param,tpscnt,p) == NULL) {
1598 return False;
1600 pull_ascii_fstring(domain, p);
1601 if (domain[0] == '\0') {
1602 fstrcpy(domain, lp_workgroup());
1604 p = skip_string(param,tpscnt,p);
1605 if (skip_string(param,tpscnt,p) == NULL) {
1606 return False;
1608 pull_ascii_fstring(first_name, p);
1610 DEBUG(4, ("domain: '%s' first_name: '%s'\n",
1611 domain, first_name));
1613 if (lp_browse_list()) {
1614 total = get_server_info(servertype,&servers,domain);
1617 data_len = fixed_len = string_len = 0;
1618 missed = 0;
1620 if (total > 0) {
1621 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1624 if (first_name[0] != '\0') {
1625 struct srv_info_struct *first_server = NULL;
1627 BINARY_ARRAY_SEARCH(servers, total, name, first_name,
1628 srv_name_match, first_server);
1629 if (first_server) {
1630 first = PTR_DIFF(first_server, servers) / sizeof(*servers);
1632 * The binary search may not find the exact match
1633 * so we need to search backward to find the first match
1635 * This implements the strange matching windows
1636 * implements. (see the comment in srv_name_match().
1638 for (;first > 0;) {
1639 int ret;
1640 ret = strcasecmp(first_name,
1641 servers[first-1].name);
1642 if (ret > 0) {
1643 break;
1645 first--;
1647 } else {
1648 /* we should return no entries */
1649 first = total;
1654 char *lastname=NULL;
1656 for (i=first;i<total;i++) {
1657 struct srv_info_struct *s = &servers[i];
1659 if (lastname && strequal(lastname,s->name)) {
1660 continue;
1662 lastname = s->name;
1663 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1664 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1665 i, s->name, s->type, s->comment, s->domain));
1667 if (data_len <= buf_len) {
1668 counted++;
1669 fixed_len += f_len;
1670 string_len += s_len;
1671 } else {
1672 missed++;
1677 *rdata_len = fixed_len + string_len;
1678 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1679 if (!*rdata) {
1680 return False;
1683 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1684 p = *rdata;
1685 f_len = fixed_len;
1686 s_len = string_len;
1689 char *lastname=NULL;
1690 int count2 = counted;
1692 for (i = first; i < total && count2;i++) {
1693 struct srv_info_struct *s = &servers[i];
1695 if (lastname && strequal(lastname,s->name)) {
1696 continue;
1698 lastname = s->name;
1699 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1700 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1701 i, s->name, s->type, s->comment, s->domain));
1702 count2--;
1706 *rparam_len = 8;
1707 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1708 if (!*rparam) {
1709 return False;
1711 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1712 SSVAL(*rparam,2,0);
1713 SSVAL(*rparam,4,counted);
1714 SSVAL(*rparam,6,counted+missed);
1716 DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n",
1717 domain,uLevel,first,first_name,
1718 first < total ? servers[first].name : "",
1719 counted,counted+missed));
1721 SAFE_FREE(servers);
1723 return True;
1726 /****************************************************************************
1727 command 0x34 - suspected of being a "Lookup Names" stub api
1728 ****************************************************************************/
1730 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1731 char *param, int tpscnt,
1732 char *data, int tdscnt,
1733 int mdrcnt, int mprcnt, char **rdata,
1734 char **rparam, int *rdata_len, int *rparam_len)
1736 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1737 char *str2 = skip_string(param,tpscnt,str1);
1738 char *p = skip_string(param,tpscnt,str2);
1739 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1740 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1741 int counted=0;
1742 int missed=0;
1744 if (!str1 || !str2 || !p) {
1745 return False;
1748 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1749 str1, str2, p, uLevel, buf_len));
1751 if (!prefix_ok(str1,"zWrLeh")) {
1752 return False;
1755 *rdata_len = 0;
1757 *rparam_len = 8;
1758 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1759 if (!*rparam) {
1760 return False;
1763 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1764 SSVAL(*rparam,2,0);
1765 SSVAL(*rparam,4,counted);
1766 SSVAL(*rparam,6,counted+missed);
1768 return True;
1771 /****************************************************************************
1772 get info about a share
1773 ****************************************************************************/
1775 static bool check_share_info(int uLevel, char* id)
1777 switch( uLevel ) {
1778 case 0:
1779 if (strcmp(id,"B13") != 0) {
1780 return False;
1782 break;
1783 case 1:
1784 /* Level-2 descriptor is allowed (and ignored) */
1785 if (strcmp(id,"B13BWz") != 0 &&
1786 strcmp(id,"B13BWzWWWzB9B") != 0) {
1787 return False;
1789 break;
1790 case 2:
1791 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1792 return False;
1794 break;
1795 case 91:
1796 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1797 return False;
1799 break;
1800 default:
1801 return False;
1803 return True;
1806 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1807 char** buf, int* buflen,
1808 char** stringbuf, int* stringspace, char* baseaddr)
1810 int struct_len;
1811 char* p;
1812 char* p2;
1813 int l2;
1814 int len;
1816 switch( uLevel ) {
1817 case 0:
1818 struct_len = 13;
1819 break;
1820 case 1:
1821 struct_len = 20;
1822 break;
1823 case 2:
1824 struct_len = 40;
1825 break;
1826 case 91:
1827 struct_len = 68;
1828 break;
1829 default:
1830 return -1;
1833 if (!buf) {
1834 len = 0;
1836 if (uLevel > 0) {
1837 len += StrlenExpanded(conn,snum,lp_comment(snum));
1839 if (uLevel > 1) {
1840 len += strlen(lp_pathname(snum)) + 1;
1842 if (buflen) {
1843 *buflen = struct_len;
1845 if (stringspace) {
1846 *stringspace = len;
1848 return struct_len + len;
1851 len = struct_len;
1852 p = *buf;
1853 if ((*buflen) < struct_len) {
1854 return -1;
1857 if (stringbuf) {
1858 p2 = *stringbuf;
1859 l2 = *stringspace;
1860 } else {
1861 p2 = p + struct_len;
1862 l2 = (*buflen) - struct_len;
1865 if (!baseaddr) {
1866 baseaddr = p;
1869 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1871 if (uLevel > 0) {
1872 int type;
1874 SCVAL(p,13,0);
1875 type = STYPE_DISKTREE;
1876 if (lp_print_ok(snum)) {
1877 type = STYPE_PRINTQ;
1879 if (strequal("IPC",lp_fstype(snum))) {
1880 type = STYPE_IPC;
1882 SSVAL(p,14,type); /* device type */
1883 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1884 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1887 if (uLevel > 1) {
1888 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1889 SSVALS(p,22,-1); /* max uses */
1890 SSVAL(p,24,1); /* current uses */
1891 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1892 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1893 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1896 if (uLevel > 2) {
1897 memset(p+40,0,SHPWLEN+2);
1898 SSVAL(p,50,0);
1899 SIVAL(p,52,0);
1900 SSVAL(p,56,0);
1901 SSVAL(p,58,0);
1902 SIVAL(p,60,0);
1903 SSVAL(p,64,0);
1904 SSVAL(p,66,0);
1907 if (stringbuf) {
1908 (*buf) = p + struct_len;
1909 (*buflen) -= struct_len;
1910 (*stringbuf) = p2;
1911 (*stringspace) = l2;
1912 } else {
1913 (*buf) = p2;
1914 (*buflen) -= len;
1917 return len;
1920 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1921 char *param, int tpscnt,
1922 char *data, int tdscnt,
1923 int mdrcnt,int mprcnt,
1924 char **rdata,char **rparam,
1925 int *rdata_len,int *rparam_len)
1927 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1928 char *str2 = skip_string(param,tpscnt,str1);
1929 char *netname = skip_string(param,tpscnt,str2);
1930 char *p = skip_string(param,tpscnt,netname);
1931 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1932 int snum;
1934 if (!str1 || !str2 || !netname || !p) {
1935 return False;
1938 snum = find_service(netname);
1939 if (snum < 0) {
1940 return False;
1943 /* check it's a supported varient */
1944 if (!prefix_ok(str1,"zWrLh")) {
1945 return False;
1947 if (!check_share_info(uLevel,str2)) {
1948 return False;
1951 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1952 if (!*rdata) {
1953 return False;
1955 p = *rdata;
1956 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1957 if (*rdata_len < 0) {
1958 return False;
1961 *rparam_len = 6;
1962 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1963 if (!*rparam) {
1964 return False;
1966 SSVAL(*rparam,0,NERR_Success);
1967 SSVAL(*rparam,2,0); /* converter word */
1968 SSVAL(*rparam,4,*rdata_len);
1970 return True;
1973 /****************************************************************************
1974 View the list of available shares.
1976 This function is the server side of the NetShareEnum() RAP call.
1977 It fills the return buffer with share names and share comments.
1978 Note that the return buffer normally (in all known cases) allows only
1979 twelve byte strings for share names (plus one for a nul terminator).
1980 Share names longer than 12 bytes must be skipped.
1981 ****************************************************************************/
1983 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1984 char *param, int tpscnt,
1985 char *data, int tdscnt,
1986 int mdrcnt,
1987 int mprcnt,
1988 char **rdata,
1989 char **rparam,
1990 int *rdata_len,
1991 int *rparam_len )
1993 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1994 char *str2 = skip_string(param,tpscnt,str1);
1995 char *p = skip_string(param,tpscnt,str2);
1996 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1997 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1998 char *p2;
1999 int count = 0;
2000 int total=0,counted=0;
2001 bool missed = False;
2002 int i;
2003 int data_len, fixed_len, string_len;
2004 int f_len = 0, s_len = 0;
2006 if (!str1 || !str2 || !p) {
2007 return False;
2010 if (!prefix_ok(str1,"WrLeh")) {
2011 return False;
2013 if (!check_share_info(uLevel,str2)) {
2014 return False;
2017 /* Ensure all the usershares are loaded. */
2018 become_root();
2019 load_registry_shares();
2020 count = load_usershare_shares();
2021 unbecome_root();
2023 data_len = fixed_len = string_len = 0;
2024 for (i=0;i<count;i++) {
2025 fstring servicename_dos;
2026 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2027 continue;
2029 push_ascii_fstring(servicename_dos, lp_servicename(i));
2030 /* Maximum name length = 13. */
2031 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
2032 total++;
2033 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
2034 if (data_len <= buf_len) {
2035 counted++;
2036 fixed_len += f_len;
2037 string_len += s_len;
2038 } else {
2039 missed = True;
2044 *rdata_len = fixed_len + string_len;
2045 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2046 if (!*rdata) {
2047 return False;
2050 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
2051 p = *rdata;
2052 f_len = fixed_len;
2053 s_len = string_len;
2055 for( i = 0; i < count; i++ ) {
2056 fstring servicename_dos;
2057 if (!(lp_browseable(i) && lp_snum_ok(i))) {
2058 continue;
2061 push_ascii_fstring(servicename_dos, lp_servicename(i));
2062 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
2063 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
2064 break;
2069 *rparam_len = 8;
2070 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2071 if (!*rparam) {
2072 return False;
2074 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
2075 SSVAL(*rparam,2,0);
2076 SSVAL(*rparam,4,counted);
2077 SSVAL(*rparam,6,total);
2079 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
2080 counted,total,uLevel,
2081 buf_len,*rdata_len,mdrcnt));
2083 return True;
2086 /****************************************************************************
2087 Add a share
2088 ****************************************************************************/
2090 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
2091 char *param, int tpscnt,
2092 char *data, int tdscnt,
2093 int mdrcnt,int mprcnt,
2094 char **rdata,char **rparam,
2095 int *rdata_len,int *rparam_len)
2097 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2098 char *str2 = skip_string(param,tpscnt,str1);
2099 char *p = skip_string(param,tpscnt,str2);
2100 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2101 fstring sharename;
2102 fstring comment;
2103 char *pathname = NULL;
2104 char *command, *cmdname;
2105 unsigned int offset;
2106 int snum;
2107 int res = ERRunsup;
2108 size_t converted_size;
2110 if (!str1 || !str2 || !p) {
2111 return False;
2114 /* check it's a supported varient */
2115 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
2116 return False;
2118 if (!check_share_info(uLevel,str2)) {
2119 return False;
2121 if (uLevel != 2) {
2122 return False;
2125 /* Do we have a string ? */
2126 if (skip_string(data,mdrcnt,data) == NULL) {
2127 return False;
2129 pull_ascii_fstring(sharename,data);
2130 snum = find_service(sharename);
2131 if (snum >= 0) { /* already exists */
2132 res = ERRfilexists;
2133 goto error_exit;
2136 if (mdrcnt < 28) {
2137 return False;
2140 /* only support disk share adds */
2141 if (SVAL(data,14)!=STYPE_DISKTREE) {
2142 return False;
2145 offset = IVAL(data, 16);
2146 if (offset >= mdrcnt) {
2147 res = ERRinvalidparam;
2148 goto error_exit;
2151 /* Do we have a string ? */
2152 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2153 return False;
2155 pull_ascii_fstring(comment, offset? (data+offset) : "");
2157 offset = IVAL(data, 26);
2159 if (offset >= mdrcnt) {
2160 res = ERRinvalidparam;
2161 goto error_exit;
2164 /* Do we have a string ? */
2165 if (skip_string(data,mdrcnt,data+offset) == NULL) {
2166 return False;
2169 if (!pull_ascii_talloc(talloc_tos(), &pathname,
2170 offset ? (data+offset) : "", &converted_size))
2172 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
2173 strerror(errno)));
2176 if (!pathname) {
2177 return false;
2180 string_replace(sharename, '"', ' ');
2181 string_replace(pathname, '"', ' ');
2182 string_replace(comment, '"', ' ');
2184 cmdname = lp_add_share_cmd();
2186 if (!cmdname || *cmdname == '\0') {
2187 return False;
2190 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
2191 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
2192 pathname, comment) == -1) {
2193 return false;
2196 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
2198 if ((res = smbrun(command, NULL)) != 0) {
2199 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
2200 command, res ));
2201 SAFE_FREE(command);
2202 res = ERRnoaccess;
2203 goto error_exit;
2204 } else {
2205 SAFE_FREE(command);
2206 message_send_all(smbd_messaging_context(),
2207 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2210 *rparam_len = 6;
2211 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2212 if (!*rparam) {
2213 return False;
2215 SSVAL(*rparam,0,NERR_Success);
2216 SSVAL(*rparam,2,0); /* converter word */
2217 SSVAL(*rparam,4,*rdata_len);
2218 *rdata_len = 0;
2220 return True;
2222 error_exit:
2224 *rparam_len = 4;
2225 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2226 if (!*rparam) {
2227 return False;
2229 *rdata_len = 0;
2230 SSVAL(*rparam,0,res);
2231 SSVAL(*rparam,2,0);
2232 return True;
2235 /****************************************************************************
2236 view list of groups available
2237 ****************************************************************************/
2239 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2240 char *param, int tpscnt,
2241 char *data, int tdscnt,
2242 int mdrcnt,int mprcnt,
2243 char **rdata,char **rparam,
2244 int *rdata_len,int *rparam_len)
2246 int i;
2247 int errflags=0;
2248 int resume_context, cli_buf_size;
2249 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2250 char *str2 = skip_string(param,tpscnt,str1);
2251 char *p = skip_string(param,tpscnt,str2);
2253 uint32_t num_groups;
2254 uint32_t resume_handle;
2255 struct rpc_pipe_client *samr_pipe;
2256 struct policy_handle samr_handle, domain_handle;
2257 NTSTATUS status;
2259 if (!str1 || !str2 || !p) {
2260 return False;
2263 if (strcmp(str1,"WrLeh") != 0) {
2264 return False;
2267 /* parameters
2268 * W-> resume context (number of users to skip)
2269 * r -> return parameter pointer to receive buffer
2270 * L -> length of receive buffer
2271 * e -> return parameter number of entries
2272 * h -> return parameter total number of users
2275 if (strcmp("B21",str2) != 0) {
2276 return False;
2279 status = rpc_pipe_open_internal(
2280 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2281 conn->server_info, &samr_pipe);
2282 if (!NT_STATUS_IS_OK(status)) {
2283 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2284 nt_errstr(status)));
2285 return false;
2288 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2289 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2290 if (!NT_STATUS_IS_OK(status)) {
2291 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2292 nt_errstr(status)));
2293 return false;
2296 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2297 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2298 get_global_sam_sid(), &domain_handle);
2299 if (!NT_STATUS_IS_OK(status)) {
2300 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2301 nt_errstr(status)));
2302 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2303 return false;
2306 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2307 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2308 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2309 "%d\n", resume_context, cli_buf_size));
2311 *rdata_len = cli_buf_size;
2312 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2313 if (!*rdata) {
2314 return False;
2317 p = *rdata;
2319 errflags = NERR_Success;
2320 num_groups = 0;
2321 resume_handle = 0;
2323 while (true) {
2324 struct samr_SamArray *sam_entries;
2325 uint32_t num_entries;
2327 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2328 &domain_handle,
2329 &resume_handle,
2330 &sam_entries, 1,
2331 &num_entries);
2332 if (!NT_STATUS_IS_OK(status)) {
2333 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2334 "%s\n", nt_errstr(status)));
2335 break;
2338 if (num_entries == 0) {
2339 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2340 "no entries -- done\n"));
2341 break;
2344 for(i=0; i<num_entries; i++) {
2345 const char *name;
2347 name = sam_entries->entries[i].name.string;
2349 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2350 /* set overflow error */
2351 DEBUG(3,("overflow on entry %d group %s\n", i,
2352 name));
2353 errflags=234;
2354 break;
2357 /* truncate the name at 21 chars. */
2358 memset(p, 0, 21);
2359 strlcpy(p, name, 21);
2360 DEBUG(10,("adding entry %d group %s\n", i, p));
2361 p += 21;
2362 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2363 * idea why... */
2364 num_groups += 1;
2367 if (errflags != NERR_Success) {
2368 break;
2371 TALLOC_FREE(sam_entries);
2374 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2375 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2377 *rdata_len = PTR_DIFF(p,*rdata);
2379 *rparam_len = 8;
2380 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2381 if (!*rparam) {
2382 return False;
2384 SSVAL(*rparam, 0, errflags);
2385 SSVAL(*rparam, 2, 0); /* converter word */
2386 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2387 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2389 return(True);
2392 /*******************************************************************
2393 Get groups that a user is a member of.
2394 ******************************************************************/
2396 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2397 char *param, int tpscnt,
2398 char *data, int tdscnt,
2399 int mdrcnt,int mprcnt,
2400 char **rdata,char **rparam,
2401 int *rdata_len,int *rparam_len)
2403 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2404 char *str2 = skip_string(param,tpscnt,str1);
2405 char *UserName = skip_string(param,tpscnt,str2);
2406 char *p = skip_string(param,tpscnt,UserName);
2407 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2408 const char *level_string;
2409 int count=0;
2410 bool ret = False;
2411 uint32_t i;
2412 char *endp = NULL;
2414 struct rpc_pipe_client *samr_pipe;
2415 struct policy_handle samr_handle, domain_handle, user_handle;
2416 struct lsa_String name;
2417 struct lsa_Strings names;
2418 struct samr_Ids type, rid;
2419 struct samr_RidWithAttributeArray *rids;
2420 NTSTATUS status;
2422 if (!str1 || !str2 || !UserName || !p) {
2423 return False;
2426 *rparam_len = 8;
2427 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2428 if (!*rparam) {
2429 return False;
2432 /* check it's a supported varient */
2434 if ( strcmp(str1,"zWrLeh") != 0 )
2435 return False;
2437 switch( uLevel ) {
2438 case 0:
2439 level_string = "B21";
2440 break;
2441 default:
2442 return False;
2445 if (strcmp(level_string,str2) != 0)
2446 return False;
2448 *rdata_len = mdrcnt + 1024;
2449 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2450 if (!*rdata) {
2451 return False;
2454 SSVAL(*rparam,0,NERR_Success);
2455 SSVAL(*rparam,2,0); /* converter word */
2457 p = *rdata;
2458 endp = *rdata + *rdata_len;
2460 status = rpc_pipe_open_internal(
2461 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2462 conn->server_info, &samr_pipe);
2463 if (!NT_STATUS_IS_OK(status)) {
2464 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2465 nt_errstr(status)));
2466 return false;
2469 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2470 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2471 if (!NT_STATUS_IS_OK(status)) {
2472 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2473 nt_errstr(status)));
2474 return false;
2477 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2478 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2479 get_global_sam_sid(), &domain_handle);
2480 if (!NT_STATUS_IS_OK(status)) {
2481 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2482 nt_errstr(status)));
2483 goto close_sam;
2486 name.string = UserName;
2488 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2489 &domain_handle, 1, &name,
2490 &rid, &type);
2491 if (!NT_STATUS_IS_OK(status)) {
2492 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2493 nt_errstr(status)));
2494 goto close_domain;
2497 if (type.ids[0] != SID_NAME_USER) {
2498 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2499 sid_type_lookup(type.ids[0])));
2500 goto close_domain;
2503 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2504 &domain_handle,
2505 SAMR_USER_ACCESS_GET_GROUPS,
2506 rid.ids[0], &user_handle);
2507 if (!NT_STATUS_IS_OK(status)) {
2508 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2509 nt_errstr(status)));
2510 goto close_domain;
2513 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2514 &user_handle, &rids);
2515 if (!NT_STATUS_IS_OK(status)) {
2516 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2517 nt_errstr(status)));
2518 goto close_user;
2521 for (i=0; i<rids->count; i++) {
2523 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2524 &domain_handle,
2525 1, &rids->rids[i].rid,
2526 &names, &type);
2527 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2528 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2529 p += 21;
2530 count++;
2534 *rdata_len = PTR_DIFF(p,*rdata);
2536 SSVAL(*rparam,4,count); /* is this right?? */
2537 SSVAL(*rparam,6,count); /* is this right?? */
2539 ret = True;
2541 close_user:
2542 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2543 close_domain:
2544 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2545 close_sam:
2546 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2548 return ret;
2551 /*******************************************************************
2552 Get all users.
2553 ******************************************************************/
2555 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2556 char *param, int tpscnt,
2557 char *data, int tdscnt,
2558 int mdrcnt,int mprcnt,
2559 char **rdata,char **rparam,
2560 int *rdata_len,int *rparam_len)
2562 int count_sent=0;
2563 int num_users=0;
2564 int errflags=0;
2565 int i, resume_context, cli_buf_size;
2566 uint32_t resume_handle;
2568 struct rpc_pipe_client *samr_pipe;
2569 struct policy_handle samr_handle, domain_handle;
2570 NTSTATUS status;
2572 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2573 char *str2 = skip_string(param,tpscnt,str1);
2574 char *p = skip_string(param,tpscnt,str2);
2575 char *endp = NULL;
2577 if (!str1 || !str2 || !p) {
2578 return False;
2581 if (strcmp(str1,"WrLeh") != 0)
2582 return False;
2583 /* parameters
2584 * W-> resume context (number of users to skip)
2585 * r -> return parameter pointer to receive buffer
2586 * L -> length of receive buffer
2587 * e -> return parameter number of entries
2588 * h -> return parameter total number of users
2591 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2592 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2593 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2594 resume_context, cli_buf_size));
2596 *rparam_len = 8;
2597 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2598 if (!*rparam) {
2599 return False;
2602 /* check it's a supported varient */
2603 if (strcmp("B21",str2) != 0)
2604 return False;
2606 *rdata_len = cli_buf_size;
2607 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2608 if (!*rdata) {
2609 return False;
2612 p = *rdata;
2613 endp = *rdata + *rdata_len;
2615 status = rpc_pipe_open_internal(
2616 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2617 conn->server_info, &samr_pipe);
2618 if (!NT_STATUS_IS_OK(status)) {
2619 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2620 nt_errstr(status)));
2621 return false;
2624 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2625 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2626 if (!NT_STATUS_IS_OK(status)) {
2627 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2628 nt_errstr(status)));
2629 return false;
2632 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2633 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2634 get_global_sam_sid(), &domain_handle);
2635 if (!NT_STATUS_IS_OK(status)) {
2636 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2637 nt_errstr(status)));
2638 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2639 return false;
2642 errflags=NERR_Success;
2644 resume_handle = 0;
2646 while (true) {
2647 struct samr_SamArray *sam_entries;
2648 uint32_t num_entries;
2650 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2651 &domain_handle,
2652 &resume_handle,
2653 0, &sam_entries, 1,
2654 &num_entries);
2656 if (!NT_STATUS_IS_OK(status)) {
2657 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2658 "%s\n", nt_errstr(status)));
2659 break;
2662 if (num_entries == 0) {
2663 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2664 "no entries -- done\n"));
2665 break;
2668 for (i=0; i<num_entries; i++) {
2669 const char *name;
2671 name = sam_entries->entries[i].name.string;
2673 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2674 &&(strlen(name)<=21)) {
2675 strlcpy(p,name,PTR_DIFF(endp,p));
2676 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2677 "username %s\n",count_sent,p));
2678 p += 21;
2679 count_sent++;
2680 } else {
2681 /* set overflow error */
2682 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2683 "username %s\n",count_sent,name));
2684 errflags=234;
2685 break;
2689 if (errflags != NERR_Success) {
2690 break;
2693 TALLOC_FREE(sam_entries);
2696 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2697 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2699 *rdata_len = PTR_DIFF(p,*rdata);
2701 SSVAL(*rparam,0,errflags);
2702 SSVAL(*rparam,2,0); /* converter word */
2703 SSVAL(*rparam,4,count_sent); /* is this right?? */
2704 SSVAL(*rparam,6,num_users); /* is this right?? */
2706 return True;
2709 /****************************************************************************
2710 Get the time of day info.
2711 ****************************************************************************/
2713 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2714 char *param, int tpscnt,
2715 char *data, int tdscnt,
2716 int mdrcnt,int mprcnt,
2717 char **rdata,char **rparam,
2718 int *rdata_len,int *rparam_len)
2720 struct tm *t;
2721 time_t unixdate = time(NULL);
2722 char *p;
2724 *rparam_len = 4;
2725 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2726 if (!*rparam) {
2727 return False;
2730 *rdata_len = 21;
2731 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2732 if (!*rdata) {
2733 return False;
2736 SSVAL(*rparam,0,NERR_Success);
2737 SSVAL(*rparam,2,0); /* converter word */
2739 p = *rdata;
2741 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2742 by NT in a "net time" operation,
2743 it seems to ignore the one below */
2745 /* the client expects to get localtime, not GMT, in this bit
2746 (I think, this needs testing) */
2747 t = localtime(&unixdate);
2748 if (!t) {
2749 return False;
2752 SIVAL(p,4,0); /* msecs ? */
2753 SCVAL(p,8,t->tm_hour);
2754 SCVAL(p,9,t->tm_min);
2755 SCVAL(p,10,t->tm_sec);
2756 SCVAL(p,11,0); /* hundredths of seconds */
2757 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2758 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2759 SCVAL(p,16,t->tm_mday);
2760 SCVAL(p,17,t->tm_mon + 1);
2761 SSVAL(p,18,1900+t->tm_year);
2762 SCVAL(p,20,t->tm_wday);
2764 return True;
2767 /****************************************************************************
2768 Set the user password.
2769 *****************************************************************************/
2771 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2772 char *param, int tpscnt,
2773 char *data, int tdscnt,
2774 int mdrcnt,int mprcnt,
2775 char **rdata,char **rparam,
2776 int *rdata_len,int *rparam_len)
2778 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2779 char *p = NULL;
2780 fstring user;
2781 fstring pass1,pass2;
2783 /* Skip 2 strings. */
2784 p = skip_string(param,tpscnt,np);
2785 p = skip_string(param,tpscnt,p);
2787 if (!np || !p) {
2788 return False;
2791 /* Do we have a string ? */
2792 if (skip_string(param,tpscnt,p) == NULL) {
2793 return False;
2795 pull_ascii_fstring(user,p);
2797 p = skip_string(param,tpscnt,p);
2798 if (!p) {
2799 return False;
2802 memset(pass1,'\0',sizeof(pass1));
2803 memset(pass2,'\0',sizeof(pass2));
2805 * We use 31 here not 32 as we're checking
2806 * the last byte we want to access is safe.
2808 if (!is_offset_safe(param,tpscnt,p,31)) {
2809 return False;
2811 memcpy(pass1,p,16);
2812 memcpy(pass2,p+16,16);
2814 *rparam_len = 4;
2815 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2816 if (!*rparam) {
2817 return False;
2820 *rdata_len = 0;
2822 SSVAL(*rparam,0,NERR_badpass);
2823 SSVAL(*rparam,2,0); /* converter word */
2825 DEBUG(3,("Set password for <%s>\n",user));
2828 * Attempt to verify the old password against smbpasswd entries
2829 * Win98 clients send old and new password in plaintext for this call.
2833 auth_serversupplied_info *server_info = NULL;
2834 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2836 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2838 become_root();
2839 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2840 SSVAL(*rparam,0,NERR_Success);
2842 unbecome_root();
2844 TALLOC_FREE(server_info);
2846 data_blob_clear_free(&password);
2850 * If the plaintext change failed, attempt
2851 * the old encrypted method. NT will generate this
2852 * after trying the samr method. Note that this
2853 * method is done as a last resort as this
2854 * password change method loses the NT password hash
2855 * and cannot change the UNIX password as no plaintext
2856 * is received.
2859 if(SVAL(*rparam,0) != NERR_Success) {
2860 struct samu *hnd = NULL;
2862 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2863 become_root();
2864 if (change_lanman_password(hnd,(uchar *)pass2)) {
2865 SSVAL(*rparam,0,NERR_Success);
2867 unbecome_root();
2868 TALLOC_FREE(hnd);
2872 memset((char *)pass1,'\0',sizeof(fstring));
2873 memset((char *)pass2,'\0',sizeof(fstring));
2875 return(True);
2878 /****************************************************************************
2879 Set the user password (SamOEM version - gets plaintext).
2880 ****************************************************************************/
2882 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2883 char *param, int tpscnt,
2884 char *data, int tdscnt,
2885 int mdrcnt,int mprcnt,
2886 char **rdata,char **rparam,
2887 int *rdata_len,int *rparam_len)
2889 struct smbd_server_connection *sconn = smbd_server_conn;
2890 fstring user;
2891 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2892 *rparam_len = 2;
2893 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2894 if (!*rparam) {
2895 return False;
2898 if (!p) {
2899 return False;
2901 *rdata_len = 0;
2903 SSVAL(*rparam,0,NERR_badpass);
2906 * Check the parameter definition is correct.
2909 /* Do we have a string ? */
2910 if (skip_string(param,tpscnt,p) == 0) {
2911 return False;
2913 if(!strequal(p, "zsT")) {
2914 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2915 return False;
2917 p = skip_string(param, tpscnt, p);
2918 if (!p) {
2919 return False;
2922 /* Do we have a string ? */
2923 if (skip_string(param,tpscnt,p) == 0) {
2924 return False;
2926 if(!strequal(p, "B516B16")) {
2927 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2928 return False;
2930 p = skip_string(param,tpscnt,p);
2931 if (!p) {
2932 return False;
2934 /* Do we have a string ? */
2935 if (skip_string(param,tpscnt,p) == 0) {
2936 return False;
2938 p += pull_ascii_fstring(user,p);
2940 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2943 * Pass the user through the NT -> unix user mapping
2944 * function.
2947 (void)map_username(sconn, user);
2949 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2950 SSVAL(*rparam,0,NERR_Success);
2953 return(True);
2956 /****************************************************************************
2957 delete a print job
2958 Form: <W> <>
2959 ****************************************************************************/
2961 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2962 char *param, int tpscnt,
2963 char *data, int tdscnt,
2964 int mdrcnt,int mprcnt,
2965 char **rdata,char **rparam,
2966 int *rdata_len,int *rparam_len)
2968 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2969 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2970 char *str2 = skip_string(param,tpscnt,str1);
2971 char *p = skip_string(param,tpscnt,str2);
2972 uint32 jobid;
2973 int snum;
2974 fstring sharename;
2975 int errcode;
2976 WERROR werr = WERR_OK;
2978 if (!str1 || !str2 || !p) {
2979 return False;
2982 * We use 1 here not 2 as we're checking
2983 * the last byte we want to access is safe.
2985 if (!is_offset_safe(param,tpscnt,p,1)) {
2986 return False;
2988 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2989 return False;
2991 /* check it's a supported varient */
2992 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2993 return(False);
2995 *rparam_len = 4;
2996 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2997 if (!*rparam) {
2998 return False;
3000 *rdata_len = 0;
3002 if (!print_job_exists(sharename, jobid)) {
3003 errcode = NERR_JobNotFound;
3004 goto out;
3007 snum = lp_servicenumber( sharename);
3008 if (snum == -1) {
3009 errcode = NERR_DestNotFound;
3010 goto out;
3013 errcode = NERR_notsupported;
3015 switch (function) {
3016 case 81: /* delete */
3017 if (print_job_delete(conn->server_info, snum, jobid, &werr))
3018 errcode = NERR_Success;
3019 break;
3020 case 82: /* pause */
3021 if (print_job_pause(conn->server_info, snum, jobid, &werr))
3022 errcode = NERR_Success;
3023 break;
3024 case 83: /* resume */
3025 if (print_job_resume(conn->server_info, snum, jobid, &werr))
3026 errcode = NERR_Success;
3027 break;
3030 if (!W_ERROR_IS_OK(werr))
3031 errcode = W_ERROR_V(werr);
3033 out:
3034 SSVAL(*rparam,0,errcode);
3035 SSVAL(*rparam,2,0); /* converter word */
3037 return(True);
3040 /****************************************************************************
3041 Purge a print queue - or pause or resume it.
3042 ****************************************************************************/
3044 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
3045 char *param, int tpscnt,
3046 char *data, int tdscnt,
3047 int mdrcnt,int mprcnt,
3048 char **rdata,char **rparam,
3049 int *rdata_len,int *rparam_len)
3051 int function = get_safe_SVAL(param,tpscnt,param,0,0);
3052 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3053 char *str2 = skip_string(param,tpscnt,str1);
3054 char *QueueName = skip_string(param,tpscnt,str2);
3055 int errcode = NERR_notsupported;
3056 int snum;
3057 WERROR werr = WERR_OK;
3059 if (!str1 || !str2 || !QueueName) {
3060 return False;
3063 /* check it's a supported varient */
3064 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
3065 return(False);
3067 *rparam_len = 4;
3068 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3069 if (!*rparam) {
3070 return False;
3072 *rdata_len = 0;
3074 if (skip_string(param,tpscnt,QueueName) == NULL) {
3075 return False;
3077 snum = print_queue_snum(QueueName);
3079 if (snum == -1) {
3080 errcode = NERR_JobNotFound;
3081 goto out;
3084 switch (function) {
3085 case 74: /* Pause queue */
3086 werr = print_queue_pause(conn->server_info, snum);
3087 break;
3088 case 75: /* Resume queue */
3089 werr = print_queue_resume(conn->server_info, snum);
3090 break;
3091 case 103: /* Purge */
3092 werr = print_queue_purge(conn->server_info, snum);
3093 break;
3094 default:
3095 werr = WERR_NOT_SUPPORTED;
3096 break;
3099 errcode = W_ERROR_V(werr);
3101 out:
3102 SSVAL(*rparam,0,errcode);
3103 SSVAL(*rparam,2,0); /* converter word */
3105 return(True);
3108 /****************************************************************************
3109 set the property of a print job (undocumented?)
3110 ? function = 0xb -> set name of print job
3111 ? function = 0x6 -> move print job up/down
3112 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
3113 or <WWsTP> <WB21BB16B10zWWzDDz>
3114 ****************************************************************************/
3116 static int check_printjob_info(struct pack_desc* desc,
3117 int uLevel, char* id)
3119 desc->subformat = NULL;
3120 switch( uLevel ) {
3121 case 0: desc->format = "W"; break;
3122 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
3123 case 2: desc->format = "WWzWWDDzz"; break;
3124 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
3125 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
3126 default:
3127 DEBUG(0,("check_printjob_info: invalid level %d\n",
3128 uLevel ));
3129 return False;
3131 if (id == NULL || strcmp(desc->format,id) != 0) {
3132 DEBUG(0,("check_printjob_info: invalid format %s\n",
3133 id ? id : "<NULL>" ));
3134 return False;
3136 return True;
3139 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
3140 char *param, int tpscnt,
3141 char *data, int tdscnt,
3142 int mdrcnt,int mprcnt,
3143 char **rdata,char **rparam,
3144 int *rdata_len,int *rparam_len)
3146 struct pack_desc desc;
3147 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3148 char *str2 = skip_string(param,tpscnt,str1);
3149 char *p = skip_string(param,tpscnt,str2);
3150 uint32 jobid;
3151 fstring sharename;
3152 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3153 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
3154 int place, errcode;
3156 if (!str1 || !str2 || !p) {
3157 return False;
3160 * We use 1 here not 2 as we're checking
3161 * the last byte we want to access is safe.
3163 if (!is_offset_safe(param,tpscnt,p,1)) {
3164 return False;
3166 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
3167 return False;
3168 *rparam_len = 4;
3169 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3170 if (!*rparam) {
3171 return False;
3174 if (!share_defined(sharename)) {
3175 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
3176 sharename));
3177 return False;
3180 *rdata_len = 0;
3182 /* check it's a supported varient */
3183 if ((strcmp(str1,"WWsTP")) ||
3184 (!check_printjob_info(&desc,uLevel,str2)))
3185 return(False);
3187 if (!print_job_exists(sharename, jobid)) {
3188 errcode=NERR_JobNotFound;
3189 goto out;
3192 errcode = NERR_notsupported;
3194 switch (function) {
3195 case 0x6:
3196 /* change job place in the queue,
3197 data gives the new place */
3198 place = SVAL(data,0);
3199 if (print_job_set_place(sharename, jobid, place)) {
3200 errcode=NERR_Success;
3202 break;
3204 case 0xb:
3205 /* change print job name, data gives the name */
3206 if (print_job_set_name(sharename, jobid, data)) {
3207 errcode=NERR_Success;
3209 break;
3211 default:
3212 return False;
3215 out:
3216 SSVALS(*rparam,0,errcode);
3217 SSVAL(*rparam,2,0); /* converter word */
3219 return(True);
3223 /****************************************************************************
3224 Get info about the server.
3225 ****************************************************************************/
3227 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3228 char *param, int tpscnt,
3229 char *data, int tdscnt,
3230 int mdrcnt,int mprcnt,
3231 char **rdata,char **rparam,
3232 int *rdata_len,int *rparam_len)
3234 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3235 char *str2 = skip_string(param,tpscnt,str1);
3236 char *p = skip_string(param,tpscnt,str2);
3237 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3238 char *p2;
3239 int struct_len;
3241 if (!str1 || !str2 || !p) {
3242 return False;
3245 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3247 /* check it's a supported varient */
3248 if (!prefix_ok(str1,"WrLh")) {
3249 return False;
3252 switch( uLevel ) {
3253 case 0:
3254 if (strcmp(str2,"B16") != 0) {
3255 return False;
3257 struct_len = 16;
3258 break;
3259 case 1:
3260 if (strcmp(str2,"B16BBDz") != 0) {
3261 return False;
3263 struct_len = 26;
3264 break;
3265 case 2:
3266 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3267 return False;
3269 struct_len = 134;
3270 break;
3271 case 3:
3272 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3273 return False;
3275 struct_len = 144;
3276 break;
3277 case 20:
3278 if (strcmp(str2,"DN") != 0) {
3279 return False;
3281 struct_len = 6;
3282 break;
3283 case 50:
3284 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3285 return False;
3287 struct_len = 42;
3288 break;
3289 default:
3290 return False;
3293 *rdata_len = mdrcnt;
3294 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3295 if (!*rdata) {
3296 return False;
3299 p = *rdata;
3300 p2 = p + struct_len;
3301 if (uLevel != 20) {
3302 srvstr_push(NULL, 0, p,global_myname(),16,
3303 STR_ASCII|STR_UPPER|STR_TERMINATE);
3305 p += 16;
3306 if (uLevel > 0) {
3307 struct srv_info_struct *servers=NULL;
3308 int i,count;
3309 char *comment = NULL;
3310 TALLOC_CTX *ctx = talloc_tos();
3311 uint32 servertype= lp_default_server_announce();
3313 comment = talloc_strdup(ctx,lp_serverstring());
3314 if (!comment) {
3315 return false;
3318 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3319 for (i=0;i<count;i++) {
3320 if (strequal(servers[i].name,global_myname())) {
3321 servertype = servers[i].type;
3322 TALLOC_FREE(comment);
3323 comment = talloc_strdup(ctx,
3324 servers[i].comment);
3325 if (comment) {
3326 return false;
3332 SAFE_FREE(servers);
3334 SCVAL(p,0,lp_major_announce_version());
3335 SCVAL(p,1,lp_minor_announce_version());
3336 SIVAL(p,2,servertype);
3338 if (mdrcnt == struct_len) {
3339 SIVAL(p,6,0);
3340 } else {
3341 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3342 comment = talloc_sub_advanced(
3343 ctx,
3344 lp_servicename(SNUM(conn)),
3345 conn->server_info->unix_name,
3346 conn->connectpath,
3347 conn->server_info->utok.gid,
3348 conn->server_info->sanitized_username,
3349 pdb_get_domain(conn->server_info->sam_account),
3350 comment);
3351 if (comment) {
3352 return false;
3354 if (mdrcnt - struct_len <= 0) {
3355 return false;
3357 push_ascii(p2,
3358 comment,
3359 MIN(mdrcnt - struct_len,
3360 MAX_SERVER_STRING_LENGTH),
3361 STR_TERMINATE);
3362 p2 = skip_string(*rdata,*rdata_len,p2);
3363 if (!p2) {
3364 return False;
3369 if (uLevel > 1) {
3370 return False; /* not yet implemented */
3373 *rdata_len = PTR_DIFF(p2,*rdata);
3375 *rparam_len = 6;
3376 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3377 if (!*rparam) {
3378 return False;
3380 SSVAL(*rparam,0,NERR_Success);
3381 SSVAL(*rparam,2,0); /* converter word */
3382 SSVAL(*rparam,4,*rdata_len);
3384 return True;
3387 /****************************************************************************
3388 Get info about the server.
3389 ****************************************************************************/
3391 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3392 char *param, int tpscnt,
3393 char *data, int tdscnt,
3394 int mdrcnt,int mprcnt,
3395 char **rdata,char **rparam,
3396 int *rdata_len,int *rparam_len)
3398 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3399 char *str2 = skip_string(param,tpscnt,str1);
3400 char *p = skip_string(param,tpscnt,str2);
3401 char *p2;
3402 char *endp;
3403 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3405 if (!str1 || !str2 || !p) {
3406 return False;
3409 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3411 *rparam_len = 6;
3412 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3413 if (!*rparam) {
3414 return False;
3417 /* check it's a supported varient */
3418 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3419 return False;
3422 *rdata_len = mdrcnt + 1024;
3423 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3424 if (!*rdata) {
3425 return False;
3428 SSVAL(*rparam,0,NERR_Success);
3429 SSVAL(*rparam,2,0); /* converter word */
3431 p = *rdata;
3432 endp = *rdata + *rdata_len;
3434 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3435 if (!p2) {
3436 return False;
3439 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3440 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3441 strupper_m(p2);
3442 p2 = skip_string(*rdata,*rdata_len,p2);
3443 if (!p2) {
3444 return False;
3446 p += 4;
3448 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3449 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3450 p2 = skip_string(*rdata,*rdata_len,p2);
3451 if (!p2) {
3452 return False;
3454 p += 4;
3456 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3457 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3458 strupper_m(p2);
3459 p2 = skip_string(*rdata,*rdata_len,p2);
3460 if (!p2) {
3461 return False;
3463 p += 4;
3465 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3466 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3467 p += 2;
3469 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3470 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3471 p2 = skip_string(*rdata,*rdata_len,p2);
3472 if (!p2) {
3473 return False;
3475 p += 4;
3477 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3478 strlcpy(p2,"",PTR_DIFF(endp,p2));
3479 p2 = skip_string(*rdata,*rdata_len,p2);
3480 if (!p2) {
3481 return False;
3483 p += 4;
3485 *rdata_len = PTR_DIFF(p2,*rdata);
3487 SSVAL(*rparam,4,*rdata_len);
3489 return True;
3492 /****************************************************************************
3493 get info about a user
3495 struct user_info_11 {
3496 char usri11_name[21]; 0-20
3497 char usri11_pad; 21
3498 char *usri11_comment; 22-25
3499 char *usri11_usr_comment; 26-29
3500 unsigned short usri11_priv; 30-31
3501 unsigned long usri11_auth_flags; 32-35
3502 long usri11_password_age; 36-39
3503 char *usri11_homedir; 40-43
3504 char *usri11_parms; 44-47
3505 long usri11_last_logon; 48-51
3506 long usri11_last_logoff; 52-55
3507 unsigned short usri11_bad_pw_count; 56-57
3508 unsigned short usri11_num_logons; 58-59
3509 char *usri11_logon_server; 60-63
3510 unsigned short usri11_country_code; 64-65
3511 char *usri11_workstations; 66-69
3512 unsigned long usri11_max_storage; 70-73
3513 unsigned short usri11_units_per_week; 74-75
3514 unsigned char *usri11_logon_hours; 76-79
3515 unsigned short usri11_code_page; 80-81
3518 where:
3520 usri11_name specifies the user name for which information is retrieved
3522 usri11_pad aligns the next data structure element to a word boundary
3524 usri11_comment is a null terminated ASCII comment
3526 usri11_user_comment is a null terminated ASCII comment about the user
3528 usri11_priv specifies the level of the privilege assigned to the user.
3529 The possible values are:
3531 Name Value Description
3532 USER_PRIV_GUEST 0 Guest privilege
3533 USER_PRIV_USER 1 User privilege
3534 USER_PRV_ADMIN 2 Administrator privilege
3536 usri11_auth_flags specifies the account operator privileges. The
3537 possible values are:
3539 Name Value Description
3540 AF_OP_PRINT 0 Print operator
3543 Leach, Naik [Page 28]
3547 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3550 AF_OP_COMM 1 Communications operator
3551 AF_OP_SERVER 2 Server operator
3552 AF_OP_ACCOUNTS 3 Accounts operator
3555 usri11_password_age specifies how many seconds have elapsed since the
3556 password was last changed.
3558 usri11_home_dir points to a null terminated ASCII string that contains
3559 the path name of the user's home directory.
3561 usri11_parms points to a null terminated ASCII string that is set
3562 aside for use by applications.
3564 usri11_last_logon specifies the time when the user last logged on.
3565 This value is stored as the number of seconds elapsed since
3566 00:00:00, January 1, 1970.
3568 usri11_last_logoff specifies the time when the user last logged off.
3569 This value is stored as the number of seconds elapsed since
3570 00:00:00, January 1, 1970. A value of 0 means the last logoff
3571 time is unknown.
3573 usri11_bad_pw_count specifies the number of incorrect passwords
3574 entered since the last successful logon.
3576 usri11_log1_num_logons specifies the number of times this user has
3577 logged on. A value of -1 means the number of logons is unknown.
3579 usri11_logon_server points to a null terminated ASCII string that
3580 contains the name of the server to which logon requests are sent.
3581 A null string indicates logon requests should be sent to the
3582 domain controller.
3584 usri11_country_code specifies the country code for the user's language
3585 of choice.
3587 usri11_workstations points to a null terminated ASCII string that
3588 contains the names of workstations the user may log on from.
3589 There may be up to 8 workstations, with the names separated by
3590 commas. A null strings indicates there are no restrictions.
3592 usri11_max_storage specifies the maximum amount of disk space the user
3593 can occupy. A value of 0xffffffff indicates there are no
3594 restrictions.
3596 usri11_units_per_week specifies the equal number of time units into
3597 which a week is divided. This value must be equal to 168.
3599 usri11_logon_hours points to a 21 byte (168 bits) string that
3600 specifies the time during which the user can log on. Each bit
3601 represents one unique hour in a week. The first bit (bit 0, word
3602 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3606 Leach, Naik [Page 29]
3610 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3613 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3614 are no restrictions.
3616 usri11_code_page specifies the code page for the user's language of
3617 choice
3619 All of the pointers in this data structure need to be treated
3620 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3621 to be ignored. The converter word returned in the parameters section
3622 needs to be subtracted from the lower 16 bits to calculate an offset
3623 into the return buffer where this ASCII string resides.
3625 There is no auxiliary data in the response.
3627 ****************************************************************************/
3629 #define usri11_name 0
3630 #define usri11_pad 21
3631 #define usri11_comment 22
3632 #define usri11_usr_comment 26
3633 #define usri11_full_name 30
3634 #define usri11_priv 34
3635 #define usri11_auth_flags 36
3636 #define usri11_password_age 40
3637 #define usri11_homedir 44
3638 #define usri11_parms 48
3639 #define usri11_last_logon 52
3640 #define usri11_last_logoff 56
3641 #define usri11_bad_pw_count 60
3642 #define usri11_num_logons 62
3643 #define usri11_logon_server 64
3644 #define usri11_country_code 68
3645 #define usri11_workstations 70
3646 #define usri11_max_storage 74
3647 #define usri11_units_per_week 78
3648 #define usri11_logon_hours 80
3649 #define usri11_code_page 84
3650 #define usri11_end 86
3652 #define USER_PRIV_GUEST 0
3653 #define USER_PRIV_USER 1
3654 #define USER_PRIV_ADMIN 2
3656 #define AF_OP_PRINT 0
3657 #define AF_OP_COMM 1
3658 #define AF_OP_SERVER 2
3659 #define AF_OP_ACCOUNTS 3
3662 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3663 char *param, int tpscnt,
3664 char *data, int tdscnt,
3665 int mdrcnt,int mprcnt,
3666 char **rdata,char **rparam,
3667 int *rdata_len,int *rparam_len)
3669 struct smbd_server_connection *sconn = smbd_server_conn;
3670 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3671 char *str2 = skip_string(param,tpscnt,str1);
3672 char *UserName = skip_string(param,tpscnt,str2);
3673 char *p = skip_string(param,tpscnt,UserName);
3674 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3675 char *p2;
3676 char *endp;
3677 const char *level_string;
3679 /* get NIS home of a previously validated user - simeon */
3680 /* With share level security vuid will always be zero.
3681 Don't depend on vuser being non-null !!. JRA */
3682 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3683 if(vuser != NULL) {
3684 DEBUG(3,(" Username of UID %d is %s\n",
3685 (int)vuser->server_info->utok.uid,
3686 vuser->server_info->unix_name));
3689 if (!str1 || !str2 || !UserName || !p) {
3690 return False;
3693 *rparam_len = 6;
3694 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3695 if (!*rparam) {
3696 return False;
3699 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3701 /* check it's a supported variant */
3702 if (strcmp(str1,"zWrLh") != 0) {
3703 return False;
3705 switch( uLevel ) {
3706 case 0: level_string = "B21"; break;
3707 case 1: level_string = "B21BB16DWzzWz"; break;
3708 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3709 case 10: level_string = "B21Bzzz"; break;
3710 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3711 default: return False;
3714 if (strcmp(level_string,str2) != 0) {
3715 return False;
3718 *rdata_len = mdrcnt + 1024;
3719 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3720 if (!*rdata) {
3721 return False;
3724 SSVAL(*rparam,0,NERR_Success);
3725 SSVAL(*rparam,2,0); /* converter word */
3727 p = *rdata;
3728 endp = *rdata + *rdata_len;
3729 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3730 if (!p2) {
3731 return False;
3734 memset(p,0,21);
3735 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3737 if (uLevel > 0) {
3738 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3739 *p2 = 0;
3742 if (uLevel >= 10) {
3743 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3744 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3745 p2 = skip_string(*rdata,*rdata_len,p2);
3746 if (!p2) {
3747 return False;
3750 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3751 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3752 p2 = skip_string(*rdata,*rdata_len,p2);
3753 if (!p2) {
3754 return False;
3757 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3758 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3759 strlcpy(p2,((vuser != NULL)
3760 ? pdb_get_fullname(vuser->server_info->sam_account)
3761 : UserName),PTR_DIFF(endp,p2));
3762 p2 = skip_string(*rdata,*rdata_len,p2);
3763 if (!p2) {
3764 return False;
3768 if (uLevel == 11) {
3769 const char *homedir = "";
3770 if (vuser != NULL) {
3771 homedir = pdb_get_homedir(
3772 vuser->server_info->sam_account);
3774 /* modelled after NTAS 3.51 reply */
3775 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3776 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3777 SIVALS(p,usri11_password_age,-1); /* password age */
3778 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3779 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3780 p2 = skip_string(*rdata,*rdata_len,p2);
3781 if (!p2) {
3782 return False;
3784 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3785 strlcpy(p2,"",PTR_DIFF(endp,p2));
3786 p2 = skip_string(*rdata,*rdata_len,p2);
3787 if (!p2) {
3788 return False;
3790 SIVAL(p,usri11_last_logon,0); /* last logon */
3791 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3792 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3793 SSVALS(p,usri11_num_logons,-1); /* num logons */
3794 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3795 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3796 p2 = skip_string(*rdata,*rdata_len,p2);
3797 if (!p2) {
3798 return False;
3800 SSVAL(p,usri11_country_code,0); /* country code */
3802 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3803 strlcpy(p2,"",PTR_DIFF(endp,p2));
3804 p2 = skip_string(*rdata,*rdata_len,p2);
3805 if (!p2) {
3806 return False;
3809 SIVALS(p,usri11_max_storage,-1); /* max storage */
3810 SSVAL(p,usri11_units_per_week,168); /* units per week */
3811 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3813 /* a simple way to get logon hours at all times. */
3814 memset(p2,0xff,21);
3815 SCVAL(p2,21,0); /* fix zero termination */
3816 p2 = skip_string(*rdata,*rdata_len,p2);
3817 if (!p2) {
3818 return False;
3821 SSVAL(p,usri11_code_page,0); /* code page */
3824 if (uLevel == 1 || uLevel == 2) {
3825 memset(p+22,' ',16); /* password */
3826 SIVALS(p,38,-1); /* password age */
3827 SSVAL(p,42,
3828 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3829 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3830 strlcpy(p2, vuser ? pdb_get_homedir(
3831 vuser->server_info->sam_account) : "",
3832 PTR_DIFF(endp,p2));
3833 p2 = skip_string(*rdata,*rdata_len,p2);
3834 if (!p2) {
3835 return False;
3837 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3838 *p2++ = 0;
3839 SSVAL(p,52,0); /* flags */
3840 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3841 strlcpy(p2, vuser ? pdb_get_logon_script(
3842 vuser->server_info->sam_account) : "",
3843 PTR_DIFF(endp,p2));
3844 p2 = skip_string(*rdata,*rdata_len,p2);
3845 if (!p2) {
3846 return False;
3848 if (uLevel == 2) {
3849 SIVAL(p,60,0); /* auth_flags */
3850 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3851 strlcpy(p2,((vuser != NULL)
3852 ? pdb_get_fullname(vuser->server_info->sam_account)
3853 : UserName),PTR_DIFF(endp,p2));
3854 p2 = skip_string(*rdata,*rdata_len,p2);
3855 if (!p2) {
3856 return False;
3858 SIVAL(p,68,0); /* urs_comment */
3859 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3860 strlcpy(p2,"",PTR_DIFF(endp,p2));
3861 p2 = skip_string(*rdata,*rdata_len,p2);
3862 if (!p2) {
3863 return False;
3865 SIVAL(p,76,0); /* workstations */
3866 SIVAL(p,80,0); /* last_logon */
3867 SIVAL(p,84,0); /* last_logoff */
3868 SIVALS(p,88,-1); /* acct_expires */
3869 SIVALS(p,92,-1); /* max_storage */
3870 SSVAL(p,96,168); /* units_per_week */
3871 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3872 memset(p2,-1,21);
3873 p2 += 21;
3874 SSVALS(p,102,-1); /* bad_pw_count */
3875 SSVALS(p,104,-1); /* num_logons */
3876 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3878 TALLOC_CTX *ctx = talloc_tos();
3879 int space_rem = *rdata_len - (p2 - *rdata);
3880 char *tmp;
3882 if (space_rem <= 0) {
3883 return false;
3885 tmp = talloc_strdup(ctx, "\\\\%L");
3886 if (!tmp) {
3887 return false;
3889 tmp = talloc_sub_basic(ctx,
3892 tmp);
3893 if (!tmp) {
3894 return false;
3897 push_ascii(p2,
3898 tmp,
3899 space_rem,
3900 STR_TERMINATE);
3902 p2 = skip_string(*rdata,*rdata_len,p2);
3903 if (!p2) {
3904 return False;
3906 SSVAL(p,110,49); /* country_code */
3907 SSVAL(p,112,860); /* code page */
3911 *rdata_len = PTR_DIFF(p2,*rdata);
3913 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3915 return(True);
3918 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3919 char *param, int tpscnt,
3920 char *data, int tdscnt,
3921 int mdrcnt,int mprcnt,
3922 char **rdata,char **rparam,
3923 int *rdata_len,int *rparam_len)
3925 struct smbd_server_connection *sconn = smbd_server_conn;
3926 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3927 char *str2 = skip_string(param,tpscnt,str1);
3928 char *p = skip_string(param,tpscnt,str2);
3929 int uLevel;
3930 struct pack_desc desc;
3931 char* name;
3932 /* With share level security vuid will always be zero.
3933 Don't depend on vuser being non-null !!. JRA */
3934 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3936 if (!str1 || !str2 || !p) {
3937 return False;
3940 if(vuser != NULL) {
3941 DEBUG(3,(" Username of UID %d is %s\n",
3942 (int)vuser->server_info->utok.uid,
3943 vuser->server_info->unix_name));
3946 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3947 name = get_safe_str_ptr(param,tpscnt,p,2);
3948 if (!name) {
3949 return False;
3952 memset((char *)&desc,'\0',sizeof(desc));
3954 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3956 /* check it's a supported varient */
3957 if (strcmp(str1,"OOWb54WrLh") != 0) {
3958 return False;
3960 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3961 return False;
3963 if (mdrcnt > 0) {
3964 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3965 if (!*rdata) {
3966 return False;
3970 desc.base = *rdata;
3971 desc.buflen = mdrcnt;
3972 desc.subformat = NULL;
3973 desc.format = str2;
3975 if (init_package(&desc,1,0)) {
3976 PACKI(&desc,"W",0); /* code */
3977 PACKS(&desc,"B21",name); /* eff. name */
3978 PACKS(&desc,"B",""); /* pad */
3979 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3980 PACKI(&desc,"D",0); /* auth flags XXX */
3981 PACKI(&desc,"W",0); /* num logons */
3982 PACKI(&desc,"W",0); /* bad pw count */
3983 PACKI(&desc,"D",0); /* last logon */
3984 PACKI(&desc,"D",-1); /* last logoff */
3985 PACKI(&desc,"D",-1); /* logoff time */
3986 PACKI(&desc,"D",-1); /* kickoff time */
3987 PACKI(&desc,"D",0); /* password age */
3988 PACKI(&desc,"D",0); /* password can change */
3989 PACKI(&desc,"D",-1); /* password must change */
3992 fstring mypath;
3993 fstrcpy(mypath,"\\\\");
3994 fstrcat(mypath,get_local_machine_name());
3995 strupper_m(mypath);
3996 PACKS(&desc,"z",mypath); /* computer */
3999 PACKS(&desc,"z",lp_workgroup());/* domain */
4000 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
4001 vuser->server_info->sam_account) : ""); /* script path */
4002 PACKI(&desc,"D",0x00000000); /* reserved */
4005 *rdata_len = desc.usedlen;
4006 *rparam_len = 6;
4007 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4008 if (!*rparam) {
4009 return False;
4011 SSVALS(*rparam,0,desc.errcode);
4012 SSVAL(*rparam,2,0);
4013 SSVAL(*rparam,4,desc.neededlen);
4015 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
4017 return True;
4020 /****************************************************************************
4021 api_WAccessGetUserPerms
4022 ****************************************************************************/
4024 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
4025 char *param, int tpscnt,
4026 char *data, int tdscnt,
4027 int mdrcnt,int mprcnt,
4028 char **rdata,char **rparam,
4029 int *rdata_len,int *rparam_len)
4031 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4032 char *str2 = skip_string(param,tpscnt,str1);
4033 char *user = skip_string(param,tpscnt,str2);
4034 char *resource = skip_string(param,tpscnt,user);
4036 if (!str1 || !str2 || !user || !resource) {
4037 return False;
4040 if (skip_string(param,tpscnt,resource) == NULL) {
4041 return False;
4043 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
4045 /* check it's a supported varient */
4046 if (strcmp(str1,"zzh") != 0) {
4047 return False;
4049 if (strcmp(str2,"") != 0) {
4050 return False;
4053 *rparam_len = 6;
4054 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4055 if (!*rparam) {
4056 return False;
4058 SSVALS(*rparam,0,0); /* errorcode */
4059 SSVAL(*rparam,2,0); /* converter word */
4060 SSVAL(*rparam,4,0x7f); /* permission flags */
4062 return True;
4065 /****************************************************************************
4066 api_WPrintJobEnumerate
4067 ****************************************************************************/
4069 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
4070 char *param, int tpscnt,
4071 char *data, int tdscnt,
4072 int mdrcnt,int mprcnt,
4073 char **rdata,char **rparam,
4074 int *rdata_len,int *rparam_len)
4076 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4077 char *str2 = skip_string(param,tpscnt,str1);
4078 char *p = skip_string(param,tpscnt,str2);
4079 int uLevel;
4080 int count;
4081 int i;
4082 int snum;
4083 fstring sharename;
4084 uint32 jobid;
4085 struct pack_desc desc;
4086 print_queue_struct *queue=NULL;
4087 print_status_struct status;
4088 char *tmpdata=NULL;
4090 if (!str1 || !str2 || !p) {
4091 return False;
4094 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
4096 memset((char *)&desc,'\0',sizeof(desc));
4097 memset((char *)&status,'\0',sizeof(status));
4099 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
4101 /* check it's a supported varient */
4102 if (strcmp(str1,"WWrLh") != 0) {
4103 return False;
4105 if (!check_printjob_info(&desc,uLevel,str2)) {
4106 return False;
4109 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
4110 return False;
4113 snum = lp_servicenumber( sharename);
4114 if (snum < 0 || !VALID_SNUM(snum)) {
4115 return(False);
4118 count = print_queue_status(snum,&queue,&status);
4119 for (i = 0; i < count; i++) {
4120 if (queue[i].job == jobid) {
4121 break;
4125 if (mdrcnt > 0) {
4126 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4127 if (!*rdata) {
4128 return False;
4130 desc.base = *rdata;
4131 desc.buflen = mdrcnt;
4132 } else {
4134 * Don't return data but need to get correct length
4135 * init_package will return wrong size if buflen=0
4137 desc.buflen = getlen(desc.format);
4138 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4141 if (init_package(&desc,1,0)) {
4142 if (i < count) {
4143 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4144 *rdata_len = desc.usedlen;
4145 } else {
4146 desc.errcode = NERR_JobNotFound;
4147 *rdata_len = 0;
4151 *rparam_len = 6;
4152 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4153 if (!*rparam) {
4154 return False;
4156 SSVALS(*rparam,0,desc.errcode);
4157 SSVAL(*rparam,2,0);
4158 SSVAL(*rparam,4,desc.neededlen);
4160 SAFE_FREE(queue);
4161 SAFE_FREE(tmpdata);
4163 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
4165 return True;
4168 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
4169 char *param, int tpscnt,
4170 char *data, int tdscnt,
4171 int mdrcnt,int mprcnt,
4172 char **rdata,char **rparam,
4173 int *rdata_len,int *rparam_len)
4175 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4176 char *str2 = skip_string(param,tpscnt,str1);
4177 char *p = skip_string(param,tpscnt,str2);
4178 char *name = p;
4179 int uLevel;
4180 int count;
4181 int i, succnt=0;
4182 int snum;
4183 struct pack_desc desc;
4184 print_queue_struct *queue=NULL;
4185 print_status_struct status;
4187 if (!str1 || !str2 || !p) {
4188 return False;
4191 memset((char *)&desc,'\0',sizeof(desc));
4192 memset((char *)&status,'\0',sizeof(status));
4194 p = skip_string(param,tpscnt,p);
4195 if (!p) {
4196 return False;
4198 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4200 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
4202 /* check it's a supported variant */
4203 if (strcmp(str1,"zWrLeh") != 0) {
4204 return False;
4207 if (uLevel > 2) {
4208 return False; /* defined only for uLevel 0,1,2 */
4211 if (!check_printjob_info(&desc,uLevel,str2)) {
4212 return False;
4215 snum = find_service(name);
4216 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4217 return False;
4220 count = print_queue_status(snum,&queue,&status);
4221 if (mdrcnt > 0) {
4222 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4223 if (!*rdata) {
4224 return False;
4227 desc.base = *rdata;
4228 desc.buflen = mdrcnt;
4230 if (init_package(&desc,count,0)) {
4231 succnt = 0;
4232 for (i = 0; i < count; i++) {
4233 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4234 if (desc.errcode == NERR_Success) {
4235 succnt = i+1;
4240 *rdata_len = desc.usedlen;
4242 *rparam_len = 8;
4243 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4244 if (!*rparam) {
4245 return False;
4247 SSVALS(*rparam,0,desc.errcode);
4248 SSVAL(*rparam,2,0);
4249 SSVAL(*rparam,4,succnt);
4250 SSVAL(*rparam,6,count);
4252 SAFE_FREE(queue);
4254 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4256 return True;
4259 static int check_printdest_info(struct pack_desc* desc,
4260 int uLevel, char* id)
4262 desc->subformat = NULL;
4263 switch( uLevel ) {
4264 case 0:
4265 desc->format = "B9";
4266 break;
4267 case 1:
4268 desc->format = "B9B21WWzW";
4269 break;
4270 case 2:
4271 desc->format = "z";
4272 break;
4273 case 3:
4274 desc->format = "zzzWWzzzWW";
4275 break;
4276 default:
4277 DEBUG(0,("check_printdest_info: invalid level %d\n",
4278 uLevel));
4279 return False;
4281 if (id == NULL || strcmp(desc->format,id) != 0) {
4282 DEBUG(0,("check_printdest_info: invalid string %s\n",
4283 id ? id : "<NULL>" ));
4284 return False;
4286 return True;
4289 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4290 struct pack_desc* desc)
4292 char buf[100];
4294 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4295 buf[sizeof(buf)-1] = 0;
4296 strupper_m(buf);
4298 if (uLevel <= 1) {
4299 PACKS(desc,"B9",buf); /* szName */
4300 if (uLevel == 1) {
4301 PACKS(desc,"B21",""); /* szUserName */
4302 PACKI(desc,"W",0); /* uJobId */
4303 PACKI(desc,"W",0); /* fsStatus */
4304 PACKS(desc,"z",""); /* pszStatus */
4305 PACKI(desc,"W",0); /* time */
4309 if (uLevel == 2 || uLevel == 3) {
4310 PACKS(desc,"z",buf); /* pszPrinterName */
4311 if (uLevel == 3) {
4312 PACKS(desc,"z",""); /* pszUserName */
4313 PACKS(desc,"z",""); /* pszLogAddr */
4314 PACKI(desc,"W",0); /* uJobId */
4315 PACKI(desc,"W",0); /* fsStatus */
4316 PACKS(desc,"z",""); /* pszStatus */
4317 PACKS(desc,"z",""); /* pszComment */
4318 PACKS(desc,"z","NULL"); /* pszDrivers */
4319 PACKI(desc,"W",0); /* time */
4320 PACKI(desc,"W",0); /* pad1 */
4325 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4326 char *param, int tpscnt,
4327 char *data, int tdscnt,
4328 int mdrcnt,int mprcnt,
4329 char **rdata,char **rparam,
4330 int *rdata_len,int *rparam_len)
4332 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4333 char *str2 = skip_string(param,tpscnt,str1);
4334 char *p = skip_string(param,tpscnt,str2);
4335 char* PrinterName = p;
4336 int uLevel;
4337 struct pack_desc desc;
4338 int snum;
4339 char *tmpdata=NULL;
4341 if (!str1 || !str2 || !p) {
4342 return False;
4345 memset((char *)&desc,'\0',sizeof(desc));
4347 p = skip_string(param,tpscnt,p);
4348 if (!p) {
4349 return False;
4351 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4353 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4355 /* check it's a supported varient */
4356 if (strcmp(str1,"zWrLh") != 0) {
4357 return False;
4359 if (!check_printdest_info(&desc,uLevel,str2)) {
4360 return False;
4363 snum = find_service(PrinterName);
4364 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4365 *rdata_len = 0;
4366 desc.errcode = NERR_DestNotFound;
4367 desc.neededlen = 0;
4368 } else {
4369 if (mdrcnt > 0) {
4370 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4371 if (!*rdata) {
4372 return False;
4374 desc.base = *rdata;
4375 desc.buflen = mdrcnt;
4376 } else {
4378 * Don't return data but need to get correct length
4379 * init_package will return wrong size if buflen=0
4381 desc.buflen = getlen(desc.format);
4382 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4384 if (init_package(&desc,1,0)) {
4385 fill_printdest_info(conn,snum,uLevel,&desc);
4387 *rdata_len = desc.usedlen;
4390 *rparam_len = 6;
4391 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4392 if (!*rparam) {
4393 return False;
4395 SSVALS(*rparam,0,desc.errcode);
4396 SSVAL(*rparam,2,0);
4397 SSVAL(*rparam,4,desc.neededlen);
4399 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4400 SAFE_FREE(tmpdata);
4402 return True;
4405 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4406 char *param, int tpscnt,
4407 char *data, int tdscnt,
4408 int mdrcnt,int mprcnt,
4409 char **rdata,char **rparam,
4410 int *rdata_len,int *rparam_len)
4412 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4413 char *str2 = skip_string(param,tpscnt,str1);
4414 char *p = skip_string(param,tpscnt,str2);
4415 int uLevel;
4416 int queuecnt;
4417 int i, n, succnt=0;
4418 struct pack_desc desc;
4419 int services = lp_numservices();
4421 if (!str1 || !str2 || !p) {
4422 return False;
4425 memset((char *)&desc,'\0',sizeof(desc));
4427 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4429 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4431 /* check it's a supported varient */
4432 if (strcmp(str1,"WrLeh") != 0) {
4433 return False;
4435 if (!check_printdest_info(&desc,uLevel,str2)) {
4436 return False;
4439 queuecnt = 0;
4440 for (i = 0; i < services; i++) {
4441 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4442 queuecnt++;
4446 if (mdrcnt > 0) {
4447 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4448 if (!*rdata) {
4449 return False;
4453 desc.base = *rdata;
4454 desc.buflen = mdrcnt;
4455 if (init_package(&desc,queuecnt,0)) {
4456 succnt = 0;
4457 n = 0;
4458 for (i = 0; i < services; i++) {
4459 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4460 fill_printdest_info(conn,i,uLevel,&desc);
4461 n++;
4462 if (desc.errcode == NERR_Success) {
4463 succnt = n;
4469 *rdata_len = desc.usedlen;
4471 *rparam_len = 8;
4472 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4473 if (!*rparam) {
4474 return False;
4476 SSVALS(*rparam,0,desc.errcode);
4477 SSVAL(*rparam,2,0);
4478 SSVAL(*rparam,4,succnt);
4479 SSVAL(*rparam,6,queuecnt);
4481 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4483 return True;
4486 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4487 char *param, int tpscnt,
4488 char *data, int tdscnt,
4489 int mdrcnt,int mprcnt,
4490 char **rdata,char **rparam,
4491 int *rdata_len,int *rparam_len)
4493 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4494 char *str2 = skip_string(param,tpscnt,str1);
4495 char *p = skip_string(param,tpscnt,str2);
4496 int uLevel;
4497 int succnt;
4498 struct pack_desc desc;
4500 if (!str1 || !str2 || !p) {
4501 return False;
4504 memset((char *)&desc,'\0',sizeof(desc));
4506 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4508 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4510 /* check it's a supported varient */
4511 if (strcmp(str1,"WrLeh") != 0) {
4512 return False;
4514 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4515 return False;
4518 if (mdrcnt > 0) {
4519 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4520 if (!*rdata) {
4521 return False;
4524 desc.base = *rdata;
4525 desc.buflen = mdrcnt;
4526 if (init_package(&desc,1,0)) {
4527 PACKS(&desc,"B41","NULL");
4530 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4532 *rdata_len = desc.usedlen;
4534 *rparam_len = 8;
4535 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4536 if (!*rparam) {
4537 return False;
4539 SSVALS(*rparam,0,desc.errcode);
4540 SSVAL(*rparam,2,0);
4541 SSVAL(*rparam,4,succnt);
4542 SSVAL(*rparam,6,1);
4544 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4546 return True;
4549 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4550 char *param, int tpscnt,
4551 char *data, int tdscnt,
4552 int mdrcnt,int mprcnt,
4553 char **rdata,char **rparam,
4554 int *rdata_len,int *rparam_len)
4556 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4557 char *str2 = skip_string(param,tpscnt,str1);
4558 char *p = skip_string(param,tpscnt,str2);
4559 int uLevel;
4560 int succnt;
4561 struct pack_desc desc;
4563 if (!str1 || !str2 || !p) {
4564 return False;
4566 memset((char *)&desc,'\0',sizeof(desc));
4568 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4570 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4572 /* check it's a supported varient */
4573 if (strcmp(str1,"WrLeh") != 0) {
4574 return False;
4576 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4577 return False;
4580 if (mdrcnt > 0) {
4581 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4582 if (!*rdata) {
4583 return False;
4586 desc.base = *rdata;
4587 desc.buflen = mdrcnt;
4588 desc.format = str2;
4589 if (init_package(&desc,1,0)) {
4590 PACKS(&desc,"B13","lpd");
4593 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4595 *rdata_len = desc.usedlen;
4597 *rparam_len = 8;
4598 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4599 if (!*rparam) {
4600 return False;
4602 SSVALS(*rparam,0,desc.errcode);
4603 SSVAL(*rparam,2,0);
4604 SSVAL(*rparam,4,succnt);
4605 SSVAL(*rparam,6,1);
4607 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4609 return True;
4612 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4613 char *param, int tpscnt,
4614 char *data, int tdscnt,
4615 int mdrcnt,int mprcnt,
4616 char **rdata,char **rparam,
4617 int *rdata_len,int *rparam_len)
4619 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4620 char *str2 = skip_string(param,tpscnt,str1);
4621 char *p = skip_string(param,tpscnt,str2);
4622 int uLevel;
4623 int succnt;
4624 struct pack_desc desc;
4626 if (!str1 || !str2 || !p) {
4627 return False;
4630 memset((char *)&desc,'\0',sizeof(desc));
4632 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4634 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4636 /* check it's a supported varient */
4637 if (strcmp(str1,"WrLeh") != 0) {
4638 return False;
4640 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4641 return False;
4644 if (mdrcnt > 0) {
4645 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4646 if (!*rdata) {
4647 return False;
4650 memset((char *)&desc,'\0',sizeof(desc));
4651 desc.base = *rdata;
4652 desc.buflen = mdrcnt;
4653 desc.format = str2;
4654 if (init_package(&desc,1,0)) {
4655 PACKS(&desc,"B13","lp0");
4658 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4660 *rdata_len = desc.usedlen;
4662 *rparam_len = 8;
4663 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4664 if (!*rparam) {
4665 return False;
4667 SSVALS(*rparam,0,desc.errcode);
4668 SSVAL(*rparam,2,0);
4669 SSVAL(*rparam,4,succnt);
4670 SSVAL(*rparam,6,1);
4672 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4674 return True;
4677 /****************************************************************************
4678 List open sessions
4679 ****************************************************************************/
4681 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4682 char *param, int tpscnt,
4683 char *data, int tdscnt,
4684 int mdrcnt,int mprcnt,
4685 char **rdata,char **rparam,
4686 int *rdata_len,int *rparam_len)
4689 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4690 char *str2 = skip_string(param,tpscnt,str1);
4691 char *p = skip_string(param,tpscnt,str2);
4692 int uLevel;
4693 struct pack_desc desc;
4694 struct sessionid *session_list;
4695 int i, num_sessions;
4697 if (!str1 || !str2 || !p) {
4698 return False;
4701 memset((char *)&desc,'\0',sizeof(desc));
4703 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4705 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4706 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4707 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4709 /* check it's a supported varient */
4710 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4711 return False;
4713 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4714 return False;
4717 num_sessions = list_sessions(talloc_tos(), &session_list);
4719 if (mdrcnt > 0) {
4720 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4721 if (!*rdata) {
4722 return False;
4725 memset((char *)&desc,'\0',sizeof(desc));
4726 desc.base = *rdata;
4727 desc.buflen = mdrcnt;
4728 desc.format = str2;
4729 if (!init_package(&desc,num_sessions,0)) {
4730 return False;
4733 for(i=0; i<num_sessions; i++) {
4734 PACKS(&desc, "z", session_list[i].remote_machine);
4735 PACKS(&desc, "z", session_list[i].username);
4736 PACKI(&desc, "W", 1); /* num conns */
4737 PACKI(&desc, "W", 0); /* num opens */
4738 PACKI(&desc, "W", 1); /* num users */
4739 PACKI(&desc, "D", 0); /* session time */
4740 PACKI(&desc, "D", 0); /* idle time */
4741 PACKI(&desc, "D", 0); /* flags */
4742 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4745 *rdata_len = desc.usedlen;
4747 *rparam_len = 8;
4748 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4749 if (!*rparam) {
4750 return False;
4752 SSVALS(*rparam,0,desc.errcode);
4753 SSVAL(*rparam,2,0); /* converter */
4754 SSVAL(*rparam,4,num_sessions); /* count */
4756 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4758 return True;
4762 /****************************************************************************
4763 The buffer was too small.
4764 ****************************************************************************/
4766 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4767 int mdrcnt, int mprcnt,
4768 char **rdata, char **rparam,
4769 int *rdata_len, int *rparam_len)
4771 *rparam_len = MIN(*rparam_len,mprcnt);
4772 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4773 if (!*rparam) {
4774 return False;
4777 *rdata_len = 0;
4779 SSVAL(*rparam,0,NERR_BufTooSmall);
4781 DEBUG(3,("Supplied buffer too small in API command\n"));
4783 return True;
4786 /****************************************************************************
4787 The request is not supported.
4788 ****************************************************************************/
4790 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4791 char *param, int tpscnt,
4792 char *data, int tdscnt,
4793 int mdrcnt, int mprcnt,
4794 char **rdata, char **rparam,
4795 int *rdata_len, int *rparam_len)
4797 *rparam_len = 4;
4798 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4799 if (!*rparam) {
4800 return False;
4803 *rdata_len = 0;
4805 SSVAL(*rparam,0,NERR_notsupported);
4806 SSVAL(*rparam,2,0); /* converter word */
4808 DEBUG(3,("Unsupported API command\n"));
4810 return True;
4813 static const struct {
4814 const char *name;
4815 int id;
4816 bool (*fn)(connection_struct *, uint16,
4817 char *, int,
4818 char *, int,
4819 int,int,char **,char **,int *,int *);
4820 bool auth_user; /* Deny anonymous access? */
4821 } api_commands[] = {
4822 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4823 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4824 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4825 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4826 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4827 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4828 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4829 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4830 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4831 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4832 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4833 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4834 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4835 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4836 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4837 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4838 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4839 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4840 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4841 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4842 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4843 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4844 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4845 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4846 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
4847 {"NetServerEnum3", RAP_NetServerEnum3, api_RNetServerEnum3}, /* anon OK */
4848 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4849 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4850 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4851 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4852 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4853 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4854 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4855 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4856 {NULL, -1, api_Unsupported}
4857 /* The following RAP calls are not implemented by Samba:
4859 RAP_WFileEnum2 - anon not OK
4864 /****************************************************************************
4865 Handle remote api calls.
4866 ****************************************************************************/
4868 void api_reply(connection_struct *conn, uint16 vuid,
4869 struct smb_request *req,
4870 char *data, char *params,
4871 int tdscnt, int tpscnt,
4872 int mdrcnt, int mprcnt)
4874 struct smbd_server_connection *sconn = smbd_server_conn;
4875 int api_command;
4876 char *rdata = NULL;
4877 char *rparam = NULL;
4878 const char *name1 = NULL;
4879 const char *name2 = NULL;
4880 int rdata_len = 0;
4881 int rparam_len = 0;
4882 bool reply=False;
4883 int i;
4885 if (!params) {
4886 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4887 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4888 return;
4891 if (tpscnt < 2) {
4892 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4893 return;
4895 api_command = SVAL(params,0);
4896 /* Is there a string at position params+2 ? */
4897 if (skip_string(params,tpscnt,params+2)) {
4898 name1 = params + 2;
4899 } else {
4900 name1 = "";
4902 name2 = skip_string(params,tpscnt,params+2);
4903 if (!name2) {
4904 name2 = "";
4907 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4908 api_command,
4909 name1,
4910 name2,
4911 tdscnt,tpscnt,mdrcnt,mprcnt));
4913 for (i=0;api_commands[i].name;i++) {
4914 if (api_commands[i].id == api_command && api_commands[i].fn) {
4915 DEBUG(3,("Doing %s\n",api_commands[i].name));
4916 break;
4920 /* Check whether this api call can be done anonymously */
4922 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4923 user_struct *user = get_valid_user_struct(sconn, vuid);
4925 if (!user || user->server_info->guest) {
4926 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4927 return;
4931 rdata = (char *)SMB_MALLOC(1024);
4932 if (rdata) {
4933 memset(rdata,'\0',1024);
4936 rparam = (char *)SMB_MALLOC(1024);
4937 if (rparam) {
4938 memset(rparam,'\0',1024);
4941 if(!rdata || !rparam) {
4942 DEBUG(0,("api_reply: malloc fail !\n"));
4943 SAFE_FREE(rdata);
4944 SAFE_FREE(rparam);
4945 reply_nterror(req, NT_STATUS_NO_MEMORY);
4946 return;
4949 reply = api_commands[i].fn(conn,
4950 vuid,
4951 params,tpscnt, /* params + length */
4952 data,tdscnt, /* data + length */
4953 mdrcnt,mprcnt,
4954 &rdata,&rparam,&rdata_len,&rparam_len);
4957 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4958 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4959 &rdata,&rparam,&rdata_len,&rparam_len);
4962 /* if we get False back then it's actually unsupported */
4963 if (!reply) {
4964 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4965 &rdata,&rparam,&rdata_len,&rparam_len);
4968 /* If api_Unsupported returns false we can't return anything. */
4969 if (reply) {
4970 send_trans_reply(conn, req, rparam, rparam_len,
4971 rdata, rdata_len, False);
4974 SAFE_FREE(rdata);
4975 SAFE_FREE(rparam);
4976 return;