s3:smbd: add/improve some DEBUG messages in api_RNetServerEnum2()
[Samba/cd1.git] / source3 / smbd / lanman.c
blobc3c30f535ffc5e7b41c5ce3b76079fa0cf442163
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"
33 #ifdef CHECK_TYPES
34 #undef CHECK_TYPES
35 #endif
36 #define CHECK_TYPES 0
38 #define NERR_Success 0
39 #define NERR_badpass 86
40 #define NERR_notsupported 50
42 #define NERR_BASE (2100)
43 #define NERR_BufTooSmall (NERR_BASE+23)
44 #define NERR_JobNotFound (NERR_BASE+51)
45 #define NERR_DestNotFound (NERR_BASE+52)
47 #define ACCESS_READ 0x01
48 #define ACCESS_WRITE 0x02
49 #define ACCESS_CREATE 0x04
51 #define SHPWLEN 8 /* share password length */
53 /* Limit size of ipc replies */
55 static char *smb_realloc_limit(void *ptr, size_t size)
57 char *val;
59 size = MAX((size),4*1024);
60 val = (char *)SMB_REALLOC(ptr,size);
61 if (val) {
62 memset(val,'\0',size);
64 return val;
67 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
68 char *param, int tpscnt,
69 char *data, int tdscnt,
70 int mdrcnt, int mprcnt,
71 char **rdata, char **rparam,
72 int *rdata_len, int *rparam_len);
74 static bool api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
75 int mdrcnt, int mprcnt,
76 char **rdata, char **rparam,
77 int *rdata_len, int *rparam_len);
80 static int CopyExpanded(connection_struct *conn,
81 int snum, char **dst, char *src, int *p_space_remaining)
83 TALLOC_CTX *ctx = talloc_tos();
84 char *buf = NULL;
85 int l;
87 if (!src || !dst || !p_space_remaining || !(*dst) ||
88 *p_space_remaining <= 0) {
89 return 0;
92 buf = talloc_strdup(ctx, src);
93 if (!buf) {
94 *p_space_remaining = 0;
95 return 0;
97 buf = talloc_string_sub(ctx, buf,"%S",lp_servicename(snum));
98 if (!buf) {
99 *p_space_remaining = 0;
100 return 0;
102 buf = talloc_sub_advanced(ctx,
103 lp_servicename(SNUM(conn)),
104 conn->server_info->unix_name,
105 conn->connectpath,
106 conn->server_info->utok.gid,
107 conn->server_info->sanitized_username,
108 pdb_get_domain(conn->server_info->sam_account),
109 buf);
110 if (!buf) {
111 *p_space_remaining = 0;
112 return 0;
114 l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE);
115 if (l == -1) {
116 return 0;
118 (*dst) += l;
119 (*p_space_remaining) -= l;
120 return l;
123 static int CopyAndAdvance(char **dst, char *src, int *n)
125 int l;
126 if (!src || !dst || !n || !(*dst)) {
127 return 0;
129 l = push_ascii(*dst,src,*n, STR_TERMINATE);
130 if (l == -1) {
131 return 0;
133 (*dst) += l;
134 (*n) -= l;
135 return l;
138 static int StrlenExpanded(connection_struct *conn, int snum, char *s)
140 TALLOC_CTX *ctx = talloc_tos();
141 char *buf = NULL;
142 if (!s) {
143 return 0;
145 buf = talloc_strdup(ctx,s);
146 if (!buf) {
147 return 0;
149 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
150 if (!buf) {
151 return 0;
153 buf = talloc_sub_advanced(ctx,
154 lp_servicename(SNUM(conn)),
155 conn->server_info->unix_name,
156 conn->connectpath,
157 conn->server_info->utok.gid,
158 conn->server_info->sanitized_username,
159 pdb_get_domain(conn->server_info->sam_account),
160 buf);
161 if (!buf) {
162 return 0;
164 return strlen(buf) + 1;
167 static char *Expand(connection_struct *conn, int snum, char *s)
169 TALLOC_CTX *ctx = talloc_tos();
170 char *buf = NULL;
172 if (!s) {
173 return NULL;
175 buf = talloc_strdup(ctx,s);
176 if (!buf) {
177 return 0;
179 buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(snum));
180 if (!buf) {
181 return 0;
183 return talloc_sub_advanced(ctx,
184 lp_servicename(SNUM(conn)),
185 conn->server_info->unix_name,
186 conn->connectpath,
187 conn->server_info->utok.gid,
188 conn->server_info->sanitized_username,
189 pdb_get_domain(conn->server_info->sam_account),
190 buf);
193 /*******************************************************************
194 Check a API string for validity when we only need to check the prefix.
195 ******************************************************************/
197 static bool prefix_ok(const char *str, const char *prefix)
199 return(strncmp(str,prefix,strlen(prefix)) == 0);
202 struct pack_desc {
203 const char *format; /* formatstring for structure */
204 const char *subformat; /* subformat for structure */
205 char *base; /* baseaddress of buffer */
206 int buflen; /* remaining size for fixed part; on init: length of base */
207 int subcount; /* count of substructures */
208 char *structbuf; /* pointer into buffer for remaining fixed part */
209 int stringlen; /* remaining size for variable part */
210 char *stringbuf; /* pointer into buffer for remaining variable part */
211 int neededlen; /* total needed size */
212 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
213 const char *curpos; /* current position; pointer into format or subformat */
214 int errcode;
217 static int get_counter(const char **p)
219 int i, n;
220 if (!p || !(*p)) {
221 return 1;
223 if (!isdigit((int)**p)) {
224 return 1;
226 for (n = 0;;) {
227 i = **p;
228 if (isdigit(i)) {
229 n = 10 * n + (i - '0');
230 } else {
231 return n;
233 (*p)++;
237 static int getlen(const char *p)
239 int n = 0;
240 if (!p) {
241 return 0;
244 while (*p) {
245 switch( *p++ ) {
246 case 'W': /* word (2 byte) */
247 n += 2;
248 break;
249 case 'K': /* status word? (2 byte) */
250 n += 2;
251 break;
252 case 'N': /* count of substructures (word) at end */
253 n += 2;
254 break;
255 case 'D': /* double word (4 byte) */
256 case 'z': /* offset to zero terminated string (4 byte) */
257 case 'l': /* offset to user data (4 byte) */
258 n += 4;
259 break;
260 case 'b': /* offset to data (with counter) (4 byte) */
261 n += 4;
262 get_counter(&p);
263 break;
264 case 'B': /* byte (with optional counter) */
265 n += get_counter(&p);
266 break;
269 return n;
272 static bool init_package(struct pack_desc *p, int count, int subcount)
274 int n = p->buflen;
275 int i;
277 if (!p->format || !p->base) {
278 return False;
281 i = count * getlen(p->format);
282 if (p->subformat) {
283 i += subcount * getlen(p->subformat);
285 p->structbuf = p->base;
286 p->neededlen = 0;
287 p->usedlen = 0;
288 p->subcount = 0;
289 p->curpos = p->format;
290 if (i > n) {
291 p->neededlen = i;
292 i = n = 0;
293 #if 0
295 * This is the old error code we used. Aparently
296 * WinNT/2k systems return ERRbuftoosmall (2123) and
297 * OS/2 needs this. I'm leaving this here so we can revert
298 * if needed. JRA.
300 p->errcode = ERRmoredata;
301 #else
302 p->errcode = ERRbuftoosmall;
303 #endif
304 } else {
305 p->errcode = NERR_Success;
307 p->buflen = i;
308 n -= i;
309 p->stringbuf = p->base + i;
310 p->stringlen = n;
311 return (p->errcode == NERR_Success);
314 static int package(struct pack_desc *p, ...)
316 va_list args;
317 int needed=0, stringneeded;
318 const char *str=NULL;
319 int is_string=0, stringused;
320 int32 temp;
322 va_start(args,p);
324 if (!*p->curpos) {
325 if (!p->subcount) {
326 p->curpos = p->format;
327 } else {
328 p->curpos = p->subformat;
329 p->subcount--;
332 #if CHECK_TYPES
333 str = va_arg(args,char*);
334 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
335 #endif
336 stringneeded = -1;
338 if (!p->curpos) {
339 va_end(args);
340 return 0;
343 switch( *p->curpos++ ) {
344 case 'W': /* word (2 byte) */
345 needed = 2;
346 temp = va_arg(args,int);
347 if (p->buflen >= needed) {
348 SSVAL(p->structbuf,0,temp);
350 break;
351 case 'K': /* status word? (2 byte) */
352 needed = 2;
353 temp = va_arg(args,int);
354 if (p->buflen >= needed) {
355 SSVAL(p->structbuf,0,temp);
357 break;
358 case 'N': /* count of substructures (word) at end */
359 needed = 2;
360 p->subcount = va_arg(args,int);
361 if (p->buflen >= needed) {
362 SSVAL(p->structbuf,0,p->subcount);
364 break;
365 case 'D': /* double word (4 byte) */
366 needed = 4;
367 temp = va_arg(args,int);
368 if (p->buflen >= needed) {
369 SIVAL(p->structbuf,0,temp);
371 break;
372 case 'B': /* byte (with optional counter) */
373 needed = get_counter(&p->curpos);
375 char *s = va_arg(args,char*);
376 if (p->buflen >= needed) {
377 StrnCpy(p->structbuf,s?s:"",needed-1);
380 break;
381 case 'z': /* offset to zero terminated string (4 byte) */
382 str = va_arg(args,char*);
383 stringneeded = (str ? strlen(str)+1 : 0);
384 is_string = 1;
385 break;
386 case 'l': /* offset to user data (4 byte) */
387 str = va_arg(args,char*);
388 stringneeded = va_arg(args,int);
389 is_string = 0;
390 break;
391 case 'b': /* offset to data (with counter) (4 byte) */
392 str = va_arg(args,char*);
393 stringneeded = get_counter(&p->curpos);
394 is_string = 0;
395 break;
398 va_end(args);
399 if (stringneeded >= 0) {
400 needed = 4;
401 if (p->buflen >= needed) {
402 stringused = stringneeded;
403 if (stringused > p->stringlen) {
404 stringused = (is_string ? p->stringlen : 0);
405 if (p->errcode == NERR_Success) {
406 p->errcode = ERRmoredata;
409 if (!stringused) {
410 SIVAL(p->structbuf,0,0);
411 } else {
412 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
413 memcpy(p->stringbuf,str?str:"",stringused);
414 if (is_string) {
415 p->stringbuf[stringused-1] = '\0';
417 p->stringbuf += stringused;
418 p->stringlen -= stringused;
419 p->usedlen += stringused;
422 p->neededlen += stringneeded;
425 p->neededlen += needed;
426 if (p->buflen >= needed) {
427 p->structbuf += needed;
428 p->buflen -= needed;
429 p->usedlen += needed;
430 } else {
431 if (p->errcode == NERR_Success) {
432 p->errcode = ERRmoredata;
435 return 1;
438 #if CHECK_TYPES
439 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
440 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
441 #else
442 #define PACK(desc,t,v) package(desc,v)
443 #define PACKl(desc,t,v,l) package(desc,v,l)
444 #endif
446 static void PACKI(struct pack_desc* desc, const char *t,int v)
448 PACK(desc,t,v);
451 static void PACKS(struct pack_desc* desc,const char *t,const char *v)
453 PACK(desc,t,v);
456 /****************************************************************************
457 Get a print queue.
458 ****************************************************************************/
460 static void PackDriverData(struct pack_desc* desc)
462 char drivdata[4+4+32];
463 SIVAL(drivdata,0,sizeof drivdata); /* cb */
464 SIVAL(drivdata,4,1000); /* lVersion */
465 memset(drivdata+8,0,32); /* szDeviceName */
466 push_ascii(drivdata+8,"NULL",32, STR_TERMINATE);
467 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
470 static int check_printq_info(struct pack_desc* desc,
471 unsigned int uLevel, char *id1, char *id2)
473 desc->subformat = NULL;
474 switch( uLevel ) {
475 case 0:
476 desc->format = "B13";
477 break;
478 case 1:
479 desc->format = "B13BWWWzzzzzWW";
480 break;
481 case 2:
482 desc->format = "B13BWWWzzzzzWN";
483 desc->subformat = "WB21BB16B10zWWzDDz";
484 break;
485 case 3:
486 desc->format = "zWWWWzzzzWWzzl";
487 break;
488 case 4:
489 desc->format = "zWWWWzzzzWNzzl";
490 desc->subformat = "WWzWWDDzz";
491 break;
492 case 5:
493 desc->format = "z";
494 break;
495 case 51:
496 desc->format = "K";
497 break;
498 case 52:
499 desc->format = "WzzzzzzzzN";
500 desc->subformat = "z";
501 break;
502 default:
503 DEBUG(0,("check_printq_info: invalid level %d\n",
504 uLevel ));
505 return False;
507 if (id1 == NULL || strcmp(desc->format,id1) != 0) {
508 DEBUG(0,("check_printq_info: invalid format %s\n",
509 id1 ? id1 : "<NULL>" ));
510 return False;
512 if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) {
513 DEBUG(0,("check_printq_info: invalid subformat %s\n",
514 id2 ? id2 : "<NULL>" ));
515 return False;
517 return True;
521 #define RAP_JOB_STATUS_QUEUED 0
522 #define RAP_JOB_STATUS_PAUSED 1
523 #define RAP_JOB_STATUS_SPOOLING 2
524 #define RAP_JOB_STATUS_PRINTING 3
525 #define RAP_JOB_STATUS_PRINTED 4
527 #define RAP_QUEUE_STATUS_PAUSED 1
528 #define RAP_QUEUE_STATUS_ERROR 2
530 /* turn a print job status into a on the wire status
532 static int printj_status(int v)
534 switch (v) {
535 case LPQ_QUEUED:
536 return RAP_JOB_STATUS_QUEUED;
537 case LPQ_PAUSED:
538 return RAP_JOB_STATUS_PAUSED;
539 case LPQ_SPOOLING:
540 return RAP_JOB_STATUS_SPOOLING;
541 case LPQ_PRINTING:
542 return RAP_JOB_STATUS_PRINTING;
544 return 0;
547 /* turn a print queue status into a on the wire status
549 static int printq_status(int v)
551 switch (v) {
552 case LPQ_QUEUED:
553 return 0;
554 case LPQ_PAUSED:
555 return RAP_QUEUE_STATUS_PAUSED;
557 return RAP_QUEUE_STATUS_ERROR;
560 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
561 struct pack_desc *desc,
562 print_queue_struct *queue, int n)
564 time_t t = queue->time;
566 /* the client expects localtime */
567 t -= get_time_zone(t);
569 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
570 if (uLevel == 1) {
571 PACKS(desc,"B21",queue->fs_user); /* szUserName */
572 PACKS(desc,"B",""); /* pad */
573 PACKS(desc,"B16",""); /* szNotifyName */
574 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
575 PACKS(desc,"z",""); /* pszParms */
576 PACKI(desc,"W",n+1); /* uPosition */
577 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
578 PACKS(desc,"z",""); /* pszStatus */
579 PACKI(desc,"D",t); /* ulSubmitted */
580 PACKI(desc,"D",queue->size); /* ulSize */
581 PACKS(desc,"z",queue->fs_file); /* pszComment */
583 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
584 PACKI(desc,"W",queue->priority); /* uPriority */
585 PACKS(desc,"z",queue->fs_user); /* pszUserName */
586 PACKI(desc,"W",n+1); /* uPosition */
587 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
588 PACKI(desc,"D",t); /* ulSubmitted */
589 PACKI(desc,"D",queue->size); /* ulSize */
590 PACKS(desc,"z","Samba"); /* pszComment */
591 PACKS(desc,"z",queue->fs_file); /* pszDocument */
592 if (uLevel == 3) {
593 PACKS(desc,"z",""); /* pszNotifyName */
594 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
595 PACKS(desc,"z",""); /* pszParms */
596 PACKS(desc,"z",""); /* pszStatus */
597 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
598 PACKS(desc,"z","lpd"); /* pszQProcName */
599 PACKS(desc,"z",""); /* pszQProcParms */
600 PACKS(desc,"z","NULL"); /* pszDriverName */
601 PackDriverData(desc); /* pDriverData */
602 PACKS(desc,"z",""); /* pszPrinterName */
603 } else if (uLevel == 4) { /* OS2 */
604 PACKS(desc,"z",""); /* pszSpoolFileName */
605 PACKS(desc,"z",""); /* pszPortName */
606 PACKS(desc,"z",""); /* pszStatus */
607 PACKI(desc,"D",0); /* ulPagesSpooled */
608 PACKI(desc,"D",0); /* ulPagesSent */
609 PACKI(desc,"D",0); /* ulPagesPrinted */
610 PACKI(desc,"D",0); /* ulTimePrinted */
611 PACKI(desc,"D",0); /* ulExtendJobStatus */
612 PACKI(desc,"D",0); /* ulStartPage */
613 PACKI(desc,"D",0); /* ulEndPage */
618 /********************************************************************
619 Return a driver name given an snum.
620 Returns True if from tdb, False otherwise.
621 ********************************************************************/
623 static bool get_driver_name(int snum, char **pp_drivername)
625 NT_PRINTER_INFO_LEVEL *info = NULL;
626 bool in_tdb = false;
628 get_a_printer (NULL, &info, 2, lp_servicename(snum));
629 if (info != NULL) {
630 *pp_drivername = talloc_strdup(talloc_tos(),
631 info->info_2->drivername);
632 in_tdb = true;
633 free_a_printer(&info, 2);
634 if (!*pp_drivername) {
635 return false;
639 return in_tdb;
642 /********************************************************************
643 Respond to the DosPrintQInfo command with a level of 52
644 This is used to get printer driver information for Win9x clients
645 ********************************************************************/
646 static void fill_printq_info_52(connection_struct *conn, int snum,
647 struct pack_desc* desc, int count )
649 int i;
650 fstring location;
651 struct spoolss_DriverInfo8 *driver = NULL;
652 NT_PRINTER_INFO_LEVEL *printer = NULL;
654 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
655 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
656 lp_servicename(snum)));
657 goto err;
660 if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
661 "Windows 4.0", 0)) )
663 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
664 printer->info_2->drivername));
665 goto err;
668 trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
669 trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
670 trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
672 PACKI(desc, "W", 0x0400); /* don't know */
673 PACKS(desc, "z", driver->driver_name); /* long printer name */
674 PACKS(desc, "z", driver->driver_path); /* Driverfile Name */
675 PACKS(desc, "z", driver->data_file); /* Datafile name */
676 PACKS(desc, "z", driver->monitor_name); /* language monitor */
678 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
679 standard_sub_basic( "", "", location, sizeof(location)-1 );
680 PACKS(desc,"z", location); /* share to retrieve files */
682 PACKS(desc,"z", driver->default_datatype); /* default data type */
683 PACKS(desc,"z", driver->help_file); /* helpfile name */
684 PACKS(desc,"z", driver->driver_path); /* driver name */
686 DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
687 DEBUG(3,("Driver: %s:\n",driver->driver_path));
688 DEBUG(3,("Data File: %s:\n",driver->data_file));
689 DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
690 DEBUG(3,("Driver Location: %s:\n",location));
691 DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
692 DEBUG(3,("Help File: %s:\n",driver->help_file));
693 PACKI(desc,"N",count); /* number of files to copy */
695 for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
697 trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
698 PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */
699 DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
702 /* sanity check */
703 if ( i != count )
704 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
705 count, i));
707 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
709 desc->errcode=NERR_Success;
710 goto done;
712 err:
713 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
714 desc->errcode=NERR_notsupported;
716 done:
717 if ( printer )
718 free_a_printer( &printer, 2 );
720 free_a_printer_driver(driver);
724 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
725 struct pack_desc* desc,
726 int count, print_queue_struct* queue,
727 print_status_struct* status)
729 switch (uLevel) {
730 case 1:
731 case 2:
732 PACKS(desc,"B13",SERVICE(snum));
733 break;
734 case 3:
735 case 4:
736 case 5:
737 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
738 break;
739 case 51:
740 PACKI(desc,"K",printq_status(status->status));
741 break;
744 if (uLevel == 1 || uLevel == 2) {
745 PACKS(desc,"B",""); /* alignment */
746 PACKI(desc,"W",5); /* priority */
747 PACKI(desc,"W",0); /* start time */
748 PACKI(desc,"W",0); /* until time */
749 PACKS(desc,"z",""); /* pSepFile */
750 PACKS(desc,"z","lpd"); /* pPrProc */
751 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
752 PACKS(desc,"z",""); /* pParms */
753 if (snum < 0) {
754 PACKS(desc,"z","UNKNOWN PRINTER");
755 PACKI(desc,"W",LPSTAT_ERROR);
757 else if (!status || !status->message[0]) {
758 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
759 PACKI(desc,"W",LPSTAT_OK); /* status */
760 } else {
761 PACKS(desc,"z",status->message);
762 PACKI(desc,"W",printq_status(status->status)); /* status */
764 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
767 if (uLevel == 3 || uLevel == 4) {
768 char *drivername = NULL;
770 PACKI(desc,"W",5); /* uPriority */
771 PACKI(desc,"W",0); /* uStarttime */
772 PACKI(desc,"W",0); /* uUntiltime */
773 PACKI(desc,"W",5); /* pad1 */
774 PACKS(desc,"z",""); /* pszSepFile */
775 PACKS(desc,"z","WinPrint"); /* pszPrProc */
776 PACKS(desc,"z",NULL); /* pszParms */
777 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
778 /* "don't ask" that it's done this way to fix corrupted
779 Win9X/ME printer comments. */
780 if (!status) {
781 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
782 } else {
783 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
785 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
786 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
787 get_driver_name(snum,&drivername);
788 if (!drivername) {
789 return;
791 PACKS(desc,"z",drivername); /* pszDriverName */
792 PackDriverData(desc); /* pDriverData */
795 if (uLevel == 2 || uLevel == 4) {
796 int i;
797 for (i=0;i<count;i++)
798 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
801 if (uLevel==52)
802 fill_printq_info_52( conn, snum, desc, count );
805 /* This function returns the number of files for a given driver */
806 static int get_printerdrivernumber(int snum)
808 int result = 0;
809 struct spoolss_DriverInfo8 *driver;
810 NT_PRINTER_INFO_LEVEL *printer = NULL;
812 ZERO_STRUCT(driver);
814 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
815 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
816 lp_servicename(snum)));
817 goto done;
820 if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
821 "Windows 4.0", 0)) )
823 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
824 printer->info_2->drivername));
825 goto done;
828 /* count the number of files */
829 while (driver->dependent_files && *driver->dependent_files[result])
830 result++;
831 done:
832 if ( printer )
833 free_a_printer( &printer, 2 );
835 free_a_printer_driver(driver);
837 return result;
840 static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
841 char *param, int tpscnt,
842 char *data, int tdscnt,
843 int mdrcnt,int mprcnt,
844 char **rdata,char **rparam,
845 int *rdata_len,int *rparam_len)
847 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
848 char *str2 = skip_string(param,tpscnt,str1);
849 char *p = skip_string(param,tpscnt,str2);
850 char *QueueName = p;
851 unsigned int uLevel;
852 int count=0;
853 int snum;
854 char *str3;
855 struct pack_desc desc;
856 print_queue_struct *queue=NULL;
857 print_status_struct status;
858 char* tmpdata=NULL;
860 if (!str1 || !str2 || !p) {
861 return False;
863 memset((char *)&status,'\0',sizeof(status));
864 memset((char *)&desc,'\0',sizeof(desc));
866 p = skip_string(param,tpscnt,p);
867 if (!p) {
868 return False;
870 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
871 str3 = get_safe_str_ptr(param,tpscnt,p,4);
872 /* str3 may be null here and is checked in check_printq_info(). */
874 /* remove any trailing username */
875 if ((p = strchr_m(QueueName,'%')))
876 *p = 0;
878 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
880 /* check it's a supported varient */
881 if (!prefix_ok(str1,"zWrLh"))
882 return False;
883 if (!check_printq_info(&desc,uLevel,str2,str3)) {
885 * Patch from Scott Moomaw <scott@bridgewater.edu>
886 * to return the 'invalid info level' error if an
887 * unknown level was requested.
889 *rdata_len = 0;
890 *rparam_len = 6;
891 *rparam = smb_realloc_limit(*rparam,*rparam_len);
892 if (!*rparam) {
893 return False;
895 SSVALS(*rparam,0,ERRunknownlevel);
896 SSVAL(*rparam,2,0);
897 SSVAL(*rparam,4,0);
898 return(True);
901 snum = find_service(QueueName);
902 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
903 return False;
905 if (uLevel==52) {
906 count = get_printerdrivernumber(snum);
907 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
908 } else {
909 count = print_queue_status(snum, &queue,&status);
912 if (mdrcnt > 0) {
913 *rdata = smb_realloc_limit(*rdata,mdrcnt);
914 if (!*rdata) {
915 SAFE_FREE(queue);
916 return False;
918 desc.base = *rdata;
919 desc.buflen = mdrcnt;
920 } else {
922 * Don't return data but need to get correct length
923 * init_package will return wrong size if buflen=0
925 desc.buflen = getlen(desc.format);
926 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
929 if (init_package(&desc,1,count)) {
930 desc.subcount = count;
931 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
934 *rdata_len = desc.usedlen;
937 * We must set the return code to ERRbuftoosmall
938 * in order to support lanman style printing with Win NT/2k
939 * clients --jerry
941 if (!mdrcnt && lp_disable_spoolss())
942 desc.errcode = ERRbuftoosmall;
944 *rdata_len = desc.usedlen;
945 *rparam_len = 6;
946 *rparam = smb_realloc_limit(*rparam,*rparam_len);
947 if (!*rparam) {
948 SAFE_FREE(queue);
949 SAFE_FREE(tmpdata);
950 return False;
952 SSVALS(*rparam,0,desc.errcode);
953 SSVAL(*rparam,2,0);
954 SSVAL(*rparam,4,desc.neededlen);
956 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
958 SAFE_FREE(queue);
959 SAFE_FREE(tmpdata);
961 return(True);
964 /****************************************************************************
965 View list of all print jobs on all queues.
966 ****************************************************************************/
968 static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
969 char *param, int tpscnt,
970 char *data, int tdscnt,
971 int mdrcnt, int mprcnt,
972 char **rdata, char** rparam,
973 int *rdata_len, int *rparam_len)
975 char *param_format = get_safe_str_ptr(param,tpscnt,param,2);
976 char *output_format1 = skip_string(param,tpscnt,param_format);
977 char *p = skip_string(param,tpscnt,output_format1);
978 unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
979 char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4);
980 int services = lp_numservices();
981 int i, n;
982 struct pack_desc desc;
983 print_queue_struct **queue = NULL;
984 print_status_struct *status = NULL;
985 int *subcntarr = NULL;
986 int queuecnt = 0, subcnt = 0, succnt = 0;
988 if (!param_format || !output_format1 || !p) {
989 return False;
992 memset((char *)&desc,'\0',sizeof(desc));
994 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
996 if (!prefix_ok(param_format,"WrLeh")) {
997 return False;
999 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
1001 * Patch from Scott Moomaw <scott@bridgewater.edu>
1002 * to return the 'invalid info level' error if an
1003 * unknown level was requested.
1005 *rdata_len = 0;
1006 *rparam_len = 6;
1007 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1008 if (!*rparam) {
1009 return False;
1011 SSVALS(*rparam,0,ERRunknownlevel);
1012 SSVAL(*rparam,2,0);
1013 SSVAL(*rparam,4,0);
1014 return(True);
1017 for (i = 0; i < services; i++) {
1018 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1019 queuecnt++;
1023 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
1024 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1025 goto err;
1027 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1028 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
1029 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1030 goto err;
1032 memset(status,0,queuecnt*sizeof(print_status_struct));
1033 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
1034 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1035 goto err;
1038 subcnt = 0;
1039 n = 0;
1040 for (i = 0; i < services; i++) {
1041 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1042 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1043 subcnt += subcntarr[n];
1044 n++;
1048 if (mdrcnt > 0) {
1049 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1050 if (!*rdata) {
1051 goto err;
1054 desc.base = *rdata;
1055 desc.buflen = mdrcnt;
1057 if (init_package(&desc,queuecnt,subcnt)) {
1058 n = 0;
1059 succnt = 0;
1060 for (i = 0; i < services; i++) {
1061 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1062 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1063 n++;
1064 if (desc.errcode == NERR_Success) {
1065 succnt = n;
1071 SAFE_FREE(subcntarr);
1073 *rdata_len = desc.usedlen;
1074 *rparam_len = 8;
1075 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1076 if (!*rparam) {
1077 goto err;
1079 SSVALS(*rparam,0,desc.errcode);
1080 SSVAL(*rparam,2,0);
1081 SSVAL(*rparam,4,succnt);
1082 SSVAL(*rparam,6,queuecnt);
1084 for (i = 0; i < queuecnt; i++) {
1085 if (queue) {
1086 SAFE_FREE(queue[i]);
1090 SAFE_FREE(queue);
1091 SAFE_FREE(status);
1093 return True;
1095 err:
1097 SAFE_FREE(subcntarr);
1098 for (i = 0; i < queuecnt; i++) {
1099 if (queue) {
1100 SAFE_FREE(queue[i]);
1103 SAFE_FREE(queue);
1104 SAFE_FREE(status);
1106 return False;
1109 /****************************************************************************
1110 Get info level for a server list query.
1111 ****************************************************************************/
1113 static bool check_server_info(int uLevel, char* id)
1115 switch( uLevel ) {
1116 case 0:
1117 if (strcmp(id,"B16") != 0) {
1118 return False;
1120 break;
1121 case 1:
1122 if (strcmp(id,"B16BBDz") != 0) {
1123 return False;
1125 break;
1126 default:
1127 return False;
1129 return True;
1132 struct srv_info_struct {
1133 fstring name;
1134 uint32 type;
1135 fstring comment;
1136 fstring domain;
1137 bool server_added;
1140 /*******************************************************************
1141 Get server info lists from the files saved by nmbd. Return the
1142 number of entries.
1143 ******************************************************************/
1145 static int get_server_info(uint32 servertype,
1146 struct srv_info_struct **servers,
1147 const char *domain)
1149 int count=0;
1150 int alloced=0;
1151 char **lines;
1152 bool local_list_only;
1153 int i;
1155 lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
1156 if (!lines) {
1157 DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
1158 return 0;
1161 /* request for everything is code for request all servers */
1162 if (servertype == SV_TYPE_ALL) {
1163 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1166 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1168 DEBUG(4,("Servertype search: %8x\n",servertype));
1170 for (i=0;lines[i];i++) {
1171 fstring stype;
1172 struct srv_info_struct *s;
1173 const char *ptr = lines[i];
1174 bool ok = True;
1175 TALLOC_CTX *frame = NULL;
1176 char *p;
1178 if (!*ptr) {
1179 continue;
1182 if (count == alloced) {
1183 alloced += 10;
1184 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1185 if (!*servers) {
1186 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1187 TALLOC_FREE(lines);
1188 return 0;
1190 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1192 s = &(*servers)[count];
1194 frame = talloc_stackframe();
1195 s->name[0] = '\0';
1196 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1197 TALLOC_FREE(frame);
1198 continue;
1200 fstrcpy(s->name, p);
1202 stype[0] = '\0';
1203 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1204 TALLOC_FREE(frame);
1205 continue;
1207 fstrcpy(stype, p);
1209 s->comment[0] = '\0';
1210 if (!next_token_talloc(frame,&ptr, &p, NULL)) {
1211 TALLOC_FREE(frame);
1212 continue;
1214 fstrcpy(s->comment, p);
1215 string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
1217 s->domain[0] = '\0';
1218 if (!next_token_talloc(frame,&ptr,&p, NULL)) {
1219 /* this allows us to cope with an old nmbd */
1220 fstrcpy(s->domain,lp_workgroup());
1221 } else {
1222 fstrcpy(s->domain, p);
1224 TALLOC_FREE(frame);
1226 if (sscanf(stype,"%X",&s->type) != 1) {
1227 DEBUG(4,("r:host file "));
1228 ok = False;
1231 /* Filter the servers/domains we return based on what was asked for. */
1233 /* Check to see if we are being asked for a local list only. */
1234 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1235 DEBUG(4,("r: local list only"));
1236 ok = False;
1239 /* doesn't match up: don't want it */
1240 if (!(servertype & s->type)) {
1241 DEBUG(4,("r:serv type "));
1242 ok = False;
1245 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1246 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1247 DEBUG(4,("s: dom mismatch "));
1248 ok = False;
1251 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1252 ok = False;
1255 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1256 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1258 if (ok) {
1259 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1260 s->name, s->type, s->comment, s->domain));
1261 s->server_added = True;
1262 count++;
1263 } else {
1264 DEBUG(4,("%20s %8x %25s %15s\n",
1265 s->name, s->type, s->comment, s->domain));
1269 TALLOC_FREE(lines);
1270 return count;
1273 /*******************************************************************
1274 Fill in a server info structure.
1275 ******************************************************************/
1277 static int fill_srv_info(struct srv_info_struct *service,
1278 int uLevel, char **buf, int *buflen,
1279 char **stringbuf, int *stringspace, char *baseaddr)
1281 int struct_len;
1282 char* p;
1283 char* p2;
1284 int l2;
1285 int len;
1287 switch (uLevel) {
1288 case 0:
1289 struct_len = 16;
1290 break;
1291 case 1:
1292 struct_len = 26;
1293 break;
1294 default:
1295 return -1;
1298 if (!buf) {
1299 len = 0;
1300 switch (uLevel) {
1301 case 1:
1302 len = strlen(service->comment)+1;
1303 break;
1306 *buflen = struct_len;
1307 *stringspace = len;
1308 return struct_len + len;
1311 len = struct_len;
1312 p = *buf;
1313 if (*buflen < struct_len) {
1314 return -1;
1316 if (stringbuf) {
1317 p2 = *stringbuf;
1318 l2 = *stringspace;
1319 } else {
1320 p2 = p + struct_len;
1321 l2 = *buflen - struct_len;
1323 if (!baseaddr) {
1324 baseaddr = p;
1327 switch (uLevel) {
1328 case 0:
1329 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1330 break;
1332 case 1:
1333 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1334 SIVAL(p,18,service->type);
1335 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1336 len += CopyAndAdvance(&p2,service->comment,&l2);
1337 break;
1340 if (stringbuf) {
1341 *buf = p + struct_len;
1342 *buflen -= struct_len;
1343 *stringbuf = p2;
1344 *stringspace = l2;
1345 } else {
1346 *buf = p2;
1347 *buflen -= len;
1349 return len;
1353 static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1355 return(strcmp(s1->name,s2->name));
1358 /****************************************************************************
1359 View list of servers available (or possibly domains). The info is
1360 extracted from lists saved by nmbd on the local host.
1361 ****************************************************************************/
1363 static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
1364 char *param, int tpscnt,
1365 char *data, int tdscnt,
1366 int mdrcnt, int mprcnt, char **rdata,
1367 char **rparam, int *rdata_len, int *rparam_len)
1369 char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
1370 char *str2 = skip_string(param,tpscnt,str1);
1371 char *p = skip_string(param,tpscnt,str2);
1372 int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
1373 int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
1374 uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
1375 char *p2;
1376 int data_len, fixed_len, string_len;
1377 int f_len = 0, s_len = 0;
1378 struct srv_info_struct *servers=NULL;
1379 int counted=0,total=0;
1380 int i,missed;
1381 fstring domain;
1382 bool domain_request;
1383 bool local_request;
1385 if (!str1 || !str2 || !p) {
1386 return False;
1389 /* If someone sets all the bits they don't really mean to set
1390 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1391 known servers. */
1393 if (servertype == SV_TYPE_ALL) {
1394 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1397 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1398 any other bit (they may just set this bit on its own) they
1399 want all the locally seen servers. However this bit can be
1400 set on its own so set the requested servers to be
1401 ALL - DOMAIN_ENUM. */
1403 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1404 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1407 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1408 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1410 p += 8;
1412 if (!prefix_ok(str1,"WrLehD")) {
1413 return False;
1415 if (!check_server_info(uLevel,str2)) {
1416 return False;
1419 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1420 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1421 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1423 if (strcmp(str1, "WrLehDz") == 0) {
1424 if (skip_string(param,tpscnt,p) == NULL) {
1425 return False;
1427 pull_ascii_fstring(domain, p);
1428 } else {
1429 fstrcpy(domain, lp_workgroup());
1432 DEBUG(4, ("domain [%s]\n", domain));
1434 if (lp_browse_list()) {
1435 total = get_server_info(servertype,&servers,domain);
1438 data_len = fixed_len = string_len = 0;
1439 missed = 0;
1441 if (total > 0) {
1442 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1446 char *lastname=NULL;
1448 for (i=0;i<total;i++) {
1449 struct srv_info_struct *s = &servers[i];
1451 if (lastname && strequal(lastname,s->name)) {
1452 continue;
1454 lastname = s->name;
1455 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1456 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1457 i, s->name, s->type, s->comment, s->domain));
1459 if (data_len <= buf_len) {
1460 counted++;
1461 fixed_len += f_len;
1462 string_len += s_len;
1463 } else {
1464 missed++;
1469 *rdata_len = fixed_len + string_len;
1470 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1471 if (!*rdata) {
1472 return False;
1475 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1476 p = *rdata;
1477 f_len = fixed_len;
1478 s_len = string_len;
1481 char *lastname=NULL;
1482 int count2 = counted;
1484 for (i = 0; i < total && count2;i++) {
1485 struct srv_info_struct *s = &servers[i];
1487 if (lastname && strequal(lastname,s->name)) {
1488 continue;
1490 lastname = s->name;
1491 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1492 DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
1493 i, s->name, s->type, s->comment, s->domain));
1494 count2--;
1498 *rparam_len = 8;
1499 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1500 if (!*rparam) {
1501 return False;
1503 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1504 SSVAL(*rparam,2,0);
1505 SSVAL(*rparam,4,counted);
1506 SSVAL(*rparam,6,counted+missed);
1508 SAFE_FREE(servers);
1510 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1511 domain,uLevel,counted,counted+missed));
1513 return True;
1516 /****************************************************************************
1517 command 0x34 - suspected of being a "Lookup Names" stub api
1518 ****************************************************************************/
1520 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1521 char *param, int tpscnt,
1522 char *data, int tdscnt,
1523 int mdrcnt, int mprcnt, char **rdata,
1524 char **rparam, int *rdata_len, int *rparam_len)
1526 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1527 char *str2 = skip_string(param,tpscnt,str1);
1528 char *p = skip_string(param,tpscnt,str2);
1529 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1530 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1531 int counted=0;
1532 int missed=0;
1534 if (!str1 || !str2 || !p) {
1535 return False;
1538 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1539 str1, str2, p, uLevel, buf_len));
1541 if (!prefix_ok(str1,"zWrLeh")) {
1542 return False;
1545 *rdata_len = 0;
1547 *rparam_len = 8;
1548 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1549 if (!*rparam) {
1550 return False;
1553 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1554 SSVAL(*rparam,2,0);
1555 SSVAL(*rparam,4,counted);
1556 SSVAL(*rparam,6,counted+missed);
1558 return True;
1561 /****************************************************************************
1562 get info about a share
1563 ****************************************************************************/
1565 static bool check_share_info(int uLevel, char* id)
1567 switch( uLevel ) {
1568 case 0:
1569 if (strcmp(id,"B13") != 0) {
1570 return False;
1572 break;
1573 case 1:
1574 /* Level-2 descriptor is allowed (and ignored) */
1575 if (strcmp(id,"B13BWz") != 0 &&
1576 strcmp(id,"B13BWzWWWzB9B") != 0) {
1577 return False;
1579 break;
1580 case 2:
1581 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1582 return False;
1584 break;
1585 case 91:
1586 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1587 return False;
1589 break;
1590 default:
1591 return False;
1593 return True;
1596 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1597 char** buf, int* buflen,
1598 char** stringbuf, int* stringspace, char* baseaddr)
1600 int struct_len;
1601 char* p;
1602 char* p2;
1603 int l2;
1604 int len;
1606 switch( uLevel ) {
1607 case 0:
1608 struct_len = 13;
1609 break;
1610 case 1:
1611 struct_len = 20;
1612 break;
1613 case 2:
1614 struct_len = 40;
1615 break;
1616 case 91:
1617 struct_len = 68;
1618 break;
1619 default:
1620 return -1;
1623 if (!buf) {
1624 len = 0;
1626 if (uLevel > 0) {
1627 len += StrlenExpanded(conn,snum,lp_comment(snum));
1629 if (uLevel > 1) {
1630 len += strlen(lp_pathname(snum)) + 1;
1632 if (buflen) {
1633 *buflen = struct_len;
1635 if (stringspace) {
1636 *stringspace = len;
1638 return struct_len + len;
1641 len = struct_len;
1642 p = *buf;
1643 if ((*buflen) < struct_len) {
1644 return -1;
1647 if (stringbuf) {
1648 p2 = *stringbuf;
1649 l2 = *stringspace;
1650 } else {
1651 p2 = p + struct_len;
1652 l2 = (*buflen) - struct_len;
1655 if (!baseaddr) {
1656 baseaddr = p;
1659 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1661 if (uLevel > 0) {
1662 int type;
1664 SCVAL(p,13,0);
1665 type = STYPE_DISKTREE;
1666 if (lp_print_ok(snum)) {
1667 type = STYPE_PRINTQ;
1669 if (strequal("IPC",lp_fstype(snum))) {
1670 type = STYPE_IPC;
1672 SSVAL(p,14,type); /* device type */
1673 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1674 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1677 if (uLevel > 1) {
1678 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1679 SSVALS(p,22,-1); /* max uses */
1680 SSVAL(p,24,1); /* current uses */
1681 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1682 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1683 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1686 if (uLevel > 2) {
1687 memset(p+40,0,SHPWLEN+2);
1688 SSVAL(p,50,0);
1689 SIVAL(p,52,0);
1690 SSVAL(p,56,0);
1691 SSVAL(p,58,0);
1692 SIVAL(p,60,0);
1693 SSVAL(p,64,0);
1694 SSVAL(p,66,0);
1697 if (stringbuf) {
1698 (*buf) = p + struct_len;
1699 (*buflen) -= struct_len;
1700 (*stringbuf) = p2;
1701 (*stringspace) = l2;
1702 } else {
1703 (*buf) = p2;
1704 (*buflen) -= len;
1707 return len;
1710 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1711 char *param, int tpscnt,
1712 char *data, int tdscnt,
1713 int mdrcnt,int mprcnt,
1714 char **rdata,char **rparam,
1715 int *rdata_len,int *rparam_len)
1717 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1718 char *str2 = skip_string(param,tpscnt,str1);
1719 char *netname = skip_string(param,tpscnt,str2);
1720 char *p = skip_string(param,tpscnt,netname);
1721 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1722 int snum;
1724 if (!str1 || !str2 || !netname || !p) {
1725 return False;
1728 snum = find_service(netname);
1729 if (snum < 0) {
1730 return False;
1733 /* check it's a supported varient */
1734 if (!prefix_ok(str1,"zWrLh")) {
1735 return False;
1737 if (!check_share_info(uLevel,str2)) {
1738 return False;
1741 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1742 if (!*rdata) {
1743 return False;
1745 p = *rdata;
1746 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1747 if (*rdata_len < 0) {
1748 return False;
1751 *rparam_len = 6;
1752 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1753 if (!*rparam) {
1754 return False;
1756 SSVAL(*rparam,0,NERR_Success);
1757 SSVAL(*rparam,2,0); /* converter word */
1758 SSVAL(*rparam,4,*rdata_len);
1760 return True;
1763 /****************************************************************************
1764 View the list of available shares.
1766 This function is the server side of the NetShareEnum() RAP call.
1767 It fills the return buffer with share names and share comments.
1768 Note that the return buffer normally (in all known cases) allows only
1769 twelve byte strings for share names (plus one for a nul terminator).
1770 Share names longer than 12 bytes must be skipped.
1771 ****************************************************************************/
1773 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1774 char *param, int tpscnt,
1775 char *data, int tdscnt,
1776 int mdrcnt,
1777 int mprcnt,
1778 char **rdata,
1779 char **rparam,
1780 int *rdata_len,
1781 int *rparam_len )
1783 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1784 char *str2 = skip_string(param,tpscnt,str1);
1785 char *p = skip_string(param,tpscnt,str2);
1786 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1787 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1788 char *p2;
1789 int count = 0;
1790 int total=0,counted=0;
1791 bool missed = False;
1792 int i;
1793 int data_len, fixed_len, string_len;
1794 int f_len = 0, s_len = 0;
1796 if (!str1 || !str2 || !p) {
1797 return False;
1800 if (!prefix_ok(str1,"WrLeh")) {
1801 return False;
1803 if (!check_share_info(uLevel,str2)) {
1804 return False;
1807 /* Ensure all the usershares are loaded. */
1808 become_root();
1809 load_registry_shares();
1810 count = load_usershare_shares();
1811 unbecome_root();
1813 data_len = fixed_len = string_len = 0;
1814 for (i=0;i<count;i++) {
1815 fstring servicename_dos;
1816 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1817 continue;
1819 push_ascii_fstring(servicename_dos, lp_servicename(i));
1820 /* Maximum name length = 13. */
1821 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1822 total++;
1823 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1824 if (data_len <= buf_len) {
1825 counted++;
1826 fixed_len += f_len;
1827 string_len += s_len;
1828 } else {
1829 missed = True;
1834 *rdata_len = fixed_len + string_len;
1835 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1836 if (!*rdata) {
1837 return False;
1840 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1841 p = *rdata;
1842 f_len = fixed_len;
1843 s_len = string_len;
1845 for( i = 0; i < count; i++ ) {
1846 fstring servicename_dos;
1847 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1848 continue;
1851 push_ascii_fstring(servicename_dos, lp_servicename(i));
1852 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1853 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1854 break;
1859 *rparam_len = 8;
1860 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1861 if (!*rparam) {
1862 return False;
1864 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1865 SSVAL(*rparam,2,0);
1866 SSVAL(*rparam,4,counted);
1867 SSVAL(*rparam,6,total);
1869 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1870 counted,total,uLevel,
1871 buf_len,*rdata_len,mdrcnt));
1873 return True;
1876 /****************************************************************************
1877 Add a share
1878 ****************************************************************************/
1880 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1881 char *param, int tpscnt,
1882 char *data, int tdscnt,
1883 int mdrcnt,int mprcnt,
1884 char **rdata,char **rparam,
1885 int *rdata_len,int *rparam_len)
1887 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1888 char *str2 = skip_string(param,tpscnt,str1);
1889 char *p = skip_string(param,tpscnt,str2);
1890 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1891 fstring sharename;
1892 fstring comment;
1893 char *pathname = NULL;
1894 char *command, *cmdname;
1895 unsigned int offset;
1896 int snum;
1897 int res = ERRunsup;
1898 size_t converted_size;
1900 if (!str1 || !str2 || !p) {
1901 return False;
1904 /* check it's a supported varient */
1905 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1906 return False;
1908 if (!check_share_info(uLevel,str2)) {
1909 return False;
1911 if (uLevel != 2) {
1912 return False;
1915 /* Do we have a string ? */
1916 if (skip_string(data,mdrcnt,data) == NULL) {
1917 return False;
1919 pull_ascii_fstring(sharename,data);
1920 snum = find_service(sharename);
1921 if (snum >= 0) { /* already exists */
1922 res = ERRfilexists;
1923 goto error_exit;
1926 if (mdrcnt < 28) {
1927 return False;
1930 /* only support disk share adds */
1931 if (SVAL(data,14)!=STYPE_DISKTREE) {
1932 return False;
1935 offset = IVAL(data, 16);
1936 if (offset >= mdrcnt) {
1937 res = ERRinvalidparam;
1938 goto error_exit;
1941 /* Do we have a string ? */
1942 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1943 return False;
1945 pull_ascii_fstring(comment, offset? (data+offset) : "");
1947 offset = IVAL(data, 26);
1949 if (offset >= mdrcnt) {
1950 res = ERRinvalidparam;
1951 goto error_exit;
1954 /* Do we have a string ? */
1955 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1956 return False;
1959 if (!pull_ascii_talloc(talloc_tos(), &pathname,
1960 offset ? (data+offset) : "", &converted_size))
1962 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
1963 strerror(errno)));
1966 if (!pathname) {
1967 return false;
1970 string_replace(sharename, '"', ' ');
1971 string_replace(pathname, '"', ' ');
1972 string_replace(comment, '"', ' ');
1974 cmdname = lp_add_share_cmd();
1976 if (!cmdname || *cmdname == '\0') {
1977 return False;
1980 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1981 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
1982 pathname, comment) == -1) {
1983 return false;
1986 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1988 if ((res = smbrun(command, NULL)) != 0) {
1989 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
1990 command, res ));
1991 SAFE_FREE(command);
1992 res = ERRnoaccess;
1993 goto error_exit;
1994 } else {
1995 SAFE_FREE(command);
1996 message_send_all(smbd_messaging_context(),
1997 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
2000 *rparam_len = 6;
2001 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2002 if (!*rparam) {
2003 return False;
2005 SSVAL(*rparam,0,NERR_Success);
2006 SSVAL(*rparam,2,0); /* converter word */
2007 SSVAL(*rparam,4,*rdata_len);
2008 *rdata_len = 0;
2010 return True;
2012 error_exit:
2014 *rparam_len = 4;
2015 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2016 if (!*rparam) {
2017 return False;
2019 *rdata_len = 0;
2020 SSVAL(*rparam,0,res);
2021 SSVAL(*rparam,2,0);
2022 return True;
2025 /****************************************************************************
2026 view list of groups available
2027 ****************************************************************************/
2029 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2030 char *param, int tpscnt,
2031 char *data, int tdscnt,
2032 int mdrcnt,int mprcnt,
2033 char **rdata,char **rparam,
2034 int *rdata_len,int *rparam_len)
2036 int i;
2037 int errflags=0;
2038 int resume_context, cli_buf_size;
2039 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2040 char *str2 = skip_string(param,tpscnt,str1);
2041 char *p = skip_string(param,tpscnt,str2);
2043 uint32_t num_groups;
2044 uint32_t resume_handle;
2045 struct rpc_pipe_client *samr_pipe;
2046 struct policy_handle samr_handle, domain_handle;
2047 NTSTATUS status;
2049 if (!str1 || !str2 || !p) {
2050 return False;
2053 if (strcmp(str1,"WrLeh") != 0) {
2054 return False;
2057 /* parameters
2058 * W-> resume context (number of users to skip)
2059 * r -> return parameter pointer to receive buffer
2060 * L -> length of receive buffer
2061 * e -> return parameter number of entries
2062 * h -> return parameter total number of users
2065 if (strcmp("B21",str2) != 0) {
2066 return False;
2069 status = rpc_pipe_open_internal(
2070 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2071 conn->server_info, &samr_pipe);
2072 if (!NT_STATUS_IS_OK(status)) {
2073 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2074 nt_errstr(status)));
2075 return false;
2078 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2079 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2080 if (!NT_STATUS_IS_OK(status)) {
2081 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2082 nt_errstr(status)));
2083 return false;
2086 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2087 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2088 get_global_sam_sid(), &domain_handle);
2089 if (!NT_STATUS_IS_OK(status)) {
2090 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2091 nt_errstr(status)));
2092 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2093 return false;
2096 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2097 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2098 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2099 "%d\n", resume_context, cli_buf_size));
2101 *rdata_len = cli_buf_size;
2102 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2103 if (!*rdata) {
2104 return False;
2107 p = *rdata;
2109 errflags = NERR_Success;
2110 num_groups = 0;
2111 resume_handle = 0;
2113 while (true) {
2114 struct samr_SamArray *sam_entries;
2115 uint32_t num_entries;
2117 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2118 &domain_handle,
2119 &resume_handle,
2120 &sam_entries, 1,
2121 &num_entries);
2122 if (!NT_STATUS_IS_OK(status)) {
2123 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2124 "%s\n", nt_errstr(status)));
2125 break;
2128 if (num_entries == 0) {
2129 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2130 "no entries -- done\n"));
2131 break;
2134 for(i=0; i<num_entries; i++) {
2135 const char *name;
2137 name = sam_entries->entries[i].name.string;
2139 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2140 /* set overflow error */
2141 DEBUG(3,("overflow on entry %d group %s\n", i,
2142 name));
2143 errflags=234;
2144 break;
2147 /* truncate the name at 21 chars. */
2148 memset(p, 0, 21);
2149 strlcpy(p, name, 21);
2150 DEBUG(10,("adding entry %d group %s\n", i, p));
2151 p += 21;
2152 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2153 * idea why... */
2154 num_groups += 1;
2157 if (errflags != NERR_Success) {
2158 break;
2161 TALLOC_FREE(sam_entries);
2164 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2165 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2167 *rdata_len = PTR_DIFF(p,*rdata);
2169 *rparam_len = 8;
2170 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2171 if (!*rparam) {
2172 return False;
2174 SSVAL(*rparam, 0, errflags);
2175 SSVAL(*rparam, 2, 0); /* converter word */
2176 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2177 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2179 return(True);
2182 /*******************************************************************
2183 Get groups that a user is a member of.
2184 ******************************************************************/
2186 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2187 char *param, int tpscnt,
2188 char *data, int tdscnt,
2189 int mdrcnt,int mprcnt,
2190 char **rdata,char **rparam,
2191 int *rdata_len,int *rparam_len)
2193 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2194 char *str2 = skip_string(param,tpscnt,str1);
2195 char *UserName = skip_string(param,tpscnt,str2);
2196 char *p = skip_string(param,tpscnt,UserName);
2197 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2198 const char *level_string;
2199 int count=0;
2200 bool ret = False;
2201 uint32_t i;
2202 char *endp = NULL;
2204 struct rpc_pipe_client *samr_pipe;
2205 struct policy_handle samr_handle, domain_handle, user_handle;
2206 struct lsa_String name;
2207 struct lsa_Strings names;
2208 struct samr_Ids type, rid;
2209 struct samr_RidWithAttributeArray *rids;
2210 NTSTATUS status;
2212 if (!str1 || !str2 || !UserName || !p) {
2213 return False;
2216 *rparam_len = 8;
2217 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2218 if (!*rparam) {
2219 return False;
2222 /* check it's a supported varient */
2224 if ( strcmp(str1,"zWrLeh") != 0 )
2225 return False;
2227 switch( uLevel ) {
2228 case 0:
2229 level_string = "B21";
2230 break;
2231 default:
2232 return False;
2235 if (strcmp(level_string,str2) != 0)
2236 return False;
2238 *rdata_len = mdrcnt + 1024;
2239 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2240 if (!*rdata) {
2241 return False;
2244 SSVAL(*rparam,0,NERR_Success);
2245 SSVAL(*rparam,2,0); /* converter word */
2247 p = *rdata;
2248 endp = *rdata + *rdata_len;
2250 status = rpc_pipe_open_internal(
2251 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2252 conn->server_info, &samr_pipe);
2253 if (!NT_STATUS_IS_OK(status)) {
2254 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2255 nt_errstr(status)));
2256 return false;
2259 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2260 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2261 if (!NT_STATUS_IS_OK(status)) {
2262 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2263 nt_errstr(status)));
2264 return false;
2267 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2268 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2269 get_global_sam_sid(), &domain_handle);
2270 if (!NT_STATUS_IS_OK(status)) {
2271 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2272 nt_errstr(status)));
2273 goto close_sam;
2276 name.string = UserName;
2278 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2279 &domain_handle, 1, &name,
2280 &rid, &type);
2281 if (!NT_STATUS_IS_OK(status)) {
2282 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2283 nt_errstr(status)));
2284 goto close_domain;
2287 if (type.ids[0] != SID_NAME_USER) {
2288 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2289 sid_type_lookup(type.ids[0])));
2290 goto close_domain;
2293 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2294 &domain_handle,
2295 SAMR_USER_ACCESS_GET_GROUPS,
2296 rid.ids[0], &user_handle);
2297 if (!NT_STATUS_IS_OK(status)) {
2298 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2299 nt_errstr(status)));
2300 goto close_domain;
2303 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2304 &user_handle, &rids);
2305 if (!NT_STATUS_IS_OK(status)) {
2306 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2307 nt_errstr(status)));
2308 goto close_user;
2311 for (i=0; i<rids->count; i++) {
2313 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2314 &domain_handle,
2315 1, &rids->rids[i].rid,
2316 &names, &type);
2317 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2318 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2319 p += 21;
2320 count++;
2324 *rdata_len = PTR_DIFF(p,*rdata);
2326 SSVAL(*rparam,4,count); /* is this right?? */
2327 SSVAL(*rparam,6,count); /* is this right?? */
2329 ret = True;
2331 close_user:
2332 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2333 close_domain:
2334 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2335 close_sam:
2336 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2338 return ret;
2341 /*******************************************************************
2342 Get all users.
2343 ******************************************************************/
2345 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2346 char *param, int tpscnt,
2347 char *data, int tdscnt,
2348 int mdrcnt,int mprcnt,
2349 char **rdata,char **rparam,
2350 int *rdata_len,int *rparam_len)
2352 int count_sent=0;
2353 int num_users=0;
2354 int errflags=0;
2355 int i, resume_context, cli_buf_size;
2356 uint32_t resume_handle;
2358 struct rpc_pipe_client *samr_pipe;
2359 struct policy_handle samr_handle, domain_handle;
2360 NTSTATUS status;
2362 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2363 char *str2 = skip_string(param,tpscnt,str1);
2364 char *p = skip_string(param,tpscnt,str2);
2365 char *endp = NULL;
2367 if (!str1 || !str2 || !p) {
2368 return False;
2371 if (strcmp(str1,"WrLeh") != 0)
2372 return False;
2373 /* parameters
2374 * W-> resume context (number of users to skip)
2375 * r -> return parameter pointer to receive buffer
2376 * L -> length of receive buffer
2377 * e -> return parameter number of entries
2378 * h -> return parameter total number of users
2381 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2382 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2383 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2384 resume_context, cli_buf_size));
2386 *rparam_len = 8;
2387 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2388 if (!*rparam) {
2389 return False;
2392 /* check it's a supported varient */
2393 if (strcmp("B21",str2) != 0)
2394 return False;
2396 *rdata_len = cli_buf_size;
2397 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2398 if (!*rdata) {
2399 return False;
2402 p = *rdata;
2403 endp = *rdata + *rdata_len;
2405 status = rpc_pipe_open_internal(
2406 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2407 conn->server_info, &samr_pipe);
2408 if (!NT_STATUS_IS_OK(status)) {
2409 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2410 nt_errstr(status)));
2411 return false;
2414 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2415 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2416 if (!NT_STATUS_IS_OK(status)) {
2417 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2418 nt_errstr(status)));
2419 return false;
2422 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2423 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2424 get_global_sam_sid(), &domain_handle);
2425 if (!NT_STATUS_IS_OK(status)) {
2426 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2427 nt_errstr(status)));
2428 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2429 return false;
2432 errflags=NERR_Success;
2434 resume_handle = 0;
2436 while (true) {
2437 struct samr_SamArray *sam_entries;
2438 uint32_t num_entries;
2440 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2441 &domain_handle,
2442 &resume_handle,
2443 0, &sam_entries, 1,
2444 &num_entries);
2446 if (!NT_STATUS_IS_OK(status)) {
2447 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2448 "%s\n", nt_errstr(status)));
2449 break;
2452 if (num_entries == 0) {
2453 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2454 "no entries -- done\n"));
2455 break;
2458 for (i=0; i<num_entries; i++) {
2459 const char *name;
2461 name = sam_entries->entries[i].name.string;
2463 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2464 &&(strlen(name)<=21)) {
2465 strlcpy(p,name,PTR_DIFF(endp,p));
2466 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2467 "username %s\n",count_sent,p));
2468 p += 21;
2469 count_sent++;
2470 } else {
2471 /* set overflow error */
2472 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2473 "username %s\n",count_sent,name));
2474 errflags=234;
2475 break;
2479 if (errflags != NERR_Success) {
2480 break;
2483 TALLOC_FREE(sam_entries);
2486 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2487 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2489 *rdata_len = PTR_DIFF(p,*rdata);
2491 SSVAL(*rparam,0,errflags);
2492 SSVAL(*rparam,2,0); /* converter word */
2493 SSVAL(*rparam,4,count_sent); /* is this right?? */
2494 SSVAL(*rparam,6,num_users); /* is this right?? */
2496 return True;
2499 /****************************************************************************
2500 Get the time of day info.
2501 ****************************************************************************/
2503 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2504 char *param, int tpscnt,
2505 char *data, int tdscnt,
2506 int mdrcnt,int mprcnt,
2507 char **rdata,char **rparam,
2508 int *rdata_len,int *rparam_len)
2510 struct tm *t;
2511 time_t unixdate = time(NULL);
2512 char *p;
2514 *rparam_len = 4;
2515 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2516 if (!*rparam) {
2517 return False;
2520 *rdata_len = 21;
2521 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2522 if (!*rdata) {
2523 return False;
2526 SSVAL(*rparam,0,NERR_Success);
2527 SSVAL(*rparam,2,0); /* converter word */
2529 p = *rdata;
2531 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2532 by NT in a "net time" operation,
2533 it seems to ignore the one below */
2535 /* the client expects to get localtime, not GMT, in this bit
2536 (I think, this needs testing) */
2537 t = localtime(&unixdate);
2538 if (!t) {
2539 return False;
2542 SIVAL(p,4,0); /* msecs ? */
2543 SCVAL(p,8,t->tm_hour);
2544 SCVAL(p,9,t->tm_min);
2545 SCVAL(p,10,t->tm_sec);
2546 SCVAL(p,11,0); /* hundredths of seconds */
2547 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2548 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2549 SCVAL(p,16,t->tm_mday);
2550 SCVAL(p,17,t->tm_mon + 1);
2551 SSVAL(p,18,1900+t->tm_year);
2552 SCVAL(p,20,t->tm_wday);
2554 return True;
2557 /****************************************************************************
2558 Set the user password.
2559 *****************************************************************************/
2561 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2562 char *param, int tpscnt,
2563 char *data, int tdscnt,
2564 int mdrcnt,int mprcnt,
2565 char **rdata,char **rparam,
2566 int *rdata_len,int *rparam_len)
2568 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2569 char *p = NULL;
2570 fstring user;
2571 fstring pass1,pass2;
2573 /* Skip 2 strings. */
2574 p = skip_string(param,tpscnt,np);
2575 p = skip_string(param,tpscnt,p);
2577 if (!np || !p) {
2578 return False;
2581 /* Do we have a string ? */
2582 if (skip_string(param,tpscnt,p) == NULL) {
2583 return False;
2585 pull_ascii_fstring(user,p);
2587 p = skip_string(param,tpscnt,p);
2588 if (!p) {
2589 return False;
2592 memset(pass1,'\0',sizeof(pass1));
2593 memset(pass2,'\0',sizeof(pass2));
2595 * We use 31 here not 32 as we're checking
2596 * the last byte we want to access is safe.
2598 if (!is_offset_safe(param,tpscnt,p,31)) {
2599 return False;
2601 memcpy(pass1,p,16);
2602 memcpy(pass2,p+16,16);
2604 *rparam_len = 4;
2605 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2606 if (!*rparam) {
2607 return False;
2610 *rdata_len = 0;
2612 SSVAL(*rparam,0,NERR_badpass);
2613 SSVAL(*rparam,2,0); /* converter word */
2615 DEBUG(3,("Set password for <%s>\n",user));
2618 * Attempt to verify the old password against smbpasswd entries
2619 * Win98 clients send old and new password in plaintext for this call.
2623 struct auth_serversupplied_info *server_info = NULL;
2624 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2626 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2628 become_root();
2629 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2630 SSVAL(*rparam,0,NERR_Success);
2632 unbecome_root();
2634 TALLOC_FREE(server_info);
2636 data_blob_clear_free(&password);
2640 * If the plaintext change failed, attempt
2641 * the old encrypted method. NT will generate this
2642 * after trying the samr method. Note that this
2643 * method is done as a last resort as this
2644 * password change method loses the NT password hash
2645 * and cannot change the UNIX password as no plaintext
2646 * is received.
2649 if(SVAL(*rparam,0) != NERR_Success) {
2650 struct samu *hnd = NULL;
2652 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2653 become_root();
2654 if (change_lanman_password(hnd,(uchar *)pass2)) {
2655 SSVAL(*rparam,0,NERR_Success);
2657 unbecome_root();
2658 TALLOC_FREE(hnd);
2662 memset((char *)pass1,'\0',sizeof(fstring));
2663 memset((char *)pass2,'\0',sizeof(fstring));
2665 return(True);
2668 /****************************************************************************
2669 Set the user password (SamOEM version - gets plaintext).
2670 ****************************************************************************/
2672 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2673 char *param, int tpscnt,
2674 char *data, int tdscnt,
2675 int mdrcnt,int mprcnt,
2676 char **rdata,char **rparam,
2677 int *rdata_len,int *rparam_len)
2679 struct smbd_server_connection *sconn = smbd_server_conn;
2680 fstring user;
2681 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2682 *rparam_len = 2;
2683 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2684 if (!*rparam) {
2685 return False;
2688 if (!p) {
2689 return False;
2691 *rdata_len = 0;
2693 SSVAL(*rparam,0,NERR_badpass);
2696 * Check the parameter definition is correct.
2699 /* Do we have a string ? */
2700 if (skip_string(param,tpscnt,p) == 0) {
2701 return False;
2703 if(!strequal(p, "zsT")) {
2704 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2705 return False;
2707 p = skip_string(param, tpscnt, p);
2708 if (!p) {
2709 return False;
2712 /* Do we have a string ? */
2713 if (skip_string(param,tpscnt,p) == 0) {
2714 return False;
2716 if(!strequal(p, "B516B16")) {
2717 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2718 return False;
2720 p = skip_string(param,tpscnt,p);
2721 if (!p) {
2722 return False;
2724 /* Do we have a string ? */
2725 if (skip_string(param,tpscnt,p) == 0) {
2726 return False;
2728 p += pull_ascii_fstring(user,p);
2730 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2733 * Pass the user through the NT -> unix user mapping
2734 * function.
2737 (void)map_username(sconn, user);
2739 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2740 SSVAL(*rparam,0,NERR_Success);
2743 return(True);
2746 /****************************************************************************
2747 delete a print job
2748 Form: <W> <>
2749 ****************************************************************************/
2751 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2752 char *param, int tpscnt,
2753 char *data, int tdscnt,
2754 int mdrcnt,int mprcnt,
2755 char **rdata,char **rparam,
2756 int *rdata_len,int *rparam_len)
2758 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2759 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2760 char *str2 = skip_string(param,tpscnt,str1);
2761 char *p = skip_string(param,tpscnt,str2);
2762 uint32 jobid;
2763 int snum;
2764 fstring sharename;
2765 int errcode;
2766 WERROR werr = WERR_OK;
2768 if (!str1 || !str2 || !p) {
2769 return False;
2772 * We use 1 here not 2 as we're checking
2773 * the last byte we want to access is safe.
2775 if (!is_offset_safe(param,tpscnt,p,1)) {
2776 return False;
2778 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2779 return False;
2781 /* check it's a supported varient */
2782 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2783 return(False);
2785 *rparam_len = 4;
2786 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2787 if (!*rparam) {
2788 return False;
2790 *rdata_len = 0;
2792 if (!print_job_exists(sharename, jobid)) {
2793 errcode = NERR_JobNotFound;
2794 goto out;
2797 snum = lp_servicenumber( sharename);
2798 if (snum == -1) {
2799 errcode = NERR_DestNotFound;
2800 goto out;
2803 errcode = NERR_notsupported;
2805 switch (function) {
2806 case 81: /* delete */
2807 if (print_job_delete(conn->server_info, snum, jobid, &werr))
2808 errcode = NERR_Success;
2809 break;
2810 case 82: /* pause */
2811 if (print_job_pause(conn->server_info, snum, jobid, &werr))
2812 errcode = NERR_Success;
2813 break;
2814 case 83: /* resume */
2815 if (print_job_resume(conn->server_info, snum, jobid, &werr))
2816 errcode = NERR_Success;
2817 break;
2820 if (!W_ERROR_IS_OK(werr))
2821 errcode = W_ERROR_V(werr);
2823 out:
2824 SSVAL(*rparam,0,errcode);
2825 SSVAL(*rparam,2,0); /* converter word */
2827 return(True);
2830 /****************************************************************************
2831 Purge a print queue - or pause or resume it.
2832 ****************************************************************************/
2834 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2835 char *param, int tpscnt,
2836 char *data, int tdscnt,
2837 int mdrcnt,int mprcnt,
2838 char **rdata,char **rparam,
2839 int *rdata_len,int *rparam_len)
2841 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2842 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2843 char *str2 = skip_string(param,tpscnt,str1);
2844 char *QueueName = skip_string(param,tpscnt,str2);
2845 int errcode = NERR_notsupported;
2846 int snum;
2847 WERROR werr = WERR_OK;
2849 if (!str1 || !str2 || !QueueName) {
2850 return False;
2853 /* check it's a supported varient */
2854 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2855 return(False);
2857 *rparam_len = 4;
2858 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2859 if (!*rparam) {
2860 return False;
2862 *rdata_len = 0;
2864 if (skip_string(param,tpscnt,QueueName) == NULL) {
2865 return False;
2867 snum = print_queue_snum(QueueName);
2869 if (snum == -1) {
2870 errcode = NERR_JobNotFound;
2871 goto out;
2874 switch (function) {
2875 case 74: /* Pause queue */
2876 werr = print_queue_pause(conn->server_info, snum);
2877 break;
2878 case 75: /* Resume queue */
2879 werr = print_queue_resume(conn->server_info, snum);
2880 break;
2881 case 103: /* Purge */
2882 werr = print_queue_purge(conn->server_info, snum);
2883 break;
2884 default:
2885 werr = WERR_NOT_SUPPORTED;
2886 break;
2889 errcode = W_ERROR_V(werr);
2891 out:
2892 SSVAL(*rparam,0,errcode);
2893 SSVAL(*rparam,2,0); /* converter word */
2895 return(True);
2898 /****************************************************************************
2899 set the property of a print job (undocumented?)
2900 ? function = 0xb -> set name of print job
2901 ? function = 0x6 -> move print job up/down
2902 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2903 or <WWsTP> <WB21BB16B10zWWzDDz>
2904 ****************************************************************************/
2906 static int check_printjob_info(struct pack_desc* desc,
2907 int uLevel, char* id)
2909 desc->subformat = NULL;
2910 switch( uLevel ) {
2911 case 0: desc->format = "W"; break;
2912 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2913 case 2: desc->format = "WWzWWDDzz"; break;
2914 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2915 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2916 default:
2917 DEBUG(0,("check_printjob_info: invalid level %d\n",
2918 uLevel ));
2919 return False;
2921 if (id == NULL || strcmp(desc->format,id) != 0) {
2922 DEBUG(0,("check_printjob_info: invalid format %s\n",
2923 id ? id : "<NULL>" ));
2924 return False;
2926 return True;
2929 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2930 char *param, int tpscnt,
2931 char *data, int tdscnt,
2932 int mdrcnt,int mprcnt,
2933 char **rdata,char **rparam,
2934 int *rdata_len,int *rparam_len)
2936 struct pack_desc desc;
2937 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2938 char *str2 = skip_string(param,tpscnt,str1);
2939 char *p = skip_string(param,tpscnt,str2);
2940 uint32 jobid;
2941 fstring sharename;
2942 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2943 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2944 int place, errcode;
2946 if (!str1 || !str2 || !p) {
2947 return False;
2950 * We use 1 here not 2 as we're checking
2951 * the last byte we want to access is safe.
2953 if (!is_offset_safe(param,tpscnt,p,1)) {
2954 return False;
2956 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2957 return False;
2958 *rparam_len = 4;
2959 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2960 if (!*rparam) {
2961 return False;
2964 if (!share_defined(sharename)) {
2965 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2966 sharename));
2967 return False;
2970 *rdata_len = 0;
2972 /* check it's a supported varient */
2973 if ((strcmp(str1,"WWsTP")) ||
2974 (!check_printjob_info(&desc,uLevel,str2)))
2975 return(False);
2977 if (!print_job_exists(sharename, jobid)) {
2978 errcode=NERR_JobNotFound;
2979 goto out;
2982 errcode = NERR_notsupported;
2984 switch (function) {
2985 case 0x6:
2986 /* change job place in the queue,
2987 data gives the new place */
2988 place = SVAL(data,0);
2989 if (print_job_set_place(sharename, jobid, place)) {
2990 errcode=NERR_Success;
2992 break;
2994 case 0xb:
2995 /* change print job name, data gives the name */
2996 if (print_job_set_name(sharename, jobid, data)) {
2997 errcode=NERR_Success;
2999 break;
3001 default:
3002 return False;
3005 out:
3006 SSVALS(*rparam,0,errcode);
3007 SSVAL(*rparam,2,0); /* converter word */
3009 return(True);
3013 /****************************************************************************
3014 Get info about the server.
3015 ****************************************************************************/
3017 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3018 char *param, int tpscnt,
3019 char *data, int tdscnt,
3020 int mdrcnt,int mprcnt,
3021 char **rdata,char **rparam,
3022 int *rdata_len,int *rparam_len)
3024 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3025 char *str2 = skip_string(param,tpscnt,str1);
3026 char *p = skip_string(param,tpscnt,str2);
3027 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3028 char *p2;
3029 int struct_len;
3031 if (!str1 || !str2 || !p) {
3032 return False;
3035 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3037 /* check it's a supported varient */
3038 if (!prefix_ok(str1,"WrLh")) {
3039 return False;
3042 switch( uLevel ) {
3043 case 0:
3044 if (strcmp(str2,"B16") != 0) {
3045 return False;
3047 struct_len = 16;
3048 break;
3049 case 1:
3050 if (strcmp(str2,"B16BBDz") != 0) {
3051 return False;
3053 struct_len = 26;
3054 break;
3055 case 2:
3056 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3057 return False;
3059 struct_len = 134;
3060 break;
3061 case 3:
3062 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3063 return False;
3065 struct_len = 144;
3066 break;
3067 case 20:
3068 if (strcmp(str2,"DN") != 0) {
3069 return False;
3071 struct_len = 6;
3072 break;
3073 case 50:
3074 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3075 return False;
3077 struct_len = 42;
3078 break;
3079 default:
3080 return False;
3083 *rdata_len = mdrcnt;
3084 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3085 if (!*rdata) {
3086 return False;
3089 p = *rdata;
3090 p2 = p + struct_len;
3091 if (uLevel != 20) {
3092 srvstr_push(NULL, 0, p,global_myname(),16,
3093 STR_ASCII|STR_UPPER|STR_TERMINATE);
3095 p += 16;
3096 if (uLevel > 0) {
3097 struct srv_info_struct *servers=NULL;
3098 int i,count;
3099 char *comment = NULL;
3100 TALLOC_CTX *ctx = talloc_tos();
3101 uint32 servertype= lp_default_server_announce();
3103 comment = talloc_strdup(ctx,lp_serverstring());
3104 if (!comment) {
3105 return false;
3108 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3109 for (i=0;i<count;i++) {
3110 if (strequal(servers[i].name,global_myname())) {
3111 servertype = servers[i].type;
3112 TALLOC_FREE(comment);
3113 comment = talloc_strdup(ctx,
3114 servers[i].comment);
3115 if (comment) {
3116 return false;
3122 SAFE_FREE(servers);
3124 SCVAL(p,0,lp_major_announce_version());
3125 SCVAL(p,1,lp_minor_announce_version());
3126 SIVAL(p,2,servertype);
3128 if (mdrcnt == struct_len) {
3129 SIVAL(p,6,0);
3130 } else {
3131 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3132 comment = talloc_sub_advanced(
3133 ctx,
3134 lp_servicename(SNUM(conn)),
3135 conn->server_info->unix_name,
3136 conn->connectpath,
3137 conn->server_info->utok.gid,
3138 conn->server_info->sanitized_username,
3139 pdb_get_domain(conn->server_info->sam_account),
3140 comment);
3141 if (comment) {
3142 return false;
3144 if (mdrcnt - struct_len <= 0) {
3145 return false;
3147 push_ascii(p2,
3148 comment,
3149 MIN(mdrcnt - struct_len,
3150 MAX_SERVER_STRING_LENGTH),
3151 STR_TERMINATE);
3152 p2 = skip_string(*rdata,*rdata_len,p2);
3153 if (!p2) {
3154 return False;
3159 if (uLevel > 1) {
3160 return False; /* not yet implemented */
3163 *rdata_len = PTR_DIFF(p2,*rdata);
3165 *rparam_len = 6;
3166 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3167 if (!*rparam) {
3168 return False;
3170 SSVAL(*rparam,0,NERR_Success);
3171 SSVAL(*rparam,2,0); /* converter word */
3172 SSVAL(*rparam,4,*rdata_len);
3174 return True;
3177 /****************************************************************************
3178 Get info about the server.
3179 ****************************************************************************/
3181 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3182 char *param, int tpscnt,
3183 char *data, int tdscnt,
3184 int mdrcnt,int mprcnt,
3185 char **rdata,char **rparam,
3186 int *rdata_len,int *rparam_len)
3188 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3189 char *str2 = skip_string(param,tpscnt,str1);
3190 char *p = skip_string(param,tpscnt,str2);
3191 char *p2;
3192 char *endp;
3193 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3195 if (!str1 || !str2 || !p) {
3196 return False;
3199 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3201 *rparam_len = 6;
3202 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3203 if (!*rparam) {
3204 return False;
3207 /* check it's a supported varient */
3208 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3209 return False;
3212 *rdata_len = mdrcnt + 1024;
3213 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3214 if (!*rdata) {
3215 return False;
3218 SSVAL(*rparam,0,NERR_Success);
3219 SSVAL(*rparam,2,0); /* converter word */
3221 p = *rdata;
3222 endp = *rdata + *rdata_len;
3224 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3225 if (!p2) {
3226 return False;
3229 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3230 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3231 strupper_m(p2);
3232 p2 = skip_string(*rdata,*rdata_len,p2);
3233 if (!p2) {
3234 return False;
3236 p += 4;
3238 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3239 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3240 p2 = skip_string(*rdata,*rdata_len,p2);
3241 if (!p2) {
3242 return False;
3244 p += 4;
3246 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3247 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3248 strupper_m(p2);
3249 p2 = skip_string(*rdata,*rdata_len,p2);
3250 if (!p2) {
3251 return False;
3253 p += 4;
3255 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3256 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3257 p += 2;
3259 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3260 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3261 p2 = skip_string(*rdata,*rdata_len,p2);
3262 if (!p2) {
3263 return False;
3265 p += 4;
3267 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3268 strlcpy(p2,"",PTR_DIFF(endp,p2));
3269 p2 = skip_string(*rdata,*rdata_len,p2);
3270 if (!p2) {
3271 return False;
3273 p += 4;
3275 *rdata_len = PTR_DIFF(p2,*rdata);
3277 SSVAL(*rparam,4,*rdata_len);
3279 return True;
3282 /****************************************************************************
3283 get info about a user
3285 struct user_info_11 {
3286 char usri11_name[21]; 0-20
3287 char usri11_pad; 21
3288 char *usri11_comment; 22-25
3289 char *usri11_usr_comment; 26-29
3290 unsigned short usri11_priv; 30-31
3291 unsigned long usri11_auth_flags; 32-35
3292 long usri11_password_age; 36-39
3293 char *usri11_homedir; 40-43
3294 char *usri11_parms; 44-47
3295 long usri11_last_logon; 48-51
3296 long usri11_last_logoff; 52-55
3297 unsigned short usri11_bad_pw_count; 56-57
3298 unsigned short usri11_num_logons; 58-59
3299 char *usri11_logon_server; 60-63
3300 unsigned short usri11_country_code; 64-65
3301 char *usri11_workstations; 66-69
3302 unsigned long usri11_max_storage; 70-73
3303 unsigned short usri11_units_per_week; 74-75
3304 unsigned char *usri11_logon_hours; 76-79
3305 unsigned short usri11_code_page; 80-81
3308 where:
3310 usri11_name specifies the user name for which information is retrieved
3312 usri11_pad aligns the next data structure element to a word boundary
3314 usri11_comment is a null terminated ASCII comment
3316 usri11_user_comment is a null terminated ASCII comment about the user
3318 usri11_priv specifies the level of the privilege assigned to the user.
3319 The possible values are:
3321 Name Value Description
3322 USER_PRIV_GUEST 0 Guest privilege
3323 USER_PRIV_USER 1 User privilege
3324 USER_PRV_ADMIN 2 Administrator privilege
3326 usri11_auth_flags specifies the account operator privileges. The
3327 possible values are:
3329 Name Value Description
3330 AF_OP_PRINT 0 Print operator
3333 Leach, Naik [Page 28]
3337 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3340 AF_OP_COMM 1 Communications operator
3341 AF_OP_SERVER 2 Server operator
3342 AF_OP_ACCOUNTS 3 Accounts operator
3345 usri11_password_age specifies how many seconds have elapsed since the
3346 password was last changed.
3348 usri11_home_dir points to a null terminated ASCII string that contains
3349 the path name of the user's home directory.
3351 usri11_parms points to a null terminated ASCII string that is set
3352 aside for use by applications.
3354 usri11_last_logon specifies the time when the user last logged on.
3355 This value is stored as the number of seconds elapsed since
3356 00:00:00, January 1, 1970.
3358 usri11_last_logoff specifies the time when the user last logged off.
3359 This value is stored as the number of seconds elapsed since
3360 00:00:00, January 1, 1970. A value of 0 means the last logoff
3361 time is unknown.
3363 usri11_bad_pw_count specifies the number of incorrect passwords
3364 entered since the last successful logon.
3366 usri11_log1_num_logons specifies the number of times this user has
3367 logged on. A value of -1 means the number of logons is unknown.
3369 usri11_logon_server points to a null terminated ASCII string that
3370 contains the name of the server to which logon requests are sent.
3371 A null string indicates logon requests should be sent to the
3372 domain controller.
3374 usri11_country_code specifies the country code for the user's language
3375 of choice.
3377 usri11_workstations points to a null terminated ASCII string that
3378 contains the names of workstations the user may log on from.
3379 There may be up to 8 workstations, with the names separated by
3380 commas. A null strings indicates there are no restrictions.
3382 usri11_max_storage specifies the maximum amount of disk space the user
3383 can occupy. A value of 0xffffffff indicates there are no
3384 restrictions.
3386 usri11_units_per_week specifies the equal number of time units into
3387 which a week is divided. This value must be equal to 168.
3389 usri11_logon_hours points to a 21 byte (168 bits) string that
3390 specifies the time during which the user can log on. Each bit
3391 represents one unique hour in a week. The first bit (bit 0, word
3392 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3396 Leach, Naik [Page 29]
3400 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3403 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3404 are no restrictions.
3406 usri11_code_page specifies the code page for the user's language of
3407 choice
3409 All of the pointers in this data structure need to be treated
3410 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3411 to be ignored. The converter word returned in the parameters section
3412 needs to be subtracted from the lower 16 bits to calculate an offset
3413 into the return buffer where this ASCII string resides.
3415 There is no auxiliary data in the response.
3417 ****************************************************************************/
3419 #define usri11_name 0
3420 #define usri11_pad 21
3421 #define usri11_comment 22
3422 #define usri11_usr_comment 26
3423 #define usri11_full_name 30
3424 #define usri11_priv 34
3425 #define usri11_auth_flags 36
3426 #define usri11_password_age 40
3427 #define usri11_homedir 44
3428 #define usri11_parms 48
3429 #define usri11_last_logon 52
3430 #define usri11_last_logoff 56
3431 #define usri11_bad_pw_count 60
3432 #define usri11_num_logons 62
3433 #define usri11_logon_server 64
3434 #define usri11_country_code 68
3435 #define usri11_workstations 70
3436 #define usri11_max_storage 74
3437 #define usri11_units_per_week 78
3438 #define usri11_logon_hours 80
3439 #define usri11_code_page 84
3440 #define usri11_end 86
3442 #define USER_PRIV_GUEST 0
3443 #define USER_PRIV_USER 1
3444 #define USER_PRIV_ADMIN 2
3446 #define AF_OP_PRINT 0
3447 #define AF_OP_COMM 1
3448 #define AF_OP_SERVER 2
3449 #define AF_OP_ACCOUNTS 3
3452 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3453 char *param, int tpscnt,
3454 char *data, int tdscnt,
3455 int mdrcnt,int mprcnt,
3456 char **rdata,char **rparam,
3457 int *rdata_len,int *rparam_len)
3459 struct smbd_server_connection *sconn = smbd_server_conn;
3460 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3461 char *str2 = skip_string(param,tpscnt,str1);
3462 char *UserName = skip_string(param,tpscnt,str2);
3463 char *p = skip_string(param,tpscnt,UserName);
3464 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3465 char *p2;
3466 char *endp;
3467 const char *level_string;
3469 /* get NIS home of a previously validated user - simeon */
3470 /* With share level security vuid will always be zero.
3471 Don't depend on vuser being non-null !!. JRA */
3472 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3473 if(vuser != NULL) {
3474 DEBUG(3,(" Username of UID %d is %s\n",
3475 (int)vuser->server_info->utok.uid,
3476 vuser->server_info->unix_name));
3479 if (!str1 || !str2 || !UserName || !p) {
3480 return False;
3483 *rparam_len = 6;
3484 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3485 if (!*rparam) {
3486 return False;
3489 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3491 /* check it's a supported variant */
3492 if (strcmp(str1,"zWrLh") != 0) {
3493 return False;
3495 switch( uLevel ) {
3496 case 0: level_string = "B21"; break;
3497 case 1: level_string = "B21BB16DWzzWz"; break;
3498 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3499 case 10: level_string = "B21Bzzz"; break;
3500 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3501 default: return False;
3504 if (strcmp(level_string,str2) != 0) {
3505 return False;
3508 *rdata_len = mdrcnt + 1024;
3509 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3510 if (!*rdata) {
3511 return False;
3514 SSVAL(*rparam,0,NERR_Success);
3515 SSVAL(*rparam,2,0); /* converter word */
3517 p = *rdata;
3518 endp = *rdata + *rdata_len;
3519 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3520 if (!p2) {
3521 return False;
3524 memset(p,0,21);
3525 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3527 if (uLevel > 0) {
3528 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3529 *p2 = 0;
3532 if (uLevel >= 10) {
3533 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3534 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3535 p2 = skip_string(*rdata,*rdata_len,p2);
3536 if (!p2) {
3537 return False;
3540 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3541 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3542 p2 = skip_string(*rdata,*rdata_len,p2);
3543 if (!p2) {
3544 return False;
3547 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3548 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3549 strlcpy(p2,((vuser != NULL)
3550 ? pdb_get_fullname(vuser->server_info->sam_account)
3551 : UserName),PTR_DIFF(endp,p2));
3552 p2 = skip_string(*rdata,*rdata_len,p2);
3553 if (!p2) {
3554 return False;
3558 if (uLevel == 11) {
3559 const char *homedir = "";
3560 if (vuser != NULL) {
3561 homedir = pdb_get_homedir(
3562 vuser->server_info->sam_account);
3564 /* modelled after NTAS 3.51 reply */
3565 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3566 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3567 SIVALS(p,usri11_password_age,-1); /* password age */
3568 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3569 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3570 p2 = skip_string(*rdata,*rdata_len,p2);
3571 if (!p2) {
3572 return False;
3574 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3575 strlcpy(p2,"",PTR_DIFF(endp,p2));
3576 p2 = skip_string(*rdata,*rdata_len,p2);
3577 if (!p2) {
3578 return False;
3580 SIVAL(p,usri11_last_logon,0); /* last logon */
3581 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3582 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3583 SSVALS(p,usri11_num_logons,-1); /* num logons */
3584 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3585 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3586 p2 = skip_string(*rdata,*rdata_len,p2);
3587 if (!p2) {
3588 return False;
3590 SSVAL(p,usri11_country_code,0); /* country code */
3592 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3593 strlcpy(p2,"",PTR_DIFF(endp,p2));
3594 p2 = skip_string(*rdata,*rdata_len,p2);
3595 if (!p2) {
3596 return False;
3599 SIVALS(p,usri11_max_storage,-1); /* max storage */
3600 SSVAL(p,usri11_units_per_week,168); /* units per week */
3601 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3603 /* a simple way to get logon hours at all times. */
3604 memset(p2,0xff,21);
3605 SCVAL(p2,21,0); /* fix zero termination */
3606 p2 = skip_string(*rdata,*rdata_len,p2);
3607 if (!p2) {
3608 return False;
3611 SSVAL(p,usri11_code_page,0); /* code page */
3614 if (uLevel == 1 || uLevel == 2) {
3615 memset(p+22,' ',16); /* password */
3616 SIVALS(p,38,-1); /* password age */
3617 SSVAL(p,42,
3618 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3619 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3620 strlcpy(p2, vuser ? pdb_get_homedir(
3621 vuser->server_info->sam_account) : "",
3622 PTR_DIFF(endp,p2));
3623 p2 = skip_string(*rdata,*rdata_len,p2);
3624 if (!p2) {
3625 return False;
3627 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3628 *p2++ = 0;
3629 SSVAL(p,52,0); /* flags */
3630 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3631 strlcpy(p2, vuser ? pdb_get_logon_script(
3632 vuser->server_info->sam_account) : "",
3633 PTR_DIFF(endp,p2));
3634 p2 = skip_string(*rdata,*rdata_len,p2);
3635 if (!p2) {
3636 return False;
3638 if (uLevel == 2) {
3639 SIVAL(p,60,0); /* auth_flags */
3640 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3641 strlcpy(p2,((vuser != NULL)
3642 ? pdb_get_fullname(vuser->server_info->sam_account)
3643 : UserName),PTR_DIFF(endp,p2));
3644 p2 = skip_string(*rdata,*rdata_len,p2);
3645 if (!p2) {
3646 return False;
3648 SIVAL(p,68,0); /* urs_comment */
3649 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3650 strlcpy(p2,"",PTR_DIFF(endp,p2));
3651 p2 = skip_string(*rdata,*rdata_len,p2);
3652 if (!p2) {
3653 return False;
3655 SIVAL(p,76,0); /* workstations */
3656 SIVAL(p,80,0); /* last_logon */
3657 SIVAL(p,84,0); /* last_logoff */
3658 SIVALS(p,88,-1); /* acct_expires */
3659 SIVALS(p,92,-1); /* max_storage */
3660 SSVAL(p,96,168); /* units_per_week */
3661 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3662 memset(p2,-1,21);
3663 p2 += 21;
3664 SSVALS(p,102,-1); /* bad_pw_count */
3665 SSVALS(p,104,-1); /* num_logons */
3666 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3668 TALLOC_CTX *ctx = talloc_tos();
3669 int space_rem = *rdata_len - (p2 - *rdata);
3670 char *tmp;
3672 if (space_rem <= 0) {
3673 return false;
3675 tmp = talloc_strdup(ctx, "\\\\%L");
3676 if (!tmp) {
3677 return false;
3679 tmp = talloc_sub_basic(ctx,
3682 tmp);
3683 if (!tmp) {
3684 return false;
3687 push_ascii(p2,
3688 tmp,
3689 space_rem,
3690 STR_TERMINATE);
3692 p2 = skip_string(*rdata,*rdata_len,p2);
3693 if (!p2) {
3694 return False;
3696 SSVAL(p,110,49); /* country_code */
3697 SSVAL(p,112,860); /* code page */
3701 *rdata_len = PTR_DIFF(p2,*rdata);
3703 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3705 return(True);
3708 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3709 char *param, int tpscnt,
3710 char *data, int tdscnt,
3711 int mdrcnt,int mprcnt,
3712 char **rdata,char **rparam,
3713 int *rdata_len,int *rparam_len)
3715 struct smbd_server_connection *sconn = smbd_server_conn;
3716 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3717 char *str2 = skip_string(param,tpscnt,str1);
3718 char *p = skip_string(param,tpscnt,str2);
3719 int uLevel;
3720 struct pack_desc desc;
3721 char* name;
3722 /* With share level security vuid will always be zero.
3723 Don't depend on vuser being non-null !!. JRA */
3724 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3726 if (!str1 || !str2 || !p) {
3727 return False;
3730 if(vuser != NULL) {
3731 DEBUG(3,(" Username of UID %d is %s\n",
3732 (int)vuser->server_info->utok.uid,
3733 vuser->server_info->unix_name));
3736 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3737 name = get_safe_str_ptr(param,tpscnt,p,2);
3738 if (!name) {
3739 return False;
3742 memset((char *)&desc,'\0',sizeof(desc));
3744 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3746 /* check it's a supported varient */
3747 if (strcmp(str1,"OOWb54WrLh") != 0) {
3748 return False;
3750 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3751 return False;
3753 if (mdrcnt > 0) {
3754 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3755 if (!*rdata) {
3756 return False;
3760 desc.base = *rdata;
3761 desc.buflen = mdrcnt;
3762 desc.subformat = NULL;
3763 desc.format = str2;
3765 if (init_package(&desc,1,0)) {
3766 PACKI(&desc,"W",0); /* code */
3767 PACKS(&desc,"B21",name); /* eff. name */
3768 PACKS(&desc,"B",""); /* pad */
3769 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3770 PACKI(&desc,"D",0); /* auth flags XXX */
3771 PACKI(&desc,"W",0); /* num logons */
3772 PACKI(&desc,"W",0); /* bad pw count */
3773 PACKI(&desc,"D",0); /* last logon */
3774 PACKI(&desc,"D",-1); /* last logoff */
3775 PACKI(&desc,"D",-1); /* logoff time */
3776 PACKI(&desc,"D",-1); /* kickoff time */
3777 PACKI(&desc,"D",0); /* password age */
3778 PACKI(&desc,"D",0); /* password can change */
3779 PACKI(&desc,"D",-1); /* password must change */
3782 fstring mypath;
3783 fstrcpy(mypath,"\\\\");
3784 fstrcat(mypath,get_local_machine_name());
3785 strupper_m(mypath);
3786 PACKS(&desc,"z",mypath); /* computer */
3789 PACKS(&desc,"z",lp_workgroup());/* domain */
3790 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3791 vuser->server_info->sam_account) : ""); /* script path */
3792 PACKI(&desc,"D",0x00000000); /* reserved */
3795 *rdata_len = desc.usedlen;
3796 *rparam_len = 6;
3797 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3798 if (!*rparam) {
3799 return False;
3801 SSVALS(*rparam,0,desc.errcode);
3802 SSVAL(*rparam,2,0);
3803 SSVAL(*rparam,4,desc.neededlen);
3805 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3807 return True;
3810 /****************************************************************************
3811 api_WAccessGetUserPerms
3812 ****************************************************************************/
3814 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3815 char *param, int tpscnt,
3816 char *data, int tdscnt,
3817 int mdrcnt,int mprcnt,
3818 char **rdata,char **rparam,
3819 int *rdata_len,int *rparam_len)
3821 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3822 char *str2 = skip_string(param,tpscnt,str1);
3823 char *user = skip_string(param,tpscnt,str2);
3824 char *resource = skip_string(param,tpscnt,user);
3826 if (!str1 || !str2 || !user || !resource) {
3827 return False;
3830 if (skip_string(param,tpscnt,resource) == NULL) {
3831 return False;
3833 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3835 /* check it's a supported varient */
3836 if (strcmp(str1,"zzh") != 0) {
3837 return False;
3839 if (strcmp(str2,"") != 0) {
3840 return False;
3843 *rparam_len = 6;
3844 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3845 if (!*rparam) {
3846 return False;
3848 SSVALS(*rparam,0,0); /* errorcode */
3849 SSVAL(*rparam,2,0); /* converter word */
3850 SSVAL(*rparam,4,0x7f); /* permission flags */
3852 return True;
3855 /****************************************************************************
3856 api_WPrintJobEnumerate
3857 ****************************************************************************/
3859 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3860 char *param, int tpscnt,
3861 char *data, int tdscnt,
3862 int mdrcnt,int mprcnt,
3863 char **rdata,char **rparam,
3864 int *rdata_len,int *rparam_len)
3866 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3867 char *str2 = skip_string(param,tpscnt,str1);
3868 char *p = skip_string(param,tpscnt,str2);
3869 int uLevel;
3870 int count;
3871 int i;
3872 int snum;
3873 fstring sharename;
3874 uint32 jobid;
3875 struct pack_desc desc;
3876 print_queue_struct *queue=NULL;
3877 print_status_struct status;
3878 char *tmpdata=NULL;
3880 if (!str1 || !str2 || !p) {
3881 return False;
3884 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3886 memset((char *)&desc,'\0',sizeof(desc));
3887 memset((char *)&status,'\0',sizeof(status));
3889 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3891 /* check it's a supported varient */
3892 if (strcmp(str1,"WWrLh") != 0) {
3893 return False;
3895 if (!check_printjob_info(&desc,uLevel,str2)) {
3896 return False;
3899 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3900 return False;
3903 snum = lp_servicenumber( sharename);
3904 if (snum < 0 || !VALID_SNUM(snum)) {
3905 return(False);
3908 count = print_queue_status(snum,&queue,&status);
3909 for (i = 0; i < count; i++) {
3910 if (queue[i].job == jobid) {
3911 break;
3915 if (mdrcnt > 0) {
3916 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3917 if (!*rdata) {
3918 return False;
3920 desc.base = *rdata;
3921 desc.buflen = mdrcnt;
3922 } else {
3924 * Don't return data but need to get correct length
3925 * init_package will return wrong size if buflen=0
3927 desc.buflen = getlen(desc.format);
3928 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3931 if (init_package(&desc,1,0)) {
3932 if (i < count) {
3933 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3934 *rdata_len = desc.usedlen;
3935 } else {
3936 desc.errcode = NERR_JobNotFound;
3937 *rdata_len = 0;
3941 *rparam_len = 6;
3942 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3943 if (!*rparam) {
3944 return False;
3946 SSVALS(*rparam,0,desc.errcode);
3947 SSVAL(*rparam,2,0);
3948 SSVAL(*rparam,4,desc.neededlen);
3950 SAFE_FREE(queue);
3951 SAFE_FREE(tmpdata);
3953 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3955 return True;
3958 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3959 char *param, int tpscnt,
3960 char *data, int tdscnt,
3961 int mdrcnt,int mprcnt,
3962 char **rdata,char **rparam,
3963 int *rdata_len,int *rparam_len)
3965 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3966 char *str2 = skip_string(param,tpscnt,str1);
3967 char *p = skip_string(param,tpscnt,str2);
3968 char *name = p;
3969 int uLevel;
3970 int count;
3971 int i, succnt=0;
3972 int snum;
3973 struct pack_desc desc;
3974 print_queue_struct *queue=NULL;
3975 print_status_struct status;
3977 if (!str1 || !str2 || !p) {
3978 return False;
3981 memset((char *)&desc,'\0',sizeof(desc));
3982 memset((char *)&status,'\0',sizeof(status));
3984 p = skip_string(param,tpscnt,p);
3985 if (!p) {
3986 return False;
3988 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3990 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3992 /* check it's a supported variant */
3993 if (strcmp(str1,"zWrLeh") != 0) {
3994 return False;
3997 if (uLevel > 2) {
3998 return False; /* defined only for uLevel 0,1,2 */
4001 if (!check_printjob_info(&desc,uLevel,str2)) {
4002 return False;
4005 snum = find_service(name);
4006 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4007 return False;
4010 count = print_queue_status(snum,&queue,&status);
4011 if (mdrcnt > 0) {
4012 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4013 if (!*rdata) {
4014 return False;
4017 desc.base = *rdata;
4018 desc.buflen = mdrcnt;
4020 if (init_package(&desc,count,0)) {
4021 succnt = 0;
4022 for (i = 0; i < count; i++) {
4023 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4024 if (desc.errcode == NERR_Success) {
4025 succnt = i+1;
4030 *rdata_len = desc.usedlen;
4032 *rparam_len = 8;
4033 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4034 if (!*rparam) {
4035 return False;
4037 SSVALS(*rparam,0,desc.errcode);
4038 SSVAL(*rparam,2,0);
4039 SSVAL(*rparam,4,succnt);
4040 SSVAL(*rparam,6,count);
4042 SAFE_FREE(queue);
4044 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4046 return True;
4049 static int check_printdest_info(struct pack_desc* desc,
4050 int uLevel, char* id)
4052 desc->subformat = NULL;
4053 switch( uLevel ) {
4054 case 0:
4055 desc->format = "B9";
4056 break;
4057 case 1:
4058 desc->format = "B9B21WWzW";
4059 break;
4060 case 2:
4061 desc->format = "z";
4062 break;
4063 case 3:
4064 desc->format = "zzzWWzzzWW";
4065 break;
4066 default:
4067 DEBUG(0,("check_printdest_info: invalid level %d\n",
4068 uLevel));
4069 return False;
4071 if (id == NULL || strcmp(desc->format,id) != 0) {
4072 DEBUG(0,("check_printdest_info: invalid string %s\n",
4073 id ? id : "<NULL>" ));
4074 return False;
4076 return True;
4079 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4080 struct pack_desc* desc)
4082 char buf[100];
4084 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4085 buf[sizeof(buf)-1] = 0;
4086 strupper_m(buf);
4088 if (uLevel <= 1) {
4089 PACKS(desc,"B9",buf); /* szName */
4090 if (uLevel == 1) {
4091 PACKS(desc,"B21",""); /* szUserName */
4092 PACKI(desc,"W",0); /* uJobId */
4093 PACKI(desc,"W",0); /* fsStatus */
4094 PACKS(desc,"z",""); /* pszStatus */
4095 PACKI(desc,"W",0); /* time */
4099 if (uLevel == 2 || uLevel == 3) {
4100 PACKS(desc,"z",buf); /* pszPrinterName */
4101 if (uLevel == 3) {
4102 PACKS(desc,"z",""); /* pszUserName */
4103 PACKS(desc,"z",""); /* pszLogAddr */
4104 PACKI(desc,"W",0); /* uJobId */
4105 PACKI(desc,"W",0); /* fsStatus */
4106 PACKS(desc,"z",""); /* pszStatus */
4107 PACKS(desc,"z",""); /* pszComment */
4108 PACKS(desc,"z","NULL"); /* pszDrivers */
4109 PACKI(desc,"W",0); /* time */
4110 PACKI(desc,"W",0); /* pad1 */
4115 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4116 char *param, int tpscnt,
4117 char *data, int tdscnt,
4118 int mdrcnt,int mprcnt,
4119 char **rdata,char **rparam,
4120 int *rdata_len,int *rparam_len)
4122 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4123 char *str2 = skip_string(param,tpscnt,str1);
4124 char *p = skip_string(param,tpscnt,str2);
4125 char* PrinterName = p;
4126 int uLevel;
4127 struct pack_desc desc;
4128 int snum;
4129 char *tmpdata=NULL;
4131 if (!str1 || !str2 || !p) {
4132 return False;
4135 memset((char *)&desc,'\0',sizeof(desc));
4137 p = skip_string(param,tpscnt,p);
4138 if (!p) {
4139 return False;
4141 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4143 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4145 /* check it's a supported varient */
4146 if (strcmp(str1,"zWrLh") != 0) {
4147 return False;
4149 if (!check_printdest_info(&desc,uLevel,str2)) {
4150 return False;
4153 snum = find_service(PrinterName);
4154 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4155 *rdata_len = 0;
4156 desc.errcode = NERR_DestNotFound;
4157 desc.neededlen = 0;
4158 } else {
4159 if (mdrcnt > 0) {
4160 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4161 if (!*rdata) {
4162 return False;
4164 desc.base = *rdata;
4165 desc.buflen = mdrcnt;
4166 } else {
4168 * Don't return data but need to get correct length
4169 * init_package will return wrong size if buflen=0
4171 desc.buflen = getlen(desc.format);
4172 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4174 if (init_package(&desc,1,0)) {
4175 fill_printdest_info(conn,snum,uLevel,&desc);
4177 *rdata_len = desc.usedlen;
4180 *rparam_len = 6;
4181 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4182 if (!*rparam) {
4183 return False;
4185 SSVALS(*rparam,0,desc.errcode);
4186 SSVAL(*rparam,2,0);
4187 SSVAL(*rparam,4,desc.neededlen);
4189 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4190 SAFE_FREE(tmpdata);
4192 return True;
4195 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4196 char *param, int tpscnt,
4197 char *data, int tdscnt,
4198 int mdrcnt,int mprcnt,
4199 char **rdata,char **rparam,
4200 int *rdata_len,int *rparam_len)
4202 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4203 char *str2 = skip_string(param,tpscnt,str1);
4204 char *p = skip_string(param,tpscnt,str2);
4205 int uLevel;
4206 int queuecnt;
4207 int i, n, succnt=0;
4208 struct pack_desc desc;
4209 int services = lp_numservices();
4211 if (!str1 || !str2 || !p) {
4212 return False;
4215 memset((char *)&desc,'\0',sizeof(desc));
4217 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4219 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4221 /* check it's a supported varient */
4222 if (strcmp(str1,"WrLeh") != 0) {
4223 return False;
4225 if (!check_printdest_info(&desc,uLevel,str2)) {
4226 return False;
4229 queuecnt = 0;
4230 for (i = 0; i < services; i++) {
4231 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4232 queuecnt++;
4236 if (mdrcnt > 0) {
4237 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4238 if (!*rdata) {
4239 return False;
4243 desc.base = *rdata;
4244 desc.buflen = mdrcnt;
4245 if (init_package(&desc,queuecnt,0)) {
4246 succnt = 0;
4247 n = 0;
4248 for (i = 0; i < services; i++) {
4249 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4250 fill_printdest_info(conn,i,uLevel,&desc);
4251 n++;
4252 if (desc.errcode == NERR_Success) {
4253 succnt = n;
4259 *rdata_len = desc.usedlen;
4261 *rparam_len = 8;
4262 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4263 if (!*rparam) {
4264 return False;
4266 SSVALS(*rparam,0,desc.errcode);
4267 SSVAL(*rparam,2,0);
4268 SSVAL(*rparam,4,succnt);
4269 SSVAL(*rparam,6,queuecnt);
4271 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4273 return True;
4276 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4277 char *param, int tpscnt,
4278 char *data, int tdscnt,
4279 int mdrcnt,int mprcnt,
4280 char **rdata,char **rparam,
4281 int *rdata_len,int *rparam_len)
4283 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4284 char *str2 = skip_string(param,tpscnt,str1);
4285 char *p = skip_string(param,tpscnt,str2);
4286 int uLevel;
4287 int succnt;
4288 struct pack_desc desc;
4290 if (!str1 || !str2 || !p) {
4291 return False;
4294 memset((char *)&desc,'\0',sizeof(desc));
4296 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4298 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4300 /* check it's a supported varient */
4301 if (strcmp(str1,"WrLeh") != 0) {
4302 return False;
4304 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4305 return False;
4308 if (mdrcnt > 0) {
4309 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4310 if (!*rdata) {
4311 return False;
4314 desc.base = *rdata;
4315 desc.buflen = mdrcnt;
4316 if (init_package(&desc,1,0)) {
4317 PACKS(&desc,"B41","NULL");
4320 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4322 *rdata_len = desc.usedlen;
4324 *rparam_len = 8;
4325 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4326 if (!*rparam) {
4327 return False;
4329 SSVALS(*rparam,0,desc.errcode);
4330 SSVAL(*rparam,2,0);
4331 SSVAL(*rparam,4,succnt);
4332 SSVAL(*rparam,6,1);
4334 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4336 return True;
4339 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4340 char *param, int tpscnt,
4341 char *data, int tdscnt,
4342 int mdrcnt,int mprcnt,
4343 char **rdata,char **rparam,
4344 int *rdata_len,int *rparam_len)
4346 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4347 char *str2 = skip_string(param,tpscnt,str1);
4348 char *p = skip_string(param,tpscnt,str2);
4349 int uLevel;
4350 int succnt;
4351 struct pack_desc desc;
4353 if (!str1 || !str2 || !p) {
4354 return False;
4356 memset((char *)&desc,'\0',sizeof(desc));
4358 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4360 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4362 /* check it's a supported varient */
4363 if (strcmp(str1,"WrLeh") != 0) {
4364 return False;
4366 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4367 return False;
4370 if (mdrcnt > 0) {
4371 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4372 if (!*rdata) {
4373 return False;
4376 desc.base = *rdata;
4377 desc.buflen = mdrcnt;
4378 desc.format = str2;
4379 if (init_package(&desc,1,0)) {
4380 PACKS(&desc,"B13","lpd");
4383 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4385 *rdata_len = desc.usedlen;
4387 *rparam_len = 8;
4388 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4389 if (!*rparam) {
4390 return False;
4392 SSVALS(*rparam,0,desc.errcode);
4393 SSVAL(*rparam,2,0);
4394 SSVAL(*rparam,4,succnt);
4395 SSVAL(*rparam,6,1);
4397 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4399 return True;
4402 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4403 char *param, int tpscnt,
4404 char *data, int tdscnt,
4405 int mdrcnt,int mprcnt,
4406 char **rdata,char **rparam,
4407 int *rdata_len,int *rparam_len)
4409 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4410 char *str2 = skip_string(param,tpscnt,str1);
4411 char *p = skip_string(param,tpscnt,str2);
4412 int uLevel;
4413 int succnt;
4414 struct pack_desc desc;
4416 if (!str1 || !str2 || !p) {
4417 return False;
4420 memset((char *)&desc,'\0',sizeof(desc));
4422 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4424 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4426 /* check it's a supported varient */
4427 if (strcmp(str1,"WrLeh") != 0) {
4428 return False;
4430 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4431 return False;
4434 if (mdrcnt > 0) {
4435 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4436 if (!*rdata) {
4437 return False;
4440 memset((char *)&desc,'\0',sizeof(desc));
4441 desc.base = *rdata;
4442 desc.buflen = mdrcnt;
4443 desc.format = str2;
4444 if (init_package(&desc,1,0)) {
4445 PACKS(&desc,"B13","lp0");
4448 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4450 *rdata_len = desc.usedlen;
4452 *rparam_len = 8;
4453 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4454 if (!*rparam) {
4455 return False;
4457 SSVALS(*rparam,0,desc.errcode);
4458 SSVAL(*rparam,2,0);
4459 SSVAL(*rparam,4,succnt);
4460 SSVAL(*rparam,6,1);
4462 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4464 return True;
4467 /****************************************************************************
4468 List open sessions
4469 ****************************************************************************/
4471 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4472 char *param, int tpscnt,
4473 char *data, int tdscnt,
4474 int mdrcnt,int mprcnt,
4475 char **rdata,char **rparam,
4476 int *rdata_len,int *rparam_len)
4479 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4480 char *str2 = skip_string(param,tpscnt,str1);
4481 char *p = skip_string(param,tpscnt,str2);
4482 int uLevel;
4483 struct pack_desc desc;
4484 struct sessionid *session_list;
4485 int i, num_sessions;
4487 if (!str1 || !str2 || !p) {
4488 return False;
4491 memset((char *)&desc,'\0',sizeof(desc));
4493 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4495 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4496 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4497 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4499 /* check it's a supported varient */
4500 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4501 return False;
4503 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4504 return False;
4507 num_sessions = list_sessions(talloc_tos(), &session_list);
4509 if (mdrcnt > 0) {
4510 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4511 if (!*rdata) {
4512 return False;
4515 memset((char *)&desc,'\0',sizeof(desc));
4516 desc.base = *rdata;
4517 desc.buflen = mdrcnt;
4518 desc.format = str2;
4519 if (!init_package(&desc,num_sessions,0)) {
4520 return False;
4523 for(i=0; i<num_sessions; i++) {
4524 PACKS(&desc, "z", session_list[i].remote_machine);
4525 PACKS(&desc, "z", session_list[i].username);
4526 PACKI(&desc, "W", 1); /* num conns */
4527 PACKI(&desc, "W", 0); /* num opens */
4528 PACKI(&desc, "W", 1); /* num users */
4529 PACKI(&desc, "D", 0); /* session time */
4530 PACKI(&desc, "D", 0); /* idle time */
4531 PACKI(&desc, "D", 0); /* flags */
4532 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4535 *rdata_len = desc.usedlen;
4537 *rparam_len = 8;
4538 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4539 if (!*rparam) {
4540 return False;
4542 SSVALS(*rparam,0,desc.errcode);
4543 SSVAL(*rparam,2,0); /* converter */
4544 SSVAL(*rparam,4,num_sessions); /* count */
4546 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4548 return True;
4552 /****************************************************************************
4553 The buffer was too small.
4554 ****************************************************************************/
4556 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4557 int mdrcnt, int mprcnt,
4558 char **rdata, char **rparam,
4559 int *rdata_len, int *rparam_len)
4561 *rparam_len = MIN(*rparam_len,mprcnt);
4562 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4563 if (!*rparam) {
4564 return False;
4567 *rdata_len = 0;
4569 SSVAL(*rparam,0,NERR_BufTooSmall);
4571 DEBUG(3,("Supplied buffer too small in API command\n"));
4573 return True;
4576 /****************************************************************************
4577 The request is not supported.
4578 ****************************************************************************/
4580 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4581 char *param, int tpscnt,
4582 char *data, int tdscnt,
4583 int mdrcnt, int mprcnt,
4584 char **rdata, char **rparam,
4585 int *rdata_len, int *rparam_len)
4587 *rparam_len = 4;
4588 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4589 if (!*rparam) {
4590 return False;
4593 *rdata_len = 0;
4595 SSVAL(*rparam,0,NERR_notsupported);
4596 SSVAL(*rparam,2,0); /* converter word */
4598 DEBUG(3,("Unsupported API command\n"));
4600 return True;
4603 static const struct {
4604 const char *name;
4605 int id;
4606 bool (*fn)(connection_struct *, uint16,
4607 char *, int,
4608 char *, int,
4609 int,int,char **,char **,int *,int *);
4610 bool auth_user; /* Deny anonymous access? */
4611 } api_commands[] = {
4612 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4613 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4614 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4615 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4616 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4617 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4618 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4619 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4620 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4621 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4622 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4623 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4624 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4625 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4626 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4627 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4628 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4629 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4630 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4631 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4632 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4633 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4634 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4635 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4636 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
4637 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4638 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4639 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4640 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4641 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4642 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4643 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4644 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4645 {NULL, -1, api_Unsupported}
4646 /* The following RAP calls are not implemented by Samba:
4648 RAP_WFileEnum2 - anon not OK
4653 /****************************************************************************
4654 Handle remote api calls.
4655 ****************************************************************************/
4657 void api_reply(connection_struct *conn, uint16 vuid,
4658 struct smb_request *req,
4659 char *data, char *params,
4660 int tdscnt, int tpscnt,
4661 int mdrcnt, int mprcnt)
4663 struct smbd_server_connection *sconn = smbd_server_conn;
4664 int api_command;
4665 char *rdata = NULL;
4666 char *rparam = NULL;
4667 const char *name1 = NULL;
4668 const char *name2 = NULL;
4669 int rdata_len = 0;
4670 int rparam_len = 0;
4671 bool reply=False;
4672 int i;
4674 if (!params) {
4675 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4676 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4677 return;
4680 if (tpscnt < 2) {
4681 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4682 return;
4684 api_command = SVAL(params,0);
4685 /* Is there a string at position params+2 ? */
4686 if (skip_string(params,tpscnt,params+2)) {
4687 name1 = params + 2;
4688 } else {
4689 name1 = "";
4691 name2 = skip_string(params,tpscnt,params+2);
4692 if (!name2) {
4693 name2 = "";
4696 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4697 api_command,
4698 name1,
4699 name2,
4700 tdscnt,tpscnt,mdrcnt,mprcnt));
4702 for (i=0;api_commands[i].name;i++) {
4703 if (api_commands[i].id == api_command && api_commands[i].fn) {
4704 DEBUG(3,("Doing %s\n",api_commands[i].name));
4705 break;
4709 /* Check whether this api call can be done anonymously */
4711 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4712 user_struct *user = get_valid_user_struct(sconn, vuid);
4714 if (!user || user->server_info->guest) {
4715 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4716 return;
4720 rdata = (char *)SMB_MALLOC(1024);
4721 if (rdata) {
4722 memset(rdata,'\0',1024);
4725 rparam = (char *)SMB_MALLOC(1024);
4726 if (rparam) {
4727 memset(rparam,'\0',1024);
4730 if(!rdata || !rparam) {
4731 DEBUG(0,("api_reply: malloc fail !\n"));
4732 SAFE_FREE(rdata);
4733 SAFE_FREE(rparam);
4734 reply_nterror(req, NT_STATUS_NO_MEMORY);
4735 return;
4738 reply = api_commands[i].fn(conn,
4739 vuid,
4740 params,tpscnt, /* params + length */
4741 data,tdscnt, /* data + length */
4742 mdrcnt,mprcnt,
4743 &rdata,&rparam,&rdata_len,&rparam_len);
4746 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4747 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4748 &rdata,&rparam,&rdata_len,&rparam_len);
4751 /* if we get False back then it's actually unsupported */
4752 if (!reply) {
4753 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4754 &rdata,&rparam,&rdata_len,&rparam_len);
4757 /* If api_Unsupported returns false we can't return anything. */
4758 if (reply) {
4759 send_trans_reply(conn, req, rparam, rparam_len,
4760 rdata, rdata_len, False);
4763 SAFE_FREE(rdata);
4764 SAFE_FREE(rparam);
4765 return;