s3:smbd: rename api_RNetServerEnum => api_RNetServerEnum2
[Samba/gbeck.git] / source3 / smbd / lanman.c
blobb969cd82c11ac41b8e40650776f527872bdb2780
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 if (lp_browse_list()) {
1433 total = get_server_info(servertype,&servers,domain);
1436 data_len = fixed_len = string_len = 0;
1437 missed = 0;
1439 if (total > 0) {
1440 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1444 char *lastname=NULL;
1446 for (i=0;i<total;i++) {
1447 struct srv_info_struct *s = &servers[i];
1449 if (lastname && strequal(lastname,s->name)) {
1450 continue;
1452 lastname = s->name;
1453 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1454 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1455 s->name, s->type, s->comment, s->domain));
1457 if (data_len <= buf_len) {
1458 counted++;
1459 fixed_len += f_len;
1460 string_len += s_len;
1461 } else {
1462 missed++;
1467 *rdata_len = fixed_len + string_len;
1468 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1469 if (!*rdata) {
1470 return False;
1473 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1474 p = *rdata;
1475 f_len = fixed_len;
1476 s_len = string_len;
1479 char *lastname=NULL;
1480 int count2 = counted;
1482 for (i = 0; i < total && count2;i++) {
1483 struct srv_info_struct *s = &servers[i];
1485 if (lastname && strequal(lastname,s->name)) {
1486 continue;
1488 lastname = s->name;
1489 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1490 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1491 s->name, s->type, s->comment, s->domain));
1492 count2--;
1496 *rparam_len = 8;
1497 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1498 if (!*rparam) {
1499 return False;
1501 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1502 SSVAL(*rparam,2,0);
1503 SSVAL(*rparam,4,counted);
1504 SSVAL(*rparam,6,counted+missed);
1506 SAFE_FREE(servers);
1508 DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
1509 domain,uLevel,counted,counted+missed));
1511 return True;
1514 /****************************************************************************
1515 command 0x34 - suspected of being a "Lookup Names" stub api
1516 ****************************************************************************/
1518 static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
1519 char *param, int tpscnt,
1520 char *data, int tdscnt,
1521 int mdrcnt, int mprcnt, char **rdata,
1522 char **rparam, int *rdata_len, int *rparam_len)
1524 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1525 char *str2 = skip_string(param,tpscnt,str1);
1526 char *p = skip_string(param,tpscnt,str2);
1527 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1528 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1529 int counted=0;
1530 int missed=0;
1532 if (!str1 || !str2 || !p) {
1533 return False;
1536 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1537 str1, str2, p, uLevel, buf_len));
1539 if (!prefix_ok(str1,"zWrLeh")) {
1540 return False;
1543 *rdata_len = 0;
1545 *rparam_len = 8;
1546 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1547 if (!*rparam) {
1548 return False;
1551 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1552 SSVAL(*rparam,2,0);
1553 SSVAL(*rparam,4,counted);
1554 SSVAL(*rparam,6,counted+missed);
1556 return True;
1559 /****************************************************************************
1560 get info about a share
1561 ****************************************************************************/
1563 static bool check_share_info(int uLevel, char* id)
1565 switch( uLevel ) {
1566 case 0:
1567 if (strcmp(id,"B13") != 0) {
1568 return False;
1570 break;
1571 case 1:
1572 /* Level-2 descriptor is allowed (and ignored) */
1573 if (strcmp(id,"B13BWz") != 0 &&
1574 strcmp(id,"B13BWzWWWzB9B") != 0) {
1575 return False;
1577 break;
1578 case 2:
1579 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1580 return False;
1582 break;
1583 case 91:
1584 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1585 return False;
1587 break;
1588 default:
1589 return False;
1591 return True;
1594 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1595 char** buf, int* buflen,
1596 char** stringbuf, int* stringspace, char* baseaddr)
1598 int struct_len;
1599 char* p;
1600 char* p2;
1601 int l2;
1602 int len;
1604 switch( uLevel ) {
1605 case 0:
1606 struct_len = 13;
1607 break;
1608 case 1:
1609 struct_len = 20;
1610 break;
1611 case 2:
1612 struct_len = 40;
1613 break;
1614 case 91:
1615 struct_len = 68;
1616 break;
1617 default:
1618 return -1;
1621 if (!buf) {
1622 len = 0;
1624 if (uLevel > 0) {
1625 len += StrlenExpanded(conn,snum,lp_comment(snum));
1627 if (uLevel > 1) {
1628 len += strlen(lp_pathname(snum)) + 1;
1630 if (buflen) {
1631 *buflen = struct_len;
1633 if (stringspace) {
1634 *stringspace = len;
1636 return struct_len + len;
1639 len = struct_len;
1640 p = *buf;
1641 if ((*buflen) < struct_len) {
1642 return -1;
1645 if (stringbuf) {
1646 p2 = *stringbuf;
1647 l2 = *stringspace;
1648 } else {
1649 p2 = p + struct_len;
1650 l2 = (*buflen) - struct_len;
1653 if (!baseaddr) {
1654 baseaddr = p;
1657 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1659 if (uLevel > 0) {
1660 int type;
1662 SCVAL(p,13,0);
1663 type = STYPE_DISKTREE;
1664 if (lp_print_ok(snum)) {
1665 type = STYPE_PRINTQ;
1667 if (strequal("IPC",lp_fstype(snum))) {
1668 type = STYPE_IPC;
1670 SSVAL(p,14,type); /* device type */
1671 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1672 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1675 if (uLevel > 1) {
1676 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1677 SSVALS(p,22,-1); /* max uses */
1678 SSVAL(p,24,1); /* current uses */
1679 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1680 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1681 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1684 if (uLevel > 2) {
1685 memset(p+40,0,SHPWLEN+2);
1686 SSVAL(p,50,0);
1687 SIVAL(p,52,0);
1688 SSVAL(p,56,0);
1689 SSVAL(p,58,0);
1690 SIVAL(p,60,0);
1691 SSVAL(p,64,0);
1692 SSVAL(p,66,0);
1695 if (stringbuf) {
1696 (*buf) = p + struct_len;
1697 (*buflen) -= struct_len;
1698 (*stringbuf) = p2;
1699 (*stringspace) = l2;
1700 } else {
1701 (*buf) = p2;
1702 (*buflen) -= len;
1705 return len;
1708 static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
1709 char *param, int tpscnt,
1710 char *data, int tdscnt,
1711 int mdrcnt,int mprcnt,
1712 char **rdata,char **rparam,
1713 int *rdata_len,int *rparam_len)
1715 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1716 char *str2 = skip_string(param,tpscnt,str1);
1717 char *netname = skip_string(param,tpscnt,str2);
1718 char *p = skip_string(param,tpscnt,netname);
1719 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1720 int snum;
1722 if (!str1 || !str2 || !netname || !p) {
1723 return False;
1726 snum = find_service(netname);
1727 if (snum < 0) {
1728 return False;
1731 /* check it's a supported varient */
1732 if (!prefix_ok(str1,"zWrLh")) {
1733 return False;
1735 if (!check_share_info(uLevel,str2)) {
1736 return False;
1739 *rdata = smb_realloc_limit(*rdata,mdrcnt);
1740 if (!*rdata) {
1741 return False;
1743 p = *rdata;
1744 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1745 if (*rdata_len < 0) {
1746 return False;
1749 *rparam_len = 6;
1750 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1751 if (!*rparam) {
1752 return False;
1754 SSVAL(*rparam,0,NERR_Success);
1755 SSVAL(*rparam,2,0); /* converter word */
1756 SSVAL(*rparam,4,*rdata_len);
1758 return True;
1761 /****************************************************************************
1762 View the list of available shares.
1764 This function is the server side of the NetShareEnum() RAP call.
1765 It fills the return buffer with share names and share comments.
1766 Note that the return buffer normally (in all known cases) allows only
1767 twelve byte strings for share names (plus one for a nul terminator).
1768 Share names longer than 12 bytes must be skipped.
1769 ****************************************************************************/
1771 static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
1772 char *param, int tpscnt,
1773 char *data, int tdscnt,
1774 int mdrcnt,
1775 int mprcnt,
1776 char **rdata,
1777 char **rparam,
1778 int *rdata_len,
1779 int *rparam_len )
1781 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1782 char *str2 = skip_string(param,tpscnt,str1);
1783 char *p = skip_string(param,tpscnt,str2);
1784 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1785 int buf_len = get_safe_SVAL(param,tpscnt,p,2,0);
1786 char *p2;
1787 int count = 0;
1788 int total=0,counted=0;
1789 bool missed = False;
1790 int i;
1791 int data_len, fixed_len, string_len;
1792 int f_len = 0, s_len = 0;
1794 if (!str1 || !str2 || !p) {
1795 return False;
1798 if (!prefix_ok(str1,"WrLeh")) {
1799 return False;
1801 if (!check_share_info(uLevel,str2)) {
1802 return False;
1805 /* Ensure all the usershares are loaded. */
1806 become_root();
1807 load_registry_shares();
1808 count = load_usershare_shares();
1809 unbecome_root();
1811 data_len = fixed_len = string_len = 0;
1812 for (i=0;i<count;i++) {
1813 fstring servicename_dos;
1814 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1815 continue;
1817 push_ascii_fstring(servicename_dos, lp_servicename(i));
1818 /* Maximum name length = 13. */
1819 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1820 total++;
1821 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1822 if (data_len <= buf_len) {
1823 counted++;
1824 fixed_len += f_len;
1825 string_len += s_len;
1826 } else {
1827 missed = True;
1832 *rdata_len = fixed_len + string_len;
1833 *rdata = smb_realloc_limit(*rdata,*rdata_len);
1834 if (!*rdata) {
1835 return False;
1838 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1839 p = *rdata;
1840 f_len = fixed_len;
1841 s_len = string_len;
1843 for( i = 0; i < count; i++ ) {
1844 fstring servicename_dos;
1845 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1846 continue;
1849 push_ascii_fstring(servicename_dos, lp_servicename(i));
1850 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1851 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1852 break;
1857 *rparam_len = 8;
1858 *rparam = smb_realloc_limit(*rparam,*rparam_len);
1859 if (!*rparam) {
1860 return False;
1862 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1863 SSVAL(*rparam,2,0);
1864 SSVAL(*rparam,4,counted);
1865 SSVAL(*rparam,6,total);
1867 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1868 counted,total,uLevel,
1869 buf_len,*rdata_len,mdrcnt));
1871 return True;
1874 /****************************************************************************
1875 Add a share
1876 ****************************************************************************/
1878 static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
1879 char *param, int tpscnt,
1880 char *data, int tdscnt,
1881 int mdrcnt,int mprcnt,
1882 char **rdata,char **rparam,
1883 int *rdata_len,int *rparam_len)
1885 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
1886 char *str2 = skip_string(param,tpscnt,str1);
1887 char *p = skip_string(param,tpscnt,str2);
1888 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
1889 fstring sharename;
1890 fstring comment;
1891 char *pathname = NULL;
1892 char *command, *cmdname;
1893 unsigned int offset;
1894 int snum;
1895 int res = ERRunsup;
1896 size_t converted_size;
1898 if (!str1 || !str2 || !p) {
1899 return False;
1902 /* check it's a supported varient */
1903 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1904 return False;
1906 if (!check_share_info(uLevel,str2)) {
1907 return False;
1909 if (uLevel != 2) {
1910 return False;
1913 /* Do we have a string ? */
1914 if (skip_string(data,mdrcnt,data) == NULL) {
1915 return False;
1917 pull_ascii_fstring(sharename,data);
1918 snum = find_service(sharename);
1919 if (snum >= 0) { /* already exists */
1920 res = ERRfilexists;
1921 goto error_exit;
1924 if (mdrcnt < 28) {
1925 return False;
1928 /* only support disk share adds */
1929 if (SVAL(data,14)!=STYPE_DISKTREE) {
1930 return False;
1933 offset = IVAL(data, 16);
1934 if (offset >= mdrcnt) {
1935 res = ERRinvalidparam;
1936 goto error_exit;
1939 /* Do we have a string ? */
1940 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1941 return False;
1943 pull_ascii_fstring(comment, offset? (data+offset) : "");
1945 offset = IVAL(data, 26);
1947 if (offset >= mdrcnt) {
1948 res = ERRinvalidparam;
1949 goto error_exit;
1952 /* Do we have a string ? */
1953 if (skip_string(data,mdrcnt,data+offset) == NULL) {
1954 return False;
1957 if (!pull_ascii_talloc(talloc_tos(), &pathname,
1958 offset ? (data+offset) : "", &converted_size))
1960 DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s",
1961 strerror(errno)));
1964 if (!pathname) {
1965 return false;
1968 string_replace(sharename, '"', ' ');
1969 string_replace(pathname, '"', ' ');
1970 string_replace(comment, '"', ' ');
1972 cmdname = lp_add_share_cmd();
1974 if (!cmdname || *cmdname == '\0') {
1975 return False;
1978 if (asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1979 lp_add_share_cmd(), get_dyn_CONFIGFILE(), sharename,
1980 pathname, comment) == -1) {
1981 return false;
1984 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1986 if ((res = smbrun(command, NULL)) != 0) {
1987 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n",
1988 command, res ));
1989 SAFE_FREE(command);
1990 res = ERRnoaccess;
1991 goto error_exit;
1992 } else {
1993 SAFE_FREE(command);
1994 message_send_all(smbd_messaging_context(),
1995 MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1998 *rparam_len = 6;
1999 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2000 if (!*rparam) {
2001 return False;
2003 SSVAL(*rparam,0,NERR_Success);
2004 SSVAL(*rparam,2,0); /* converter word */
2005 SSVAL(*rparam,4,*rdata_len);
2006 *rdata_len = 0;
2008 return True;
2010 error_exit:
2012 *rparam_len = 4;
2013 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2014 if (!*rparam) {
2015 return False;
2017 *rdata_len = 0;
2018 SSVAL(*rparam,0,res);
2019 SSVAL(*rparam,2,0);
2020 return True;
2023 /****************************************************************************
2024 view list of groups available
2025 ****************************************************************************/
2027 static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
2028 char *param, int tpscnt,
2029 char *data, int tdscnt,
2030 int mdrcnt,int mprcnt,
2031 char **rdata,char **rparam,
2032 int *rdata_len,int *rparam_len)
2034 int i;
2035 int errflags=0;
2036 int resume_context, cli_buf_size;
2037 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2038 char *str2 = skip_string(param,tpscnt,str1);
2039 char *p = skip_string(param,tpscnt,str2);
2041 uint32_t num_groups;
2042 uint32_t resume_handle;
2043 struct rpc_pipe_client *samr_pipe;
2044 struct policy_handle samr_handle, domain_handle;
2045 NTSTATUS status;
2047 if (!str1 || !str2 || !p) {
2048 return False;
2051 if (strcmp(str1,"WrLeh") != 0) {
2052 return False;
2055 /* parameters
2056 * W-> resume context (number of users to skip)
2057 * r -> return parameter pointer to receive buffer
2058 * L -> length of receive buffer
2059 * e -> return parameter number of entries
2060 * h -> return parameter total number of users
2063 if (strcmp("B21",str2) != 0) {
2064 return False;
2067 status = rpc_pipe_open_internal(
2068 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2069 conn->server_info, &samr_pipe);
2070 if (!NT_STATUS_IS_OK(status)) {
2071 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2072 nt_errstr(status)));
2073 return false;
2076 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2077 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2078 if (!NT_STATUS_IS_OK(status)) {
2079 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2080 nt_errstr(status)));
2081 return false;
2084 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2085 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2086 get_global_sam_sid(), &domain_handle);
2087 if (!NT_STATUS_IS_OK(status)) {
2088 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2089 nt_errstr(status)));
2090 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2091 return false;
2094 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2095 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2096 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
2097 "%d\n", resume_context, cli_buf_size));
2099 *rdata_len = cli_buf_size;
2100 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2101 if (!*rdata) {
2102 return False;
2105 p = *rdata;
2107 errflags = NERR_Success;
2108 num_groups = 0;
2109 resume_handle = 0;
2111 while (true) {
2112 struct samr_SamArray *sam_entries;
2113 uint32_t num_entries;
2115 status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
2116 &domain_handle,
2117 &resume_handle,
2118 &sam_entries, 1,
2119 &num_entries);
2120 if (!NT_STATUS_IS_OK(status)) {
2121 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2122 "%s\n", nt_errstr(status)));
2123 break;
2126 if (num_entries == 0) {
2127 DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
2128 "no entries -- done\n"));
2129 break;
2132 for(i=0; i<num_entries; i++) {
2133 const char *name;
2135 name = sam_entries->entries[i].name.string;
2137 if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
2138 /* set overflow error */
2139 DEBUG(3,("overflow on entry %d group %s\n", i,
2140 name));
2141 errflags=234;
2142 break;
2145 /* truncate the name at 21 chars. */
2146 memset(p, 0, 21);
2147 strlcpy(p, name, 21);
2148 DEBUG(10,("adding entry %d group %s\n", i, p));
2149 p += 21;
2150 p += 5; /* Both NT4 and W2k3SP1 do padding here. No
2151 * idea why... */
2152 num_groups += 1;
2155 if (errflags != NERR_Success) {
2156 break;
2159 TALLOC_FREE(sam_entries);
2162 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2163 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2165 *rdata_len = PTR_DIFF(p,*rdata);
2167 *rparam_len = 8;
2168 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2169 if (!*rparam) {
2170 return False;
2172 SSVAL(*rparam, 0, errflags);
2173 SSVAL(*rparam, 2, 0); /* converter word */
2174 SSVAL(*rparam, 4, num_groups); /* is this right?? */
2175 SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */
2177 return(True);
2180 /*******************************************************************
2181 Get groups that a user is a member of.
2182 ******************************************************************/
2184 static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
2185 char *param, int tpscnt,
2186 char *data, int tdscnt,
2187 int mdrcnt,int mprcnt,
2188 char **rdata,char **rparam,
2189 int *rdata_len,int *rparam_len)
2191 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2192 char *str2 = skip_string(param,tpscnt,str1);
2193 char *UserName = skip_string(param,tpscnt,str2);
2194 char *p = skip_string(param,tpscnt,UserName);
2195 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
2196 const char *level_string;
2197 int count=0;
2198 bool ret = False;
2199 uint32_t i;
2200 char *endp = NULL;
2202 struct rpc_pipe_client *samr_pipe;
2203 struct policy_handle samr_handle, domain_handle, user_handle;
2204 struct lsa_String name;
2205 struct lsa_Strings names;
2206 struct samr_Ids type, rid;
2207 struct samr_RidWithAttributeArray *rids;
2208 NTSTATUS status;
2210 if (!str1 || !str2 || !UserName || !p) {
2211 return False;
2214 *rparam_len = 8;
2215 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2216 if (!*rparam) {
2217 return False;
2220 /* check it's a supported varient */
2222 if ( strcmp(str1,"zWrLeh") != 0 )
2223 return False;
2225 switch( uLevel ) {
2226 case 0:
2227 level_string = "B21";
2228 break;
2229 default:
2230 return False;
2233 if (strcmp(level_string,str2) != 0)
2234 return False;
2236 *rdata_len = mdrcnt + 1024;
2237 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2238 if (!*rdata) {
2239 return False;
2242 SSVAL(*rparam,0,NERR_Success);
2243 SSVAL(*rparam,2,0); /* converter word */
2245 p = *rdata;
2246 endp = *rdata + *rdata_len;
2248 status = rpc_pipe_open_internal(
2249 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2250 conn->server_info, &samr_pipe);
2251 if (!NT_STATUS_IS_OK(status)) {
2252 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2253 nt_errstr(status)));
2254 return false;
2257 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2258 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2259 if (!NT_STATUS_IS_OK(status)) {
2260 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2261 nt_errstr(status)));
2262 return false;
2265 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2266 SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
2267 get_global_sam_sid(), &domain_handle);
2268 if (!NT_STATUS_IS_OK(status)) {
2269 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2270 nt_errstr(status)));
2271 goto close_sam;
2274 name.string = UserName;
2276 status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
2277 &domain_handle, 1, &name,
2278 &rid, &type);
2279 if (!NT_STATUS_IS_OK(status)) {
2280 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2281 nt_errstr(status)));
2282 goto close_domain;
2285 if (type.ids[0] != SID_NAME_USER) {
2286 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2287 sid_type_lookup(type.ids[0])));
2288 goto close_domain;
2291 status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
2292 &domain_handle,
2293 SAMR_USER_ACCESS_GET_GROUPS,
2294 rid.ids[0], &user_handle);
2295 if (!NT_STATUS_IS_OK(status)) {
2296 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2297 nt_errstr(status)));
2298 goto close_domain;
2301 status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
2302 &user_handle, &rids);
2303 if (!NT_STATUS_IS_OK(status)) {
2304 DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
2305 nt_errstr(status)));
2306 goto close_user;
2309 for (i=0; i<rids->count; i++) {
2311 status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
2312 &domain_handle,
2313 1, &rids->rids[i].rid,
2314 &names, &type);
2315 if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
2316 strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
2317 p += 21;
2318 count++;
2322 *rdata_len = PTR_DIFF(p,*rdata);
2324 SSVAL(*rparam,4,count); /* is this right?? */
2325 SSVAL(*rparam,6,count); /* is this right?? */
2327 ret = True;
2329 close_user:
2330 rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
2331 close_domain:
2332 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2333 close_sam:
2334 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2336 return ret;
2339 /*******************************************************************
2340 Get all users.
2341 ******************************************************************/
2343 static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
2344 char *param, int tpscnt,
2345 char *data, int tdscnt,
2346 int mdrcnt,int mprcnt,
2347 char **rdata,char **rparam,
2348 int *rdata_len,int *rparam_len)
2350 int count_sent=0;
2351 int num_users=0;
2352 int errflags=0;
2353 int i, resume_context, cli_buf_size;
2354 uint32_t resume_handle;
2356 struct rpc_pipe_client *samr_pipe;
2357 struct policy_handle samr_handle, domain_handle;
2358 NTSTATUS status;
2360 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2361 char *str2 = skip_string(param,tpscnt,str1);
2362 char *p = skip_string(param,tpscnt,str2);
2363 char *endp = NULL;
2365 if (!str1 || !str2 || !p) {
2366 return False;
2369 if (strcmp(str1,"WrLeh") != 0)
2370 return False;
2371 /* parameters
2372 * W-> resume context (number of users to skip)
2373 * r -> return parameter pointer to receive buffer
2374 * L -> length of receive buffer
2375 * e -> return parameter number of entries
2376 * h -> return parameter total number of users
2379 resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
2380 cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0);
2381 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2382 resume_context, cli_buf_size));
2384 *rparam_len = 8;
2385 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2386 if (!*rparam) {
2387 return False;
2390 /* check it's a supported varient */
2391 if (strcmp("B21",str2) != 0)
2392 return False;
2394 *rdata_len = cli_buf_size;
2395 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2396 if (!*rdata) {
2397 return False;
2400 p = *rdata;
2401 endp = *rdata + *rdata_len;
2403 status = rpc_pipe_open_internal(
2404 talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
2405 conn->server_info, &samr_pipe);
2406 if (!NT_STATUS_IS_OK(status)) {
2407 DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
2408 nt_errstr(status)));
2409 return false;
2412 status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
2413 SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
2414 if (!NT_STATUS_IS_OK(status)) {
2415 DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
2416 nt_errstr(status)));
2417 return false;
2420 status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
2421 SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
2422 get_global_sam_sid(), &domain_handle);
2423 if (!NT_STATUS_IS_OK(status)) {
2424 DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
2425 nt_errstr(status)));
2426 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2427 return false;
2430 errflags=NERR_Success;
2432 resume_handle = 0;
2434 while (true) {
2435 struct samr_SamArray *sam_entries;
2436 uint32_t num_entries;
2438 status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
2439 &domain_handle,
2440 &resume_handle,
2441 0, &sam_entries, 1,
2442 &num_entries);
2444 if (!NT_STATUS_IS_OK(status)) {
2445 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2446 "%s\n", nt_errstr(status)));
2447 break;
2450 if (num_entries == 0) {
2451 DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
2452 "no entries -- done\n"));
2453 break;
2456 for (i=0; i<num_entries; i++) {
2457 const char *name;
2459 name = sam_entries->entries[i].name.string;
2461 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
2462 &&(strlen(name)<=21)) {
2463 strlcpy(p,name,PTR_DIFF(endp,p));
2464 DEBUG(10,("api_RNetUserEnum:adding entry %d "
2465 "username %s\n",count_sent,p));
2466 p += 21;
2467 count_sent++;
2468 } else {
2469 /* set overflow error */
2470 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2471 "username %s\n",count_sent,name));
2472 errflags=234;
2473 break;
2477 if (errflags != NERR_Success) {
2478 break;
2481 TALLOC_FREE(sam_entries);
2484 rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
2485 rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
2487 *rdata_len = PTR_DIFF(p,*rdata);
2489 SSVAL(*rparam,0,errflags);
2490 SSVAL(*rparam,2,0); /* converter word */
2491 SSVAL(*rparam,4,count_sent); /* is this right?? */
2492 SSVAL(*rparam,6,num_users); /* is this right?? */
2494 return True;
2497 /****************************************************************************
2498 Get the time of day info.
2499 ****************************************************************************/
2501 static bool api_NetRemoteTOD(connection_struct *conn,uint16 vuid,
2502 char *param, int tpscnt,
2503 char *data, int tdscnt,
2504 int mdrcnt,int mprcnt,
2505 char **rdata,char **rparam,
2506 int *rdata_len,int *rparam_len)
2508 struct tm *t;
2509 time_t unixdate = time(NULL);
2510 char *p;
2512 *rparam_len = 4;
2513 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2514 if (!*rparam) {
2515 return False;
2518 *rdata_len = 21;
2519 *rdata = smb_realloc_limit(*rdata,*rdata_len);
2520 if (!*rdata) {
2521 return False;
2524 SSVAL(*rparam,0,NERR_Success);
2525 SSVAL(*rparam,2,0); /* converter word */
2527 p = *rdata;
2529 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2530 by NT in a "net time" operation,
2531 it seems to ignore the one below */
2533 /* the client expects to get localtime, not GMT, in this bit
2534 (I think, this needs testing) */
2535 t = localtime(&unixdate);
2536 if (!t) {
2537 return False;
2540 SIVAL(p,4,0); /* msecs ? */
2541 SCVAL(p,8,t->tm_hour);
2542 SCVAL(p,9,t->tm_min);
2543 SCVAL(p,10,t->tm_sec);
2544 SCVAL(p,11,0); /* hundredths of seconds */
2545 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2546 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2547 SCVAL(p,16,t->tm_mday);
2548 SCVAL(p,17,t->tm_mon + 1);
2549 SSVAL(p,18,1900+t->tm_year);
2550 SCVAL(p,20,t->tm_wday);
2552 return True;
2555 /****************************************************************************
2556 Set the user password.
2557 *****************************************************************************/
2559 static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
2560 char *param, int tpscnt,
2561 char *data, int tdscnt,
2562 int mdrcnt,int mprcnt,
2563 char **rdata,char **rparam,
2564 int *rdata_len,int *rparam_len)
2566 char *np = get_safe_str_ptr(param,tpscnt,param,2);
2567 char *p = NULL;
2568 fstring user;
2569 fstring pass1,pass2;
2571 /* Skip 2 strings. */
2572 p = skip_string(param,tpscnt,np);
2573 p = skip_string(param,tpscnt,p);
2575 if (!np || !p) {
2576 return False;
2579 /* Do we have a string ? */
2580 if (skip_string(param,tpscnt,p) == NULL) {
2581 return False;
2583 pull_ascii_fstring(user,p);
2585 p = skip_string(param,tpscnt,p);
2586 if (!p) {
2587 return False;
2590 memset(pass1,'\0',sizeof(pass1));
2591 memset(pass2,'\0',sizeof(pass2));
2593 * We use 31 here not 32 as we're checking
2594 * the last byte we want to access is safe.
2596 if (!is_offset_safe(param,tpscnt,p,31)) {
2597 return False;
2599 memcpy(pass1,p,16);
2600 memcpy(pass2,p+16,16);
2602 *rparam_len = 4;
2603 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2604 if (!*rparam) {
2605 return False;
2608 *rdata_len = 0;
2610 SSVAL(*rparam,0,NERR_badpass);
2611 SSVAL(*rparam,2,0); /* converter word */
2613 DEBUG(3,("Set password for <%s>\n",user));
2616 * Attempt to verify the old password against smbpasswd entries
2617 * Win98 clients send old and new password in plaintext for this call.
2621 struct auth_serversupplied_info *server_info = NULL;
2622 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2624 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2626 become_root();
2627 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2628 SSVAL(*rparam,0,NERR_Success);
2630 unbecome_root();
2632 TALLOC_FREE(server_info);
2634 data_blob_clear_free(&password);
2638 * If the plaintext change failed, attempt
2639 * the old encrypted method. NT will generate this
2640 * after trying the samr method. Note that this
2641 * method is done as a last resort as this
2642 * password change method loses the NT password hash
2643 * and cannot change the UNIX password as no plaintext
2644 * is received.
2647 if(SVAL(*rparam,0) != NERR_Success) {
2648 struct samu *hnd = NULL;
2650 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2651 become_root();
2652 if (change_lanman_password(hnd,(uchar *)pass2)) {
2653 SSVAL(*rparam,0,NERR_Success);
2655 unbecome_root();
2656 TALLOC_FREE(hnd);
2660 memset((char *)pass1,'\0',sizeof(fstring));
2661 memset((char *)pass2,'\0',sizeof(fstring));
2663 return(True);
2666 /****************************************************************************
2667 Set the user password (SamOEM version - gets plaintext).
2668 ****************************************************************************/
2670 static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
2671 char *param, int tpscnt,
2672 char *data, int tdscnt,
2673 int mdrcnt,int mprcnt,
2674 char **rdata,char **rparam,
2675 int *rdata_len,int *rparam_len)
2677 struct smbd_server_connection *sconn = smbd_server_conn;
2678 fstring user;
2679 char *p = get_safe_str_ptr(param,tpscnt,param,2);
2680 *rparam_len = 2;
2681 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2682 if (!*rparam) {
2683 return False;
2686 if (!p) {
2687 return False;
2689 *rdata_len = 0;
2691 SSVAL(*rparam,0,NERR_badpass);
2694 * Check the parameter definition is correct.
2697 /* Do we have a string ? */
2698 if (skip_string(param,tpscnt,p) == 0) {
2699 return False;
2701 if(!strequal(p, "zsT")) {
2702 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p));
2703 return False;
2705 p = skip_string(param, tpscnt, p);
2706 if (!p) {
2707 return False;
2710 /* Do we have a string ? */
2711 if (skip_string(param,tpscnt,p) == 0) {
2712 return False;
2714 if(!strequal(p, "B516B16")) {
2715 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2716 return False;
2718 p = skip_string(param,tpscnt,p);
2719 if (!p) {
2720 return False;
2722 /* Do we have a string ? */
2723 if (skip_string(param,tpscnt,p) == 0) {
2724 return False;
2726 p += pull_ascii_fstring(user,p);
2728 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2731 * Pass the user through the NT -> unix user mapping
2732 * function.
2735 (void)map_username(sconn, user);
2737 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2738 SSVAL(*rparam,0,NERR_Success);
2741 return(True);
2744 /****************************************************************************
2745 delete a print job
2746 Form: <W> <>
2747 ****************************************************************************/
2749 static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
2750 char *param, int tpscnt,
2751 char *data, int tdscnt,
2752 int mdrcnt,int mprcnt,
2753 char **rdata,char **rparam,
2754 int *rdata_len,int *rparam_len)
2756 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2757 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2758 char *str2 = skip_string(param,tpscnt,str1);
2759 char *p = skip_string(param,tpscnt,str2);
2760 uint32 jobid;
2761 int snum;
2762 fstring sharename;
2763 int errcode;
2764 WERROR werr = WERR_OK;
2766 if (!str1 || !str2 || !p) {
2767 return False;
2770 * We use 1 here not 2 as we're checking
2771 * the last byte we want to access is safe.
2773 if (!is_offset_safe(param,tpscnt,p,1)) {
2774 return False;
2776 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2777 return False;
2779 /* check it's a supported varient */
2780 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2781 return(False);
2783 *rparam_len = 4;
2784 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2785 if (!*rparam) {
2786 return False;
2788 *rdata_len = 0;
2790 if (!print_job_exists(sharename, jobid)) {
2791 errcode = NERR_JobNotFound;
2792 goto out;
2795 snum = lp_servicenumber( sharename);
2796 if (snum == -1) {
2797 errcode = NERR_DestNotFound;
2798 goto out;
2801 errcode = NERR_notsupported;
2803 switch (function) {
2804 case 81: /* delete */
2805 if (print_job_delete(conn->server_info, snum, jobid, &werr))
2806 errcode = NERR_Success;
2807 break;
2808 case 82: /* pause */
2809 if (print_job_pause(conn->server_info, snum, jobid, &werr))
2810 errcode = NERR_Success;
2811 break;
2812 case 83: /* resume */
2813 if (print_job_resume(conn->server_info, snum, jobid, &werr))
2814 errcode = NERR_Success;
2815 break;
2818 if (!W_ERROR_IS_OK(werr))
2819 errcode = W_ERROR_V(werr);
2821 out:
2822 SSVAL(*rparam,0,errcode);
2823 SSVAL(*rparam,2,0); /* converter word */
2825 return(True);
2828 /****************************************************************************
2829 Purge a print queue - or pause or resume it.
2830 ****************************************************************************/
2832 static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
2833 char *param, int tpscnt,
2834 char *data, int tdscnt,
2835 int mdrcnt,int mprcnt,
2836 char **rdata,char **rparam,
2837 int *rdata_len,int *rparam_len)
2839 int function = get_safe_SVAL(param,tpscnt,param,0,0);
2840 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2841 char *str2 = skip_string(param,tpscnt,str1);
2842 char *QueueName = skip_string(param,tpscnt,str2);
2843 int errcode = NERR_notsupported;
2844 int snum;
2845 WERROR werr = WERR_OK;
2847 if (!str1 || !str2 || !QueueName) {
2848 return False;
2851 /* check it's a supported varient */
2852 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2853 return(False);
2855 *rparam_len = 4;
2856 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2857 if (!*rparam) {
2858 return False;
2860 *rdata_len = 0;
2862 if (skip_string(param,tpscnt,QueueName) == NULL) {
2863 return False;
2865 snum = print_queue_snum(QueueName);
2867 if (snum == -1) {
2868 errcode = NERR_JobNotFound;
2869 goto out;
2872 switch (function) {
2873 case 74: /* Pause queue */
2874 werr = print_queue_pause(conn->server_info, snum);
2875 break;
2876 case 75: /* Resume queue */
2877 werr = print_queue_resume(conn->server_info, snum);
2878 break;
2879 case 103: /* Purge */
2880 werr = print_queue_purge(conn->server_info, snum);
2881 break;
2882 default:
2883 werr = WERR_NOT_SUPPORTED;
2884 break;
2887 errcode = W_ERROR_V(werr);
2889 out:
2890 SSVAL(*rparam,0,errcode);
2891 SSVAL(*rparam,2,0); /* converter word */
2893 return(True);
2896 /****************************************************************************
2897 set the property of a print job (undocumented?)
2898 ? function = 0xb -> set name of print job
2899 ? function = 0x6 -> move print job up/down
2900 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2901 or <WWsTP> <WB21BB16B10zWWzDDz>
2902 ****************************************************************************/
2904 static int check_printjob_info(struct pack_desc* desc,
2905 int uLevel, char* id)
2907 desc->subformat = NULL;
2908 switch( uLevel ) {
2909 case 0: desc->format = "W"; break;
2910 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2911 case 2: desc->format = "WWzWWDDzz"; break;
2912 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2913 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2914 default:
2915 DEBUG(0,("check_printjob_info: invalid level %d\n",
2916 uLevel ));
2917 return False;
2919 if (id == NULL || strcmp(desc->format,id) != 0) {
2920 DEBUG(0,("check_printjob_info: invalid format %s\n",
2921 id ? id : "<NULL>" ));
2922 return False;
2924 return True;
2927 static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
2928 char *param, int tpscnt,
2929 char *data, int tdscnt,
2930 int mdrcnt,int mprcnt,
2931 char **rdata,char **rparam,
2932 int *rdata_len,int *rparam_len)
2934 struct pack_desc desc;
2935 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
2936 char *str2 = skip_string(param,tpscnt,str1);
2937 char *p = skip_string(param,tpscnt,str2);
2938 uint32 jobid;
2939 fstring sharename;
2940 int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
2941 int function = get_safe_SVAL(param,tpscnt,p,4,-1);
2942 int place, errcode;
2944 if (!str1 || !str2 || !p) {
2945 return False;
2948 * We use 1 here not 2 as we're checking
2949 * the last byte we want to access is safe.
2951 if (!is_offset_safe(param,tpscnt,p,1)) {
2952 return False;
2954 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2955 return False;
2956 *rparam_len = 4;
2957 *rparam = smb_realloc_limit(*rparam,*rparam_len);
2958 if (!*rparam) {
2959 return False;
2962 if (!share_defined(sharename)) {
2963 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2964 sharename));
2965 return False;
2968 *rdata_len = 0;
2970 /* check it's a supported varient */
2971 if ((strcmp(str1,"WWsTP")) ||
2972 (!check_printjob_info(&desc,uLevel,str2)))
2973 return(False);
2975 if (!print_job_exists(sharename, jobid)) {
2976 errcode=NERR_JobNotFound;
2977 goto out;
2980 errcode = NERR_notsupported;
2982 switch (function) {
2983 case 0x6:
2984 /* change job place in the queue,
2985 data gives the new place */
2986 place = SVAL(data,0);
2987 if (print_job_set_place(sharename, jobid, place)) {
2988 errcode=NERR_Success;
2990 break;
2992 case 0xb:
2993 /* change print job name, data gives the name */
2994 if (print_job_set_name(sharename, jobid, data)) {
2995 errcode=NERR_Success;
2997 break;
2999 default:
3000 return False;
3003 out:
3004 SSVALS(*rparam,0,errcode);
3005 SSVAL(*rparam,2,0); /* converter word */
3007 return(True);
3011 /****************************************************************************
3012 Get info about the server.
3013 ****************************************************************************/
3015 static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
3016 char *param, int tpscnt,
3017 char *data, int tdscnt,
3018 int mdrcnt,int mprcnt,
3019 char **rdata,char **rparam,
3020 int *rdata_len,int *rparam_len)
3022 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3023 char *str2 = skip_string(param,tpscnt,str1);
3024 char *p = skip_string(param,tpscnt,str2);
3025 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3026 char *p2;
3027 int struct_len;
3029 if (!str1 || !str2 || !p) {
3030 return False;
3033 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
3035 /* check it's a supported varient */
3036 if (!prefix_ok(str1,"WrLh")) {
3037 return False;
3040 switch( uLevel ) {
3041 case 0:
3042 if (strcmp(str2,"B16") != 0) {
3043 return False;
3045 struct_len = 16;
3046 break;
3047 case 1:
3048 if (strcmp(str2,"B16BBDz") != 0) {
3049 return False;
3051 struct_len = 26;
3052 break;
3053 case 2:
3054 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
3055 return False;
3057 struct_len = 134;
3058 break;
3059 case 3:
3060 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
3061 return False;
3063 struct_len = 144;
3064 break;
3065 case 20:
3066 if (strcmp(str2,"DN") != 0) {
3067 return False;
3069 struct_len = 6;
3070 break;
3071 case 50:
3072 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
3073 return False;
3075 struct_len = 42;
3076 break;
3077 default:
3078 return False;
3081 *rdata_len = mdrcnt;
3082 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3083 if (!*rdata) {
3084 return False;
3087 p = *rdata;
3088 p2 = p + struct_len;
3089 if (uLevel != 20) {
3090 srvstr_push(NULL, 0, p,global_myname(),16,
3091 STR_ASCII|STR_UPPER|STR_TERMINATE);
3093 p += 16;
3094 if (uLevel > 0) {
3095 struct srv_info_struct *servers=NULL;
3096 int i,count;
3097 char *comment = NULL;
3098 TALLOC_CTX *ctx = talloc_tos();
3099 uint32 servertype= lp_default_server_announce();
3101 comment = talloc_strdup(ctx,lp_serverstring());
3102 if (!comment) {
3103 return false;
3106 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
3107 for (i=0;i<count;i++) {
3108 if (strequal(servers[i].name,global_myname())) {
3109 servertype = servers[i].type;
3110 TALLOC_FREE(comment);
3111 comment = talloc_strdup(ctx,
3112 servers[i].comment);
3113 if (comment) {
3114 return false;
3120 SAFE_FREE(servers);
3122 SCVAL(p,0,lp_major_announce_version());
3123 SCVAL(p,1,lp_minor_announce_version());
3124 SIVAL(p,2,servertype);
3126 if (mdrcnt == struct_len) {
3127 SIVAL(p,6,0);
3128 } else {
3129 SIVAL(p,6,PTR_DIFF(p2,*rdata));
3130 comment = talloc_sub_advanced(
3131 ctx,
3132 lp_servicename(SNUM(conn)),
3133 conn->server_info->unix_name,
3134 conn->connectpath,
3135 conn->server_info->utok.gid,
3136 conn->server_info->sanitized_username,
3137 pdb_get_domain(conn->server_info->sam_account),
3138 comment);
3139 if (comment) {
3140 return false;
3142 if (mdrcnt - struct_len <= 0) {
3143 return false;
3145 push_ascii(p2,
3146 comment,
3147 MIN(mdrcnt - struct_len,
3148 MAX_SERVER_STRING_LENGTH),
3149 STR_TERMINATE);
3150 p2 = skip_string(*rdata,*rdata_len,p2);
3151 if (!p2) {
3152 return False;
3157 if (uLevel > 1) {
3158 return False; /* not yet implemented */
3161 *rdata_len = PTR_DIFF(p2,*rdata);
3163 *rparam_len = 6;
3164 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3165 if (!*rparam) {
3166 return False;
3168 SSVAL(*rparam,0,NERR_Success);
3169 SSVAL(*rparam,2,0); /* converter word */
3170 SSVAL(*rparam,4,*rdata_len);
3172 return True;
3175 /****************************************************************************
3176 Get info about the server.
3177 ****************************************************************************/
3179 static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
3180 char *param, int tpscnt,
3181 char *data, int tdscnt,
3182 int mdrcnt,int mprcnt,
3183 char **rdata,char **rparam,
3184 int *rdata_len,int *rparam_len)
3186 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3187 char *str2 = skip_string(param,tpscnt,str1);
3188 char *p = skip_string(param,tpscnt,str2);
3189 char *p2;
3190 char *endp;
3191 int level = get_safe_SVAL(param,tpscnt,p,0,-1);
3193 if (!str1 || !str2 || !p) {
3194 return False;
3197 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
3199 *rparam_len = 6;
3200 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3201 if (!*rparam) {
3202 return False;
3205 /* check it's a supported varient */
3206 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
3207 return False;
3210 *rdata_len = mdrcnt + 1024;
3211 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3212 if (!*rdata) {
3213 return False;
3216 SSVAL(*rparam,0,NERR_Success);
3217 SSVAL(*rparam,2,0); /* converter word */
3219 p = *rdata;
3220 endp = *rdata + *rdata_len;
3222 p2 = get_safe_ptr(*rdata,*rdata_len,p,22);
3223 if (!p2) {
3224 return False;
3227 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
3228 strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2));
3229 strupper_m(p2);
3230 p2 = skip_string(*rdata,*rdata_len,p2);
3231 if (!p2) {
3232 return False;
3234 p += 4;
3236 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3237 strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
3238 p2 = skip_string(*rdata,*rdata_len,p2);
3239 if (!p2) {
3240 return False;
3242 p += 4;
3244 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
3245 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2));
3246 strupper_m(p2);
3247 p2 = skip_string(*rdata,*rdata_len,p2);
3248 if (!p2) {
3249 return False;
3251 p += 4;
3253 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
3254 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
3255 p += 2;
3257 SIVAL(p,0,PTR_DIFF(p2,*rdata));
3258 strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */
3259 p2 = skip_string(*rdata,*rdata_len,p2);
3260 if (!p2) {
3261 return False;
3263 p += 4;
3265 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
3266 strlcpy(p2,"",PTR_DIFF(endp,p2));
3267 p2 = skip_string(*rdata,*rdata_len,p2);
3268 if (!p2) {
3269 return False;
3271 p += 4;
3273 *rdata_len = PTR_DIFF(p2,*rdata);
3275 SSVAL(*rparam,4,*rdata_len);
3277 return True;
3280 /****************************************************************************
3281 get info about a user
3283 struct user_info_11 {
3284 char usri11_name[21]; 0-20
3285 char usri11_pad; 21
3286 char *usri11_comment; 22-25
3287 char *usri11_usr_comment; 26-29
3288 unsigned short usri11_priv; 30-31
3289 unsigned long usri11_auth_flags; 32-35
3290 long usri11_password_age; 36-39
3291 char *usri11_homedir; 40-43
3292 char *usri11_parms; 44-47
3293 long usri11_last_logon; 48-51
3294 long usri11_last_logoff; 52-55
3295 unsigned short usri11_bad_pw_count; 56-57
3296 unsigned short usri11_num_logons; 58-59
3297 char *usri11_logon_server; 60-63
3298 unsigned short usri11_country_code; 64-65
3299 char *usri11_workstations; 66-69
3300 unsigned long usri11_max_storage; 70-73
3301 unsigned short usri11_units_per_week; 74-75
3302 unsigned char *usri11_logon_hours; 76-79
3303 unsigned short usri11_code_page; 80-81
3306 where:
3308 usri11_name specifies the user name for which information is retrieved
3310 usri11_pad aligns the next data structure element to a word boundary
3312 usri11_comment is a null terminated ASCII comment
3314 usri11_user_comment is a null terminated ASCII comment about the user
3316 usri11_priv specifies the level of the privilege assigned to the user.
3317 The possible values are:
3319 Name Value Description
3320 USER_PRIV_GUEST 0 Guest privilege
3321 USER_PRIV_USER 1 User privilege
3322 USER_PRV_ADMIN 2 Administrator privilege
3324 usri11_auth_flags specifies the account operator privileges. The
3325 possible values are:
3327 Name Value Description
3328 AF_OP_PRINT 0 Print operator
3331 Leach, Naik [Page 28]
3335 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3338 AF_OP_COMM 1 Communications operator
3339 AF_OP_SERVER 2 Server operator
3340 AF_OP_ACCOUNTS 3 Accounts operator
3343 usri11_password_age specifies how many seconds have elapsed since the
3344 password was last changed.
3346 usri11_home_dir points to a null terminated ASCII string that contains
3347 the path name of the user's home directory.
3349 usri11_parms points to a null terminated ASCII string that is set
3350 aside for use by applications.
3352 usri11_last_logon specifies the time when the user last logged on.
3353 This value is stored as the number of seconds elapsed since
3354 00:00:00, January 1, 1970.
3356 usri11_last_logoff specifies the time when the user last logged off.
3357 This value is stored as the number of seconds elapsed since
3358 00:00:00, January 1, 1970. A value of 0 means the last logoff
3359 time is unknown.
3361 usri11_bad_pw_count specifies the number of incorrect passwords
3362 entered since the last successful logon.
3364 usri11_log1_num_logons specifies the number of times this user has
3365 logged on. A value of -1 means the number of logons is unknown.
3367 usri11_logon_server points to a null terminated ASCII string that
3368 contains the name of the server to which logon requests are sent.
3369 A null string indicates logon requests should be sent to the
3370 domain controller.
3372 usri11_country_code specifies the country code for the user's language
3373 of choice.
3375 usri11_workstations points to a null terminated ASCII string that
3376 contains the names of workstations the user may log on from.
3377 There may be up to 8 workstations, with the names separated by
3378 commas. A null strings indicates there are no restrictions.
3380 usri11_max_storage specifies the maximum amount of disk space the user
3381 can occupy. A value of 0xffffffff indicates there are no
3382 restrictions.
3384 usri11_units_per_week specifies the equal number of time units into
3385 which a week is divided. This value must be equal to 168.
3387 usri11_logon_hours points to a 21 byte (168 bits) string that
3388 specifies the time during which the user can log on. Each bit
3389 represents one unique hour in a week. The first bit (bit 0, word
3390 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
3394 Leach, Naik [Page 29]
3398 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
3401 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
3402 are no restrictions.
3404 usri11_code_page specifies the code page for the user's language of
3405 choice
3407 All of the pointers in this data structure need to be treated
3408 specially. The pointer is a 32 bit pointer. The higher 16 bits need
3409 to be ignored. The converter word returned in the parameters section
3410 needs to be subtracted from the lower 16 bits to calculate an offset
3411 into the return buffer where this ASCII string resides.
3413 There is no auxiliary data in the response.
3415 ****************************************************************************/
3417 #define usri11_name 0
3418 #define usri11_pad 21
3419 #define usri11_comment 22
3420 #define usri11_usr_comment 26
3421 #define usri11_full_name 30
3422 #define usri11_priv 34
3423 #define usri11_auth_flags 36
3424 #define usri11_password_age 40
3425 #define usri11_homedir 44
3426 #define usri11_parms 48
3427 #define usri11_last_logon 52
3428 #define usri11_last_logoff 56
3429 #define usri11_bad_pw_count 60
3430 #define usri11_num_logons 62
3431 #define usri11_logon_server 64
3432 #define usri11_country_code 68
3433 #define usri11_workstations 70
3434 #define usri11_max_storage 74
3435 #define usri11_units_per_week 78
3436 #define usri11_logon_hours 80
3437 #define usri11_code_page 84
3438 #define usri11_end 86
3440 #define USER_PRIV_GUEST 0
3441 #define USER_PRIV_USER 1
3442 #define USER_PRIV_ADMIN 2
3444 #define AF_OP_PRINT 0
3445 #define AF_OP_COMM 1
3446 #define AF_OP_SERVER 2
3447 #define AF_OP_ACCOUNTS 3
3450 static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
3451 char *param, int tpscnt,
3452 char *data, int tdscnt,
3453 int mdrcnt,int mprcnt,
3454 char **rdata,char **rparam,
3455 int *rdata_len,int *rparam_len)
3457 struct smbd_server_connection *sconn = smbd_server_conn;
3458 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3459 char *str2 = skip_string(param,tpscnt,str1);
3460 char *UserName = skip_string(param,tpscnt,str2);
3461 char *p = skip_string(param,tpscnt,UserName);
3462 int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3463 char *p2;
3464 char *endp;
3465 const char *level_string;
3467 /* get NIS home of a previously validated user - simeon */
3468 /* With share level security vuid will always be zero.
3469 Don't depend on vuser being non-null !!. JRA */
3470 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3471 if(vuser != NULL) {
3472 DEBUG(3,(" Username of UID %d is %s\n",
3473 (int)vuser->server_info->utok.uid,
3474 vuser->server_info->unix_name));
3477 if (!str1 || !str2 || !UserName || !p) {
3478 return False;
3481 *rparam_len = 6;
3482 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3483 if (!*rparam) {
3484 return False;
3487 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3489 /* check it's a supported variant */
3490 if (strcmp(str1,"zWrLh") != 0) {
3491 return False;
3493 switch( uLevel ) {
3494 case 0: level_string = "B21"; break;
3495 case 1: level_string = "B21BB16DWzzWz"; break;
3496 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3497 case 10: level_string = "B21Bzzz"; break;
3498 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3499 default: return False;
3502 if (strcmp(level_string,str2) != 0) {
3503 return False;
3506 *rdata_len = mdrcnt + 1024;
3507 *rdata = smb_realloc_limit(*rdata,*rdata_len);
3508 if (!*rdata) {
3509 return False;
3512 SSVAL(*rparam,0,NERR_Success);
3513 SSVAL(*rparam,2,0); /* converter word */
3515 p = *rdata;
3516 endp = *rdata + *rdata_len;
3517 p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end);
3518 if (!p2) {
3519 return False;
3522 memset(p,0,21);
3523 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3525 if (uLevel > 0) {
3526 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3527 *p2 = 0;
3530 if (uLevel >= 10) {
3531 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3532 strlcpy(p2,"Comment",PTR_DIFF(endp,p2));
3533 p2 = skip_string(*rdata,*rdata_len,p2);
3534 if (!p2) {
3535 return False;
3538 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3539 strlcpy(p2,"UserComment",PTR_DIFF(endp,p2));
3540 p2 = skip_string(*rdata,*rdata_len,p2);
3541 if (!p2) {
3542 return False;
3545 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3546 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3547 strlcpy(p2,((vuser != NULL)
3548 ? pdb_get_fullname(vuser->server_info->sam_account)
3549 : UserName),PTR_DIFF(endp,p2));
3550 p2 = skip_string(*rdata,*rdata_len,p2);
3551 if (!p2) {
3552 return False;
3556 if (uLevel == 11) {
3557 const char *homedir = "";
3558 if (vuser != NULL) {
3559 homedir = pdb_get_homedir(
3560 vuser->server_info->sam_account);
3562 /* modelled after NTAS 3.51 reply */
3563 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3564 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3565 SIVALS(p,usri11_password_age,-1); /* password age */
3566 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3567 strlcpy(p2, homedir, PTR_DIFF(endp,p2));
3568 p2 = skip_string(*rdata,*rdata_len,p2);
3569 if (!p2) {
3570 return False;
3572 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3573 strlcpy(p2,"",PTR_DIFF(endp,p2));
3574 p2 = skip_string(*rdata,*rdata_len,p2);
3575 if (!p2) {
3576 return False;
3578 SIVAL(p,usri11_last_logon,0); /* last logon */
3579 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3580 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3581 SSVALS(p,usri11_num_logons,-1); /* num logons */
3582 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3583 strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2));
3584 p2 = skip_string(*rdata,*rdata_len,p2);
3585 if (!p2) {
3586 return False;
3588 SSVAL(p,usri11_country_code,0); /* country code */
3590 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3591 strlcpy(p2,"",PTR_DIFF(endp,p2));
3592 p2 = skip_string(*rdata,*rdata_len,p2);
3593 if (!p2) {
3594 return False;
3597 SIVALS(p,usri11_max_storage,-1); /* max storage */
3598 SSVAL(p,usri11_units_per_week,168); /* units per week */
3599 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3601 /* a simple way to get logon hours at all times. */
3602 memset(p2,0xff,21);
3603 SCVAL(p2,21,0); /* fix zero termination */
3604 p2 = skip_string(*rdata,*rdata_len,p2);
3605 if (!p2) {
3606 return False;
3609 SSVAL(p,usri11_code_page,0); /* code page */
3612 if (uLevel == 1 || uLevel == 2) {
3613 memset(p+22,' ',16); /* password */
3614 SIVALS(p,38,-1); /* password age */
3615 SSVAL(p,42,
3616 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3617 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3618 strlcpy(p2, vuser ? pdb_get_homedir(
3619 vuser->server_info->sam_account) : "",
3620 PTR_DIFF(endp,p2));
3621 p2 = skip_string(*rdata,*rdata_len,p2);
3622 if (!p2) {
3623 return False;
3625 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3626 *p2++ = 0;
3627 SSVAL(p,52,0); /* flags */
3628 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3629 strlcpy(p2, vuser ? pdb_get_logon_script(
3630 vuser->server_info->sam_account) : "",
3631 PTR_DIFF(endp,p2));
3632 p2 = skip_string(*rdata,*rdata_len,p2);
3633 if (!p2) {
3634 return False;
3636 if (uLevel == 2) {
3637 SIVAL(p,60,0); /* auth_flags */
3638 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3639 strlcpy(p2,((vuser != NULL)
3640 ? pdb_get_fullname(vuser->server_info->sam_account)
3641 : UserName),PTR_DIFF(endp,p2));
3642 p2 = skip_string(*rdata,*rdata_len,p2);
3643 if (!p2) {
3644 return False;
3646 SIVAL(p,68,0); /* urs_comment */
3647 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3648 strlcpy(p2,"",PTR_DIFF(endp,p2));
3649 p2 = skip_string(*rdata,*rdata_len,p2);
3650 if (!p2) {
3651 return False;
3653 SIVAL(p,76,0); /* workstations */
3654 SIVAL(p,80,0); /* last_logon */
3655 SIVAL(p,84,0); /* last_logoff */
3656 SIVALS(p,88,-1); /* acct_expires */
3657 SIVALS(p,92,-1); /* max_storage */
3658 SSVAL(p,96,168); /* units_per_week */
3659 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3660 memset(p2,-1,21);
3661 p2 += 21;
3662 SSVALS(p,102,-1); /* bad_pw_count */
3663 SSVALS(p,104,-1); /* num_logons */
3664 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3666 TALLOC_CTX *ctx = talloc_tos();
3667 int space_rem = *rdata_len - (p2 - *rdata);
3668 char *tmp;
3670 if (space_rem <= 0) {
3671 return false;
3673 tmp = talloc_strdup(ctx, "\\\\%L");
3674 if (!tmp) {
3675 return false;
3677 tmp = talloc_sub_basic(ctx,
3680 tmp);
3681 if (!tmp) {
3682 return false;
3685 push_ascii(p2,
3686 tmp,
3687 space_rem,
3688 STR_TERMINATE);
3690 p2 = skip_string(*rdata,*rdata_len,p2);
3691 if (!p2) {
3692 return False;
3694 SSVAL(p,110,49); /* country_code */
3695 SSVAL(p,112,860); /* code page */
3699 *rdata_len = PTR_DIFF(p2,*rdata);
3701 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3703 return(True);
3706 static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
3707 char *param, int tpscnt,
3708 char *data, int tdscnt,
3709 int mdrcnt,int mprcnt,
3710 char **rdata,char **rparam,
3711 int *rdata_len,int *rparam_len)
3713 struct smbd_server_connection *sconn = smbd_server_conn;
3714 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3715 char *str2 = skip_string(param,tpscnt,str1);
3716 char *p = skip_string(param,tpscnt,str2);
3717 int uLevel;
3718 struct pack_desc desc;
3719 char* name;
3720 /* With share level security vuid will always be zero.
3721 Don't depend on vuser being non-null !!. JRA */
3722 user_struct *vuser = get_valid_user_struct(sconn, vuid);
3724 if (!str1 || !str2 || !p) {
3725 return False;
3728 if(vuser != NULL) {
3729 DEBUG(3,(" Username of UID %d is %s\n",
3730 (int)vuser->server_info->utok.uid,
3731 vuser->server_info->unix_name));
3734 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3735 name = get_safe_str_ptr(param,tpscnt,p,2);
3736 if (!name) {
3737 return False;
3740 memset((char *)&desc,'\0',sizeof(desc));
3742 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3744 /* check it's a supported varient */
3745 if (strcmp(str1,"OOWb54WrLh") != 0) {
3746 return False;
3748 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3749 return False;
3751 if (mdrcnt > 0) {
3752 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3753 if (!*rdata) {
3754 return False;
3758 desc.base = *rdata;
3759 desc.buflen = mdrcnt;
3760 desc.subformat = NULL;
3761 desc.format = str2;
3763 if (init_package(&desc,1,0)) {
3764 PACKI(&desc,"W",0); /* code */
3765 PACKS(&desc,"B21",name); /* eff. name */
3766 PACKS(&desc,"B",""); /* pad */
3767 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3768 PACKI(&desc,"D",0); /* auth flags XXX */
3769 PACKI(&desc,"W",0); /* num logons */
3770 PACKI(&desc,"W",0); /* bad pw count */
3771 PACKI(&desc,"D",0); /* last logon */
3772 PACKI(&desc,"D",-1); /* last logoff */
3773 PACKI(&desc,"D",-1); /* logoff time */
3774 PACKI(&desc,"D",-1); /* kickoff time */
3775 PACKI(&desc,"D",0); /* password age */
3776 PACKI(&desc,"D",0); /* password can change */
3777 PACKI(&desc,"D",-1); /* password must change */
3780 fstring mypath;
3781 fstrcpy(mypath,"\\\\");
3782 fstrcat(mypath,get_local_machine_name());
3783 strupper_m(mypath);
3784 PACKS(&desc,"z",mypath); /* computer */
3787 PACKS(&desc,"z",lp_workgroup());/* domain */
3788 PACKS(&desc,"z", vuser ? pdb_get_logon_script(
3789 vuser->server_info->sam_account) : ""); /* script path */
3790 PACKI(&desc,"D",0x00000000); /* reserved */
3793 *rdata_len = desc.usedlen;
3794 *rparam_len = 6;
3795 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3796 if (!*rparam) {
3797 return False;
3799 SSVALS(*rparam,0,desc.errcode);
3800 SSVAL(*rparam,2,0);
3801 SSVAL(*rparam,4,desc.neededlen);
3803 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3805 return True;
3808 /****************************************************************************
3809 api_WAccessGetUserPerms
3810 ****************************************************************************/
3812 static bool api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid,
3813 char *param, int tpscnt,
3814 char *data, int tdscnt,
3815 int mdrcnt,int mprcnt,
3816 char **rdata,char **rparam,
3817 int *rdata_len,int *rparam_len)
3819 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3820 char *str2 = skip_string(param,tpscnt,str1);
3821 char *user = skip_string(param,tpscnt,str2);
3822 char *resource = skip_string(param,tpscnt,user);
3824 if (!str1 || !str2 || !user || !resource) {
3825 return False;
3828 if (skip_string(param,tpscnt,resource) == NULL) {
3829 return False;
3831 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3833 /* check it's a supported varient */
3834 if (strcmp(str1,"zzh") != 0) {
3835 return False;
3837 if (strcmp(str2,"") != 0) {
3838 return False;
3841 *rparam_len = 6;
3842 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3843 if (!*rparam) {
3844 return False;
3846 SSVALS(*rparam,0,0); /* errorcode */
3847 SSVAL(*rparam,2,0); /* converter word */
3848 SSVAL(*rparam,4,0x7f); /* permission flags */
3850 return True;
3853 /****************************************************************************
3854 api_WPrintJobEnumerate
3855 ****************************************************************************/
3857 static bool api_WPrintJobGetInfo(connection_struct *conn, uint16 vuid,
3858 char *param, int tpscnt,
3859 char *data, int tdscnt,
3860 int mdrcnt,int mprcnt,
3861 char **rdata,char **rparam,
3862 int *rdata_len,int *rparam_len)
3864 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3865 char *str2 = skip_string(param,tpscnt,str1);
3866 char *p = skip_string(param,tpscnt,str2);
3867 int uLevel;
3868 int count;
3869 int i;
3870 int snum;
3871 fstring sharename;
3872 uint32 jobid;
3873 struct pack_desc desc;
3874 print_queue_struct *queue=NULL;
3875 print_status_struct status;
3876 char *tmpdata=NULL;
3878 if (!str1 || !str2 || !p) {
3879 return False;
3882 uLevel = get_safe_SVAL(param,tpscnt,p,2,-1);
3884 memset((char *)&desc,'\0',sizeof(desc));
3885 memset((char *)&status,'\0',sizeof(status));
3887 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3889 /* check it's a supported varient */
3890 if (strcmp(str1,"WWrLh") != 0) {
3891 return False;
3893 if (!check_printjob_info(&desc,uLevel,str2)) {
3894 return False;
3897 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3898 return False;
3901 snum = lp_servicenumber( sharename);
3902 if (snum < 0 || !VALID_SNUM(snum)) {
3903 return(False);
3906 count = print_queue_status(snum,&queue,&status);
3907 for (i = 0; i < count; i++) {
3908 if (queue[i].job == jobid) {
3909 break;
3913 if (mdrcnt > 0) {
3914 *rdata = smb_realloc_limit(*rdata,mdrcnt);
3915 if (!*rdata) {
3916 return False;
3918 desc.base = *rdata;
3919 desc.buflen = mdrcnt;
3920 } else {
3922 * Don't return data but need to get correct length
3923 * init_package will return wrong size if buflen=0
3925 desc.buflen = getlen(desc.format);
3926 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3929 if (init_package(&desc,1,0)) {
3930 if (i < count) {
3931 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3932 *rdata_len = desc.usedlen;
3933 } else {
3934 desc.errcode = NERR_JobNotFound;
3935 *rdata_len = 0;
3939 *rparam_len = 6;
3940 *rparam = smb_realloc_limit(*rparam,*rparam_len);
3941 if (!*rparam) {
3942 return False;
3944 SSVALS(*rparam,0,desc.errcode);
3945 SSVAL(*rparam,2,0);
3946 SSVAL(*rparam,4,desc.neededlen);
3948 SAFE_FREE(queue);
3949 SAFE_FREE(tmpdata);
3951 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3953 return True;
3956 static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
3957 char *param, int tpscnt,
3958 char *data, int tdscnt,
3959 int mdrcnt,int mprcnt,
3960 char **rdata,char **rparam,
3961 int *rdata_len,int *rparam_len)
3963 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
3964 char *str2 = skip_string(param,tpscnt,str1);
3965 char *p = skip_string(param,tpscnt,str2);
3966 char *name = p;
3967 int uLevel;
3968 int count;
3969 int i, succnt=0;
3970 int snum;
3971 struct pack_desc desc;
3972 print_queue_struct *queue=NULL;
3973 print_status_struct status;
3975 if (!str1 || !str2 || !p) {
3976 return False;
3979 memset((char *)&desc,'\0',sizeof(desc));
3980 memset((char *)&status,'\0',sizeof(status));
3982 p = skip_string(param,tpscnt,p);
3983 if (!p) {
3984 return False;
3986 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
3988 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3990 /* check it's a supported variant */
3991 if (strcmp(str1,"zWrLeh") != 0) {
3992 return False;
3995 if (uLevel > 2) {
3996 return False; /* defined only for uLevel 0,1,2 */
3999 if (!check_printjob_info(&desc,uLevel,str2)) {
4000 return False;
4003 snum = find_service(name);
4004 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4005 return False;
4008 count = print_queue_status(snum,&queue,&status);
4009 if (mdrcnt > 0) {
4010 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4011 if (!*rdata) {
4012 return False;
4015 desc.base = *rdata;
4016 desc.buflen = mdrcnt;
4018 if (init_package(&desc,count,0)) {
4019 succnt = 0;
4020 for (i = 0; i < count; i++) {
4021 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
4022 if (desc.errcode == NERR_Success) {
4023 succnt = i+1;
4028 *rdata_len = desc.usedlen;
4030 *rparam_len = 8;
4031 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4032 if (!*rparam) {
4033 return False;
4035 SSVALS(*rparam,0,desc.errcode);
4036 SSVAL(*rparam,2,0);
4037 SSVAL(*rparam,4,succnt);
4038 SSVAL(*rparam,6,count);
4040 SAFE_FREE(queue);
4042 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
4044 return True;
4047 static int check_printdest_info(struct pack_desc* desc,
4048 int uLevel, char* id)
4050 desc->subformat = NULL;
4051 switch( uLevel ) {
4052 case 0:
4053 desc->format = "B9";
4054 break;
4055 case 1:
4056 desc->format = "B9B21WWzW";
4057 break;
4058 case 2:
4059 desc->format = "z";
4060 break;
4061 case 3:
4062 desc->format = "zzzWWzzzWW";
4063 break;
4064 default:
4065 DEBUG(0,("check_printdest_info: invalid level %d\n",
4066 uLevel));
4067 return False;
4069 if (id == NULL || strcmp(desc->format,id) != 0) {
4070 DEBUG(0,("check_printdest_info: invalid string %s\n",
4071 id ? id : "<NULL>" ));
4072 return False;
4074 return True;
4077 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
4078 struct pack_desc* desc)
4080 char buf[100];
4082 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
4083 buf[sizeof(buf)-1] = 0;
4084 strupper_m(buf);
4086 if (uLevel <= 1) {
4087 PACKS(desc,"B9",buf); /* szName */
4088 if (uLevel == 1) {
4089 PACKS(desc,"B21",""); /* szUserName */
4090 PACKI(desc,"W",0); /* uJobId */
4091 PACKI(desc,"W",0); /* fsStatus */
4092 PACKS(desc,"z",""); /* pszStatus */
4093 PACKI(desc,"W",0); /* time */
4097 if (uLevel == 2 || uLevel == 3) {
4098 PACKS(desc,"z",buf); /* pszPrinterName */
4099 if (uLevel == 3) {
4100 PACKS(desc,"z",""); /* pszUserName */
4101 PACKS(desc,"z",""); /* pszLogAddr */
4102 PACKI(desc,"W",0); /* uJobId */
4103 PACKI(desc,"W",0); /* fsStatus */
4104 PACKS(desc,"z",""); /* pszStatus */
4105 PACKS(desc,"z",""); /* pszComment */
4106 PACKS(desc,"z","NULL"); /* pszDrivers */
4107 PACKI(desc,"W",0); /* time */
4108 PACKI(desc,"W",0); /* pad1 */
4113 static bool api_WPrintDestGetInfo(connection_struct *conn, uint16 vuid,
4114 char *param, int tpscnt,
4115 char *data, int tdscnt,
4116 int mdrcnt,int mprcnt,
4117 char **rdata,char **rparam,
4118 int *rdata_len,int *rparam_len)
4120 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4121 char *str2 = skip_string(param,tpscnt,str1);
4122 char *p = skip_string(param,tpscnt,str2);
4123 char* PrinterName = p;
4124 int uLevel;
4125 struct pack_desc desc;
4126 int snum;
4127 char *tmpdata=NULL;
4129 if (!str1 || !str2 || !p) {
4130 return False;
4133 memset((char *)&desc,'\0',sizeof(desc));
4135 p = skip_string(param,tpscnt,p);
4136 if (!p) {
4137 return False;
4139 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4141 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
4143 /* check it's a supported varient */
4144 if (strcmp(str1,"zWrLh") != 0) {
4145 return False;
4147 if (!check_printdest_info(&desc,uLevel,str2)) {
4148 return False;
4151 snum = find_service(PrinterName);
4152 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
4153 *rdata_len = 0;
4154 desc.errcode = NERR_DestNotFound;
4155 desc.neededlen = 0;
4156 } else {
4157 if (mdrcnt > 0) {
4158 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4159 if (!*rdata) {
4160 return False;
4162 desc.base = *rdata;
4163 desc.buflen = mdrcnt;
4164 } else {
4166 * Don't return data but need to get correct length
4167 * init_package will return wrong size if buflen=0
4169 desc.buflen = getlen(desc.format);
4170 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
4172 if (init_package(&desc,1,0)) {
4173 fill_printdest_info(conn,snum,uLevel,&desc);
4175 *rdata_len = desc.usedlen;
4178 *rparam_len = 6;
4179 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4180 if (!*rparam) {
4181 return False;
4183 SSVALS(*rparam,0,desc.errcode);
4184 SSVAL(*rparam,2,0);
4185 SSVAL(*rparam,4,desc.neededlen);
4187 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
4188 SAFE_FREE(tmpdata);
4190 return True;
4193 static bool api_WPrintDestEnum(connection_struct *conn, uint16 vuid,
4194 char *param, int tpscnt,
4195 char *data, int tdscnt,
4196 int mdrcnt,int mprcnt,
4197 char **rdata,char **rparam,
4198 int *rdata_len,int *rparam_len)
4200 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4201 char *str2 = skip_string(param,tpscnt,str1);
4202 char *p = skip_string(param,tpscnt,str2);
4203 int uLevel;
4204 int queuecnt;
4205 int i, n, succnt=0;
4206 struct pack_desc desc;
4207 int services = lp_numservices();
4209 if (!str1 || !str2 || !p) {
4210 return False;
4213 memset((char *)&desc,'\0',sizeof(desc));
4215 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4217 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
4219 /* check it's a supported varient */
4220 if (strcmp(str1,"WrLeh") != 0) {
4221 return False;
4223 if (!check_printdest_info(&desc,uLevel,str2)) {
4224 return False;
4227 queuecnt = 0;
4228 for (i = 0; i < services; i++) {
4229 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4230 queuecnt++;
4234 if (mdrcnt > 0) {
4235 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4236 if (!*rdata) {
4237 return False;
4241 desc.base = *rdata;
4242 desc.buflen = mdrcnt;
4243 if (init_package(&desc,queuecnt,0)) {
4244 succnt = 0;
4245 n = 0;
4246 for (i = 0; i < services; i++) {
4247 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
4248 fill_printdest_info(conn,i,uLevel,&desc);
4249 n++;
4250 if (desc.errcode == NERR_Success) {
4251 succnt = n;
4257 *rdata_len = desc.usedlen;
4259 *rparam_len = 8;
4260 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4261 if (!*rparam) {
4262 return False;
4264 SSVALS(*rparam,0,desc.errcode);
4265 SSVAL(*rparam,2,0);
4266 SSVAL(*rparam,4,succnt);
4267 SSVAL(*rparam,6,queuecnt);
4269 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
4271 return True;
4274 static bool api_WPrintDriverEnum(connection_struct *conn, uint16 vuid,
4275 char *param, int tpscnt,
4276 char *data, int tdscnt,
4277 int mdrcnt,int mprcnt,
4278 char **rdata,char **rparam,
4279 int *rdata_len,int *rparam_len)
4281 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4282 char *str2 = skip_string(param,tpscnt,str1);
4283 char *p = skip_string(param,tpscnt,str2);
4284 int uLevel;
4285 int succnt;
4286 struct pack_desc desc;
4288 if (!str1 || !str2 || !p) {
4289 return False;
4292 memset((char *)&desc,'\0',sizeof(desc));
4294 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4296 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
4298 /* check it's a supported varient */
4299 if (strcmp(str1,"WrLeh") != 0) {
4300 return False;
4302 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
4303 return False;
4306 if (mdrcnt > 0) {
4307 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4308 if (!*rdata) {
4309 return False;
4312 desc.base = *rdata;
4313 desc.buflen = mdrcnt;
4314 if (init_package(&desc,1,0)) {
4315 PACKS(&desc,"B41","NULL");
4318 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4320 *rdata_len = desc.usedlen;
4322 *rparam_len = 8;
4323 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4324 if (!*rparam) {
4325 return False;
4327 SSVALS(*rparam,0,desc.errcode);
4328 SSVAL(*rparam,2,0);
4329 SSVAL(*rparam,4,succnt);
4330 SSVAL(*rparam,6,1);
4332 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
4334 return True;
4337 static bool api_WPrintQProcEnum(connection_struct *conn, uint16 vuid,
4338 char *param, int tpscnt,
4339 char *data, int tdscnt,
4340 int mdrcnt,int mprcnt,
4341 char **rdata,char **rparam,
4342 int *rdata_len,int *rparam_len)
4344 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4345 char *str2 = skip_string(param,tpscnt,str1);
4346 char *p = skip_string(param,tpscnt,str2);
4347 int uLevel;
4348 int succnt;
4349 struct pack_desc desc;
4351 if (!str1 || !str2 || !p) {
4352 return False;
4354 memset((char *)&desc,'\0',sizeof(desc));
4356 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4358 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
4360 /* check it's a supported varient */
4361 if (strcmp(str1,"WrLeh") != 0) {
4362 return False;
4364 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
4365 return False;
4368 if (mdrcnt > 0) {
4369 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4370 if (!*rdata) {
4371 return False;
4374 desc.base = *rdata;
4375 desc.buflen = mdrcnt;
4376 desc.format = str2;
4377 if (init_package(&desc,1,0)) {
4378 PACKS(&desc,"B13","lpd");
4381 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4383 *rdata_len = desc.usedlen;
4385 *rparam_len = 8;
4386 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4387 if (!*rparam) {
4388 return False;
4390 SSVALS(*rparam,0,desc.errcode);
4391 SSVAL(*rparam,2,0);
4392 SSVAL(*rparam,4,succnt);
4393 SSVAL(*rparam,6,1);
4395 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
4397 return True;
4400 static bool api_WPrintPortEnum(connection_struct *conn, uint16 vuid,
4401 char *param, int tpscnt,
4402 char *data, int tdscnt,
4403 int mdrcnt,int mprcnt,
4404 char **rdata,char **rparam,
4405 int *rdata_len,int *rparam_len)
4407 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4408 char *str2 = skip_string(param,tpscnt,str1);
4409 char *p = skip_string(param,tpscnt,str2);
4410 int uLevel;
4411 int succnt;
4412 struct pack_desc desc;
4414 if (!str1 || !str2 || !p) {
4415 return False;
4418 memset((char *)&desc,'\0',sizeof(desc));
4420 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4422 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
4424 /* check it's a supported varient */
4425 if (strcmp(str1,"WrLeh") != 0) {
4426 return False;
4428 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
4429 return False;
4432 if (mdrcnt > 0) {
4433 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4434 if (!*rdata) {
4435 return False;
4438 memset((char *)&desc,'\0',sizeof(desc));
4439 desc.base = *rdata;
4440 desc.buflen = mdrcnt;
4441 desc.format = str2;
4442 if (init_package(&desc,1,0)) {
4443 PACKS(&desc,"B13","lp0");
4446 succnt = (desc.errcode == NERR_Success ? 1 : 0);
4448 *rdata_len = desc.usedlen;
4450 *rparam_len = 8;
4451 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4452 if (!*rparam) {
4453 return False;
4455 SSVALS(*rparam,0,desc.errcode);
4456 SSVAL(*rparam,2,0);
4457 SSVAL(*rparam,4,succnt);
4458 SSVAL(*rparam,6,1);
4460 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
4462 return True;
4465 /****************************************************************************
4466 List open sessions
4467 ****************************************************************************/
4469 static bool api_RNetSessionEnum(connection_struct *conn, uint16 vuid,
4470 char *param, int tpscnt,
4471 char *data, int tdscnt,
4472 int mdrcnt,int mprcnt,
4473 char **rdata,char **rparam,
4474 int *rdata_len,int *rparam_len)
4477 char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
4478 char *str2 = skip_string(param,tpscnt,str1);
4479 char *p = skip_string(param,tpscnt,str2);
4480 int uLevel;
4481 struct pack_desc desc;
4482 struct sessionid *session_list;
4483 int i, num_sessions;
4485 if (!str1 || !str2 || !p) {
4486 return False;
4489 memset((char *)&desc,'\0',sizeof(desc));
4491 uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
4493 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
4494 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
4495 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
4497 /* check it's a supported varient */
4498 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
4499 return False;
4501 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
4502 return False;
4505 num_sessions = list_sessions(talloc_tos(), &session_list);
4507 if (mdrcnt > 0) {
4508 *rdata = smb_realloc_limit(*rdata,mdrcnt);
4509 if (!*rdata) {
4510 return False;
4513 memset((char *)&desc,'\0',sizeof(desc));
4514 desc.base = *rdata;
4515 desc.buflen = mdrcnt;
4516 desc.format = str2;
4517 if (!init_package(&desc,num_sessions,0)) {
4518 return False;
4521 for(i=0; i<num_sessions; i++) {
4522 PACKS(&desc, "z", session_list[i].remote_machine);
4523 PACKS(&desc, "z", session_list[i].username);
4524 PACKI(&desc, "W", 1); /* num conns */
4525 PACKI(&desc, "W", 0); /* num opens */
4526 PACKI(&desc, "W", 1); /* num users */
4527 PACKI(&desc, "D", 0); /* session time */
4528 PACKI(&desc, "D", 0); /* idle time */
4529 PACKI(&desc, "D", 0); /* flags */
4530 PACKS(&desc, "z", "Unknown Client"); /* client type string */
4533 *rdata_len = desc.usedlen;
4535 *rparam_len = 8;
4536 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4537 if (!*rparam) {
4538 return False;
4540 SSVALS(*rparam,0,desc.errcode);
4541 SSVAL(*rparam,2,0); /* converter */
4542 SSVAL(*rparam,4,num_sessions); /* count */
4544 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
4546 return True;
4550 /****************************************************************************
4551 The buffer was too small.
4552 ****************************************************************************/
4554 static bool api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
4555 int mdrcnt, int mprcnt,
4556 char **rdata, char **rparam,
4557 int *rdata_len, int *rparam_len)
4559 *rparam_len = MIN(*rparam_len,mprcnt);
4560 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4561 if (!*rparam) {
4562 return False;
4565 *rdata_len = 0;
4567 SSVAL(*rparam,0,NERR_BufTooSmall);
4569 DEBUG(3,("Supplied buffer too small in API command\n"));
4571 return True;
4574 /****************************************************************************
4575 The request is not supported.
4576 ****************************************************************************/
4578 static bool api_Unsupported(connection_struct *conn, uint16 vuid,
4579 char *param, int tpscnt,
4580 char *data, int tdscnt,
4581 int mdrcnt, int mprcnt,
4582 char **rdata, char **rparam,
4583 int *rdata_len, int *rparam_len)
4585 *rparam_len = 4;
4586 *rparam = smb_realloc_limit(*rparam,*rparam_len);
4587 if (!*rparam) {
4588 return False;
4591 *rdata_len = 0;
4593 SSVAL(*rparam,0,NERR_notsupported);
4594 SSVAL(*rparam,2,0); /* converter word */
4596 DEBUG(3,("Unsupported API command\n"));
4598 return True;
4601 static const struct {
4602 const char *name;
4603 int id;
4604 bool (*fn)(connection_struct *, uint16,
4605 char *, int,
4606 char *, int,
4607 int,int,char **,char **,int *,int *);
4608 bool auth_user; /* Deny anonymous access? */
4609 } api_commands[] = {
4610 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
4611 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
4612 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
4613 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
4614 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
4615 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
4616 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
4617 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
4618 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
4619 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
4620 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
4621 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
4622 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
4623 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
4624 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
4625 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
4626 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4627 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4628 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4629 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4630 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4631 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4632 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4633 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4634 {"NetServerEnum2", RAP_NetServerEnum2, api_RNetServerEnum2}, /* anon OK */
4635 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4636 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4637 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4638 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4639 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4640 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4641 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4642 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4643 {NULL, -1, api_Unsupported}
4644 /* The following RAP calls are not implemented by Samba:
4646 RAP_WFileEnum2 - anon not OK
4651 /****************************************************************************
4652 Handle remote api calls.
4653 ****************************************************************************/
4655 void api_reply(connection_struct *conn, uint16 vuid,
4656 struct smb_request *req,
4657 char *data, char *params,
4658 int tdscnt, int tpscnt,
4659 int mdrcnt, int mprcnt)
4661 struct smbd_server_connection *sconn = smbd_server_conn;
4662 int api_command;
4663 char *rdata = NULL;
4664 char *rparam = NULL;
4665 const char *name1 = NULL;
4666 const char *name2 = NULL;
4667 int rdata_len = 0;
4668 int rparam_len = 0;
4669 bool reply=False;
4670 int i;
4672 if (!params) {
4673 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4674 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4675 return;
4678 if (tpscnt < 2) {
4679 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4680 return;
4682 api_command = SVAL(params,0);
4683 /* Is there a string at position params+2 ? */
4684 if (skip_string(params,tpscnt,params+2)) {
4685 name1 = params + 2;
4686 } else {
4687 name1 = "";
4689 name2 = skip_string(params,tpscnt,params+2);
4690 if (!name2) {
4691 name2 = "";
4694 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4695 api_command,
4696 name1,
4697 name2,
4698 tdscnt,tpscnt,mdrcnt,mprcnt));
4700 for (i=0;api_commands[i].name;i++) {
4701 if (api_commands[i].id == api_command && api_commands[i].fn) {
4702 DEBUG(3,("Doing %s\n",api_commands[i].name));
4703 break;
4707 /* Check whether this api call can be done anonymously */
4709 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4710 user_struct *user = get_valid_user_struct(sconn, vuid);
4712 if (!user || user->server_info->guest) {
4713 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4714 return;
4718 rdata = (char *)SMB_MALLOC(1024);
4719 if (rdata) {
4720 memset(rdata,'\0',1024);
4723 rparam = (char *)SMB_MALLOC(1024);
4724 if (rparam) {
4725 memset(rparam,'\0',1024);
4728 if(!rdata || !rparam) {
4729 DEBUG(0,("api_reply: malloc fail !\n"));
4730 SAFE_FREE(rdata);
4731 SAFE_FREE(rparam);
4732 reply_nterror(req, NT_STATUS_NO_MEMORY);
4733 return;
4736 reply = api_commands[i].fn(conn,
4737 vuid,
4738 params,tpscnt, /* params + length */
4739 data,tdscnt, /* data + length */
4740 mdrcnt,mprcnt,
4741 &rdata,&rparam,&rdata_len,&rparam_len);
4744 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4745 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4746 &rdata,&rparam,&rdata_len,&rparam_len);
4749 /* if we get False back then it's actually unsupported */
4750 if (!reply) {
4751 reply = api_Unsupported(conn,vuid,params,tpscnt,data,tdscnt,mdrcnt,mprcnt,
4752 &rdata,&rparam,&rdata_len,&rparam_len);
4755 /* If api_Unsupported returns false we can't return anything. */
4756 if (reply) {
4757 send_trans_reply(conn, req, rparam, rparam_len,
4758 rdata, rdata_len, False);
4761 SAFE_FREE(rdata);
4762 SAFE_FREE(rparam);
4763 return;