source: trunk/samba-3.0.25pre1/source/smbd/lanman.c@ 7

Last change on this file since 7 was 1, checked in by Paul Smedley, 18 years ago

Initial code import

File size: 101.9 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
5
6 SMB Version handling
7 Copyright (C) John H Terpstra 1995-1998
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23/*
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
26 */
27
28#include "includes.h"
29
30extern struct current_user current_user;
31extern userdom_struct current_user_info;
32
33#ifdef CHECK_TYPES
34#undef CHECK_TYPES
35#endif
36#define CHECK_TYPES 0
37
38#define NERR_Success 0
39#define NERR_badpass 86
40#define NERR_notsupported 50
41
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)
46
47#define ACCESS_READ 0x01
48#define ACCESS_WRITE 0x02
49#define ACCESS_CREATE 0x04
50
51#define SHPWLEN 8 /* share password length */
52
53static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param, char *data,
54 int mdrcnt, int mprcnt,
55 char **rdata, char **rparam,
56 int *rdata_len, int *rparam_len);
57static BOOL api_TooSmall(connection_struct *conn, uint16 vuid, char *param, char *data,
58 int mdrcnt, int mprcnt,
59 char **rdata, char **rparam,
60 int *rdata_len, int *rparam_len);
61
62
63static int CopyExpanded(connection_struct *conn,
64 int snum, char **dst, char *src, int *n)
65{
66 pstring buf;
67 int l;
68
69 if (!src || !dst || !n || !(*dst)) {
70 return 0;
71 }
72
73 StrnCpy(buf,src,sizeof(buf)/2);
74 pstring_sub(buf,"%S",lp_servicename(snum));
75 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
76 conn->connectpath, conn->gid,
77 get_current_username(),
78 current_user_info.domain,
79 buf, sizeof(buf));
80 l = push_ascii(*dst,buf,*n, STR_TERMINATE);
81 (*dst) += l;
82 (*n) -= l;
83 return l;
84}
85
86static int CopyAndAdvance(char **dst, char *src, int *n)
87{
88 int l;
89 if (!src || !dst || !n || !(*dst)) {
90 return 0;
91 }
92 l = push_ascii(*dst,src,*n, STR_TERMINATE);
93 (*dst) += l;
94 (*n) -= l;
95 return l;
96}
97
98static int StrlenExpanded(connection_struct *conn, int snum, char *s)
99{
100 pstring buf;
101 if (!s) {
102 return 0;
103 }
104 StrnCpy(buf,s,sizeof(buf)/2);
105 pstring_sub(buf,"%S",lp_servicename(snum));
106 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
107 conn->connectpath, conn->gid,
108 get_current_username(),
109 current_user_info.domain,
110 buf, sizeof(buf));
111 return strlen(buf) + 1;
112}
113
114static char *Expand(connection_struct *conn, int snum, char *s)
115{
116 static pstring buf;
117 if (!s) {
118 return NULL;
119 }
120 StrnCpy(buf,s,sizeof(buf)/2);
121 pstring_sub(buf,"%S",lp_servicename(snum));
122 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
123 conn->connectpath, conn->gid,
124 get_current_username(),
125 current_user_info.domain,
126 buf, sizeof(buf));
127 return &buf[0];
128}
129
130/*******************************************************************
131 Check a API string for validity when we only need to check the prefix.
132******************************************************************/
133
134static BOOL prefix_ok(const char *str, const char *prefix)
135{
136 return(strncmp(str,prefix,strlen(prefix)) == 0);
137}
138
139struct pack_desc {
140 const char *format; /* formatstring for structure */
141 const char *subformat; /* subformat for structure */
142 char *base; /* baseaddress of buffer */
143 int buflen; /* remaining size for fixed part; on init: length of base */
144 int subcount; /* count of substructures */
145 char *structbuf; /* pointer into buffer for remaining fixed part */
146 int stringlen; /* remaining size for variable part */
147 char *stringbuf; /* pointer into buffer for remaining variable part */
148 int neededlen; /* total needed size */
149 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
150 const char *curpos; /* current position; pointer into format or subformat */
151 int errcode;
152};
153
154static int get_counter(const char **p)
155{
156 int i, n;
157 if (!p || !(*p)) {
158 return 1;
159 }
160 if (!isdigit((int)**p)) {
161 return 1;
162 }
163 for (n = 0;;) {
164 i = **p;
165 if (isdigit(i)) {
166 n = 10 * n + (i - '0');
167 } else {
168 return n;
169 }
170 (*p)++;
171 }
172}
173
174static int getlen(const char *p)
175{
176 int n = 0;
177 if (!p) {
178 return 0;
179 }
180
181 while (*p) {
182 switch( *p++ ) {
183 case 'W': /* word (2 byte) */
184 n += 2;
185 break;
186 case 'K': /* status word? (2 byte) */
187 n += 2;
188 break;
189 case 'N': /* count of substructures (word) at end */
190 n += 2;
191 break;
192 case 'D': /* double word (4 byte) */
193 case 'z': /* offset to zero terminated string (4 byte) */
194 case 'l': /* offset to user data (4 byte) */
195 n += 4;
196 break;
197 case 'b': /* offset to data (with counter) (4 byte) */
198 n += 4;
199 get_counter(&p);
200 break;
201 case 'B': /* byte (with optional counter) */
202 n += get_counter(&p);
203 break;
204 }
205 }
206 return n;
207}
208
209static BOOL init_package(struct pack_desc *p, int count, int subcount)
210{
211 int n = p->buflen;
212 int i;
213
214 if (!p->format || !p->base) {
215 return False;
216 }
217
218 i = count * getlen(p->format);
219 if (p->subformat) {
220 i += subcount * getlen(p->subformat);
221 }
222 p->structbuf = p->base;
223 p->neededlen = 0;
224 p->usedlen = 0;
225 p->subcount = 0;
226 p->curpos = p->format;
227 if (i > n) {
228 p->neededlen = i;
229 i = n = 0;
230#if 0
231 /*
232 * This is the old error code we used. Aparently
233 * WinNT/2k systems return ERRbuftoosmall (2123) and
234 * OS/2 needs this. I'm leaving this here so we can revert
235 * if needed. JRA.
236 */
237 p->errcode = ERRmoredata;
238#else
239 p->errcode = ERRbuftoosmall;
240#endif
241 } else {
242 p->errcode = NERR_Success;
243 }
244 p->buflen = i;
245 n -= i;
246 p->stringbuf = p->base + i;
247 p->stringlen = n;
248 return (p->errcode == NERR_Success);
249}
250
251static int package(struct pack_desc *p, ...)
252{
253 va_list args;
254 int needed=0, stringneeded;
255 const char *str=NULL;
256 int is_string=0, stringused;
257 int32 temp;
258
259 va_start(args,p);
260
261 if (!*p->curpos) {
262 if (!p->subcount) {
263 p->curpos = p->format;
264 } else {
265 p->curpos = p->subformat;
266 p->subcount--;
267 }
268 }
269#if CHECK_TYPES
270 str = va_arg(args,char*);
271 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
272#endif
273 stringneeded = -1;
274
275 if (!p->curpos) {
276 va_end(args);
277 return 0;
278 }
279
280 switch( *p->curpos++ ) {
281 case 'W': /* word (2 byte) */
282 needed = 2;
283 temp = va_arg(args,int);
284 if (p->buflen >= needed) {
285 SSVAL(p->structbuf,0,temp);
286 }
287 break;
288 case 'K': /* status word? (2 byte) */
289 needed = 2;
290 temp = va_arg(args,int);
291 if (p->buflen >= needed) {
292 SSVAL(p->structbuf,0,temp);
293 }
294 break;
295 case 'N': /* count of substructures (word) at end */
296 needed = 2;
297 p->subcount = va_arg(args,int);
298 if (p->buflen >= needed) {
299 SSVAL(p->structbuf,0,p->subcount);
300 }
301 break;
302 case 'D': /* double word (4 byte) */
303 needed = 4;
304 temp = va_arg(args,int);
305 if (p->buflen >= needed) {
306 SIVAL(p->structbuf,0,temp);
307 }
308 break;
309 case 'B': /* byte (with optional counter) */
310 needed = get_counter(&p->curpos);
311 {
312 char *s = va_arg(args,char*);
313 if (p->buflen >= needed) {
314 StrnCpy(p->structbuf,s?s:"",needed-1);
315 }
316 }
317 break;
318 case 'z': /* offset to zero terminated string (4 byte) */
319 str = va_arg(args,char*);
320 stringneeded = (str ? strlen(str)+1 : 0);
321 is_string = 1;
322 break;
323 case 'l': /* offset to user data (4 byte) */
324 str = va_arg(args,char*);
325 stringneeded = va_arg(args,int);
326 is_string = 0;
327 break;
328 case 'b': /* offset to data (with counter) (4 byte) */
329 str = va_arg(args,char*);
330 stringneeded = get_counter(&p->curpos);
331 is_string = 0;
332 break;
333 }
334
335 va_end(args);
336 if (stringneeded >= 0) {
337 needed = 4;
338 if (p->buflen >= needed) {
339 stringused = stringneeded;
340 if (stringused > p->stringlen) {
341 stringused = (is_string ? p->stringlen : 0);
342 if (p->errcode == NERR_Success) {
343 p->errcode = ERRmoredata;
344 }
345 }
346 if (!stringused) {
347 SIVAL(p->structbuf,0,0);
348 } else {
349 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
350 memcpy(p->stringbuf,str?str:"",stringused);
351 if (is_string) {
352 p->stringbuf[stringused-1] = '\0';
353 }
354 p->stringbuf += stringused;
355 p->stringlen -= stringused;
356 p->usedlen += stringused;
357 }
358 }
359 p->neededlen += stringneeded;
360 }
361
362 p->neededlen += needed;
363 if (p->buflen >= needed) {
364 p->structbuf += needed;
365 p->buflen -= needed;
366 p->usedlen += needed;
367 } else {
368 if (p->errcode == NERR_Success) {
369 p->errcode = ERRmoredata;
370 }
371 }
372 return 1;
373}
374
375#if CHECK_TYPES
376#define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
377#define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
378#else
379#define PACK(desc,t,v) package(desc,v)
380#define PACKl(desc,t,v,l) package(desc,v,l)
381#endif
382
383static void PACKI(struct pack_desc* desc, const char *t,int v)
384{
385 PACK(desc,t,v);
386}
387
388static void PACKS(struct pack_desc* desc,const char *t,const char *v)
389{
390 PACK(desc,t,v);
391}
392
393/****************************************************************************
394 Get a print queue.
395****************************************************************************/
396
397static void PackDriverData(struct pack_desc* desc)
398{
399 char drivdata[4+4+32];
400 SIVAL(drivdata,0,sizeof drivdata); /* cb */
401 SIVAL(drivdata,4,1000); /* lVersion */
402 memset(drivdata+8,0,32); /* szDeviceName */
403 push_ascii(drivdata+8,"NULL",-1, STR_TERMINATE);
404 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
405}
406
407static int check_printq_info(struct pack_desc* desc,
408 unsigned int uLevel, char *id1, char *id2)
409{
410 desc->subformat = NULL;
411 switch( uLevel ) {
412 case 0:
413 desc->format = "B13";
414 break;
415 case 1:
416 desc->format = "B13BWWWzzzzzWW";
417 break;
418 case 2:
419 desc->format = "B13BWWWzzzzzWN";
420 desc->subformat = "WB21BB16B10zWWzDDz";
421 break;
422 case 3:
423 desc->format = "zWWWWzzzzWWzzl";
424 break;
425 case 4:
426 desc->format = "zWWWWzzzzWNzzl";
427 desc->subformat = "WWzWWDDzz";
428 break;
429 case 5:
430 desc->format = "z";
431 break;
432 case 51:
433 desc->format = "K";
434 break;
435 case 52:
436 desc->format = "WzzzzzzzzN";
437 desc->subformat = "z";
438 break;
439 default:
440 return False;
441 }
442 if (strcmp(desc->format,id1) != 0) {
443 return False;
444 }
445 if (desc->subformat && strcmp(desc->subformat,id2) != 0) {
446 return False;
447 }
448 return True;
449}
450
451
452#define RAP_JOB_STATUS_QUEUED 0
453#define RAP_JOB_STATUS_PAUSED 1
454#define RAP_JOB_STATUS_SPOOLING 2
455#define RAP_JOB_STATUS_PRINTING 3
456#define RAP_JOB_STATUS_PRINTED 4
457
458#define RAP_QUEUE_STATUS_PAUSED 1
459#define RAP_QUEUE_STATUS_ERROR 2
460
461/* turn a print job status into a on the wire status
462*/
463static int printj_status(int v)
464{
465 switch (v) {
466 case LPQ_QUEUED:
467 return RAP_JOB_STATUS_QUEUED;
468 case LPQ_PAUSED:
469 return RAP_JOB_STATUS_PAUSED;
470 case LPQ_SPOOLING:
471 return RAP_JOB_STATUS_SPOOLING;
472 case LPQ_PRINTING:
473 return RAP_JOB_STATUS_PRINTING;
474 }
475 return 0;
476}
477
478/* turn a print queue status into a on the wire status
479*/
480static int printq_status(int v)
481{
482 switch (v) {
483 case LPQ_QUEUED:
484 return 0;
485 case LPQ_PAUSED:
486 return RAP_QUEUE_STATUS_PAUSED;
487 }
488 return RAP_QUEUE_STATUS_ERROR;
489}
490
491static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
492 struct pack_desc *desc,
493 print_queue_struct *queue, int n)
494{
495 time_t t = queue->time;
496
497 /* the client expects localtime */
498 t -= get_time_zone(t);
499
500 PACKI(desc,"W",pjobid_to_rap(lp_const_servicename(snum),queue->job)); /* uJobId */
501 if (uLevel == 1) {
502 PACKS(desc,"B21",queue->fs_user); /* szUserName */
503 PACKS(desc,"B",""); /* pad */
504 PACKS(desc,"B16",""); /* szNotifyName */
505 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
506 PACKS(desc,"z",""); /* pszParms */
507 PACKI(desc,"W",n+1); /* uPosition */
508 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
509 PACKS(desc,"z",""); /* pszStatus */
510 PACKI(desc,"D",t); /* ulSubmitted */
511 PACKI(desc,"D",queue->size); /* ulSize */
512 PACKS(desc,"z",queue->fs_file); /* pszComment */
513 }
514 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
515 PACKI(desc,"W",queue->priority); /* uPriority */
516 PACKS(desc,"z",queue->fs_user); /* pszUserName */
517 PACKI(desc,"W",n+1); /* uPosition */
518 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
519 PACKI(desc,"D",t); /* ulSubmitted */
520 PACKI(desc,"D",queue->size); /* ulSize */
521 PACKS(desc,"z","Samba"); /* pszComment */
522 PACKS(desc,"z",queue->fs_file); /* pszDocument */
523 if (uLevel == 3) {
524 PACKS(desc,"z",""); /* pszNotifyName */
525 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
526 PACKS(desc,"z",""); /* pszParms */
527 PACKS(desc,"z",""); /* pszStatus */
528 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
529 PACKS(desc,"z","lpd"); /* pszQProcName */
530 PACKS(desc,"z",""); /* pszQProcParms */
531 PACKS(desc,"z","NULL"); /* pszDriverName */
532 PackDriverData(desc); /* pDriverData */
533 PACKS(desc,"z",""); /* pszPrinterName */
534 } else if (uLevel == 4) { /* OS2 */
535 PACKS(desc,"z",""); /* pszSpoolFileName */
536 PACKS(desc,"z",""); /* pszPortName */
537 PACKS(desc,"z",""); /* pszStatus */
538 PACKI(desc,"D",0); /* ulPagesSpooled */
539 PACKI(desc,"D",0); /* ulPagesSent */
540 PACKI(desc,"D",0); /* ulPagesPrinted */
541 PACKI(desc,"D",0); /* ulTimePrinted */
542 PACKI(desc,"D",0); /* ulExtendJobStatus */
543 PACKI(desc,"D",0); /* ulStartPage */
544 PACKI(desc,"D",0); /* ulEndPage */
545 }
546 }
547}
548
549/********************************************************************
550 Return a driver name given an snum.
551 Returns True if from tdb, False otherwise.
552 ********************************************************************/
553
554static BOOL get_driver_name(int snum, pstring drivername)
555{
556 NT_PRINTER_INFO_LEVEL *info = NULL;
557 BOOL in_tdb = False;
558
559 get_a_printer (NULL, &info, 2, lp_servicename(snum));
560 if (info != NULL) {
561 pstrcpy( drivername, info->info_2->drivername);
562 in_tdb = True;
563 free_a_printer(&info, 2);
564 }
565
566 return in_tdb;
567}
568
569/********************************************************************
570 Respond to the DosPrintQInfo command with a level of 52
571 This is used to get printer driver information for Win9x clients
572 ********************************************************************/
573static void fill_printq_info_52(connection_struct *conn, int snum,
574 struct pack_desc* desc, int count )
575{
576 int i;
577 fstring location;
578 NT_PRINTER_DRIVER_INFO_LEVEL driver;
579 NT_PRINTER_INFO_LEVEL *printer = NULL;
580
581 ZERO_STRUCT(driver);
582
583 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
584 DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n",
585 lp_servicename(snum)));
586 goto err;
587 }
588
589 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
590 "Windows 4.0", 0)) )
591 {
592 DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n",
593 printer->info_2->drivername));
594 goto err;
595 }
596
597 trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
598 trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
599 trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
600
601 PACKI(desc, "W", 0x0400); /* don't know */
602 PACKS(desc, "z", driver.info_3->name); /* long printer name */
603 PACKS(desc, "z", driver.info_3->driverpath); /* Driverfile Name */
604 PACKS(desc, "z", driver.info_3->datafile); /* Datafile name */
605 PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
606
607 fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
608 standard_sub_basic( "", "", location, sizeof(location)-1 );
609 PACKS(desc,"z", location); /* share to retrieve files */
610
611 PACKS(desc,"z", driver.info_3->defaultdatatype); /* default data type */
612 PACKS(desc,"z", driver.info_3->helpfile); /* helpfile name */
613 PACKS(desc,"z", driver.info_3->driverpath); /* driver name */
614
615 DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
616 DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
617 DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
618 DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
619 DEBUG(3,("Driver Location: %s:\n",location));
620 DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
621 DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
622 PACKI(desc,"N",count); /* number of files to copy */
623
624 for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++)
625 {
626 trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
627 PACKS(desc,"z",driver.info_3->dependentfiles[i]); /* driver files to copy */
628 DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
629 }
630
631 /* sanity check */
632 if ( i != count )
633 DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n",
634 count, i));
635
636 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", SERVICE(snum),i));
637
638 desc->errcode=NERR_Success;
639 goto done;
640
641err:
642 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
643 desc->errcode=NERR_notsupported;
644
645done:
646 if ( printer )
647 free_a_printer( &printer, 2 );
648
649 if ( driver.info_3 )
650 free_a_printer_driver( driver, 3 );
651}
652
653
654static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
655 struct pack_desc* desc,
656 int count, print_queue_struct* queue,
657 print_status_struct* status)
658{
659 switch (uLevel) {
660 case 1:
661 case 2:
662 PACKS(desc,"B13",SERVICE(snum));
663 break;
664 case 3:
665 case 4:
666 case 5:
667 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
668 break;
669 case 51:
670 PACKI(desc,"K",printq_status(status->status));
671 break;
672 }
673
674 if (uLevel == 1 || uLevel == 2) {
675 PACKS(desc,"B",""); /* alignment */
676 PACKI(desc,"W",5); /* priority */
677 PACKI(desc,"W",0); /* start time */
678 PACKI(desc,"W",0); /* until time */
679 PACKS(desc,"z",""); /* pSepFile */
680 PACKS(desc,"z","lpd"); /* pPrProc */
681 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
682 PACKS(desc,"z",""); /* pParms */
683 if (snum < 0) {
684 PACKS(desc,"z","UNKNOWN PRINTER");
685 PACKI(desc,"W",LPSTAT_ERROR);
686 }
687 else if (!status || !status->message[0]) {
688 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
689 PACKI(desc,"W",LPSTAT_OK); /* status */
690 } else {
691 PACKS(desc,"z",status->message);
692 PACKI(desc,"W",printq_status(status->status)); /* status */
693 }
694 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
695 }
696
697 if (uLevel == 3 || uLevel == 4) {
698 pstring drivername;
699
700 PACKI(desc,"W",5); /* uPriority */
701 PACKI(desc,"W",0); /* uStarttime */
702 PACKI(desc,"W",0); /* uUntiltime */
703 PACKI(desc,"W",5); /* pad1 */
704 PACKS(desc,"z",""); /* pszSepFile */
705 PACKS(desc,"z","WinPrint"); /* pszPrProc */
706 PACKS(desc,"z",NULL); /* pszParms */
707 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
708 /* "don't ask" that it's done this way to fix corrupted
709 Win9X/ME printer comments. */
710 if (!status) {
711 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
712 } else {
713 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
714 }
715 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
716 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
717 get_driver_name(snum,drivername);
718 PACKS(desc,"z",drivername); /* pszDriverName */
719 PackDriverData(desc); /* pDriverData */
720 }
721
722 if (uLevel == 2 || uLevel == 4) {
723 int i;
724 for (i=0;i<count;i++)
725 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
726 }
727
728 if (uLevel==52)
729 fill_printq_info_52( conn, snum, desc, count );
730}
731
732/* This function returns the number of files for a given driver */
733static int get_printerdrivernumber(int snum)
734{
735 int result = 0;
736 NT_PRINTER_DRIVER_INFO_LEVEL driver;
737 NT_PRINTER_INFO_LEVEL *printer = NULL;
738
739 ZERO_STRUCT(driver);
740
741 if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
742 DEBUG(3,("get_printerdrivernumber: Failed to lookup printer [%s]\n",
743 lp_servicename(snum)));
744 goto done;
745 }
746
747 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername,
748 "Windows 4.0", 0)) )
749 {
750 DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n",
751 printer->info_2->drivername));
752 goto done;
753 }
754
755 /* count the number of files */
756 while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
757 result++;
758 \
759 done:
760 if ( printer )
761 free_a_printer( &printer, 2 );
762
763 if ( driver.info_3 )
764 free_a_printer_driver( driver, 3 );
765
766 return result;
767}
768
769static BOOL api_DosPrintQGetInfo(connection_struct *conn,
770 uint16 vuid, char *param,char *data,
771 int mdrcnt,int mprcnt,
772 char **rdata,char **rparam,
773 int *rdata_len,int *rparam_len)
774{
775 char *str1 = param+2;
776 char *str2 = skip_string(str1,1);
777 char *p = skip_string(str2,1);
778 char *QueueName = p;
779 unsigned int uLevel;
780 int count=0;
781 int snum;
782 char* str3;
783 struct pack_desc desc;
784 print_queue_struct *queue=NULL;
785 print_status_struct status;
786 char* tmpdata=NULL;
787
788 memset((char *)&status,'\0',sizeof(status));
789 memset((char *)&desc,'\0',sizeof(desc));
790
791 p = skip_string(p,1);
792 uLevel = SVAL(p,0);
793 str3 = p + 4;
794
795 /* remove any trailing username */
796 if ((p = strchr_m(QueueName,'%')))
797 *p = 0;
798
799 DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
800
801 /* check it's a supported varient */
802 if (!prefix_ok(str1,"zWrLh"))
803 return False;
804 if (!check_printq_info(&desc,uLevel,str2,str3)) {
805 /*
806 * Patch from Scott Moomaw <scott@bridgewater.edu>
807 * to return the 'invalid info level' error if an
808 * unknown level was requested.
809 */
810 *rdata_len = 0;
811 *rparam_len = 6;
812 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
813 if (!*rparam) {
814 return False;
815 }
816 SSVALS(*rparam,0,ERRunknownlevel);
817 SSVAL(*rparam,2,0);
818 SSVAL(*rparam,4,0);
819 return(True);
820 }
821
822 snum = find_service(QueueName);
823 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
824 return False;
825
826 if (uLevel==52) {
827 count = get_printerdrivernumber(snum);
828 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
829 } else {
830 count = print_queue_status(snum, &queue,&status);
831 }
832
833 if (mdrcnt > 0) {
834 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
835 if (!*rdata) {
836 return False;
837 }
838 desc.base = *rdata;
839 desc.buflen = mdrcnt;
840 } else {
841 /*
842 * Don't return data but need to get correct length
843 * init_package will return wrong size if buflen=0
844 */
845 desc.buflen = getlen(desc.format);
846 desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen);
847 }
848
849 if (init_package(&desc,1,count)) {
850 desc.subcount = count;
851 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
852 }
853
854 *rdata_len = desc.usedlen;
855
856 /*
857 * We must set the return code to ERRbuftoosmall
858 * in order to support lanman style printing with Win NT/2k
859 * clients --jerry
860 */
861 if (!mdrcnt && lp_disable_spoolss())
862 desc.errcode = ERRbuftoosmall;
863
864 *rdata_len = desc.usedlen;
865 *rparam_len = 6;
866 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
867 if (!*rparam) {
868 return False;
869 }
870 SSVALS(*rparam,0,desc.errcode);
871 SSVAL(*rparam,2,0);
872 SSVAL(*rparam,4,desc.neededlen);
873
874 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
875
876 SAFE_FREE(queue);
877 SAFE_FREE(tmpdata);
878
879 return(True);
880}
881
882/****************************************************************************
883 View list of all print jobs on all queues.
884****************************************************************************/
885
886static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
887 int mdrcnt, int mprcnt,
888 char **rdata, char** rparam,
889 int *rdata_len, int *rparam_len)
890{
891 char *param_format = param+2;
892 char *output_format1 = skip_string(param_format,1);
893 char *p = skip_string(output_format1,1);
894 unsigned int uLevel = SVAL(p,0);
895 char *output_format2 = p + 4;
896 int services = lp_numservices();
897 int i, n;
898 struct pack_desc desc;
899 print_queue_struct **queue = NULL;
900 print_status_struct *status = NULL;
901 int *subcntarr = NULL;
902 int queuecnt = 0, subcnt = 0, succnt = 0;
903
904 memset((char *)&desc,'\0',sizeof(desc));
905
906 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
907
908 if (!prefix_ok(param_format,"WrLeh")) {
909 return False;
910 }
911 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
912 /*
913 * Patch from Scott Moomaw <scott@bridgewater.edu>
914 * to return the 'invalid info level' error if an
915 * unknown level was requested.
916 */
917 *rdata_len = 0;
918 *rparam_len = 6;
919 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
920 if (!*rparam) {
921 return False;
922 }
923 SSVALS(*rparam,0,ERRunknownlevel);
924 SSVAL(*rparam,2,0);
925 SSVAL(*rparam,4,0);
926 return(True);
927 }
928
929 for (i = 0; i < services; i++) {
930 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
931 queuecnt++;
932 }
933 }
934
935 if((queue = SMB_MALLOC_ARRAY(print_queue_struct*, queuecnt)) == NULL) {
936 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
937 goto err;
938 }
939 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
940 if((status = SMB_MALLOC_ARRAY(print_status_struct,queuecnt)) == NULL) {
941 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
942 goto err;
943 }
944 memset(status,0,queuecnt*sizeof(print_status_struct));
945 if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) {
946 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
947 goto err;
948 }
949
950 subcnt = 0;
951 n = 0;
952 for (i = 0; i < services; i++) {
953 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
954 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
955 subcnt += subcntarr[n];
956 n++;
957 }
958 }
959
960 if (mdrcnt > 0) {
961 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
962 if (!*rdata) {
963 goto err;
964 }
965 }
966 desc.base = *rdata;
967 desc.buflen = mdrcnt;
968
969 if (init_package(&desc,queuecnt,subcnt)) {
970 n = 0;
971 succnt = 0;
972 for (i = 0; i < services; i++) {
973 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
974 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
975 n++;
976 if (desc.errcode == NERR_Success) {
977 succnt = n;
978 }
979 }
980 }
981 }
982
983 SAFE_FREE(subcntarr);
984
985 *rdata_len = desc.usedlen;
986 *rparam_len = 8;
987 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
988 if (!*rparam) {
989 goto err;
990 }
991 SSVALS(*rparam,0,desc.errcode);
992 SSVAL(*rparam,2,0);
993 SSVAL(*rparam,4,succnt);
994 SSVAL(*rparam,6,queuecnt);
995
996 for (i = 0; i < queuecnt; i++) {
997 if (queue) {
998 SAFE_FREE(queue[i]);
999 }
1000 }
1001
1002 SAFE_FREE(queue);
1003 SAFE_FREE(status);
1004
1005 return True;
1006
1007 err:
1008
1009 SAFE_FREE(subcntarr);
1010 for (i = 0; i < queuecnt; i++) {
1011 if (queue) {
1012 SAFE_FREE(queue[i]);
1013 }
1014 }
1015 SAFE_FREE(queue);
1016 SAFE_FREE(status);
1017
1018 return False;
1019}
1020
1021/****************************************************************************
1022 Get info level for a server list query.
1023****************************************************************************/
1024
1025static BOOL check_server_info(int uLevel, char* id)
1026{
1027 switch( uLevel ) {
1028 case 0:
1029 if (strcmp(id,"B16") != 0) {
1030 return False;
1031 }
1032 break;
1033 case 1:
1034 if (strcmp(id,"B16BBDz") != 0) {
1035 return False;
1036 }
1037 break;
1038 default:
1039 return False;
1040 }
1041 return True;
1042}
1043
1044struct srv_info_struct {
1045 fstring name;
1046 uint32 type;
1047 fstring comment;
1048 fstring domain;
1049 BOOL server_added;
1050};
1051
1052/*******************************************************************
1053 Get server info lists from the files saved by nmbd. Return the
1054 number of entries.
1055******************************************************************/
1056
1057static int get_server_info(uint32 servertype,
1058 struct srv_info_struct **servers,
1059 const char *domain)
1060{
1061 int count=0;
1062 int alloced=0;
1063 char **lines;
1064 BOOL local_list_only;
1065 int i;
1066
1067 lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
1068 if (!lines) {
1069 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1070 return 0;
1071 }
1072
1073 /* request for everything is code for request all servers */
1074 if (servertype == SV_TYPE_ALL) {
1075 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1076 }
1077
1078 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1079
1080 DEBUG(4,("Servertype search: %8x\n",servertype));
1081
1082 for (i=0;lines[i];i++) {
1083 fstring stype;
1084 struct srv_info_struct *s;
1085 const char *ptr = lines[i];
1086 BOOL ok = True;
1087
1088 if (!*ptr) {
1089 continue;
1090 }
1091
1092 if (count == alloced) {
1093 alloced += 10;
1094 *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
1095 if (!*servers) {
1096 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1097 file_lines_free(lines);
1098 return 0;
1099 }
1100 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1101 }
1102 s = &(*servers)[count];
1103
1104 if (!next_token(&ptr,s->name, NULL, sizeof(s->name))) {
1105 continue;
1106 }
1107 if (!next_token(&ptr,stype, NULL, sizeof(stype))) {
1108 continue;
1109 }
1110 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) {
1111 continue;
1112 }
1113 if (!next_token(&ptr,s->domain, NULL, sizeof(s->domain))) {
1114 /* this allows us to cope with an old nmbd */
1115 fstrcpy(s->domain,lp_workgroup());
1116 }
1117
1118 if (sscanf(stype,"%X",&s->type) != 1) {
1119 DEBUG(4,("r:host file "));
1120 ok = False;
1121 }
1122
1123 /* Filter the servers/domains we return based on what was asked for. */
1124
1125 /* Check to see if we are being asked for a local list only. */
1126 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1127 DEBUG(4,("r: local list only"));
1128 ok = False;
1129 }
1130
1131 /* doesn't match up: don't want it */
1132 if (!(servertype & s->type)) {
1133 DEBUG(4,("r:serv type "));
1134 ok = False;
1135 }
1136
1137 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1138 (s->type & SV_TYPE_DOMAIN_ENUM)) {
1139 DEBUG(4,("s: dom mismatch "));
1140 ok = False;
1141 }
1142
1143 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1144 ok = False;
1145 }
1146
1147 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1148 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1149
1150 if (ok) {
1151 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1152 s->name, s->type, s->comment, s->domain));
1153 s->server_added = True;
1154 count++;
1155 } else {
1156 DEBUG(4,("%20s %8x %25s %15s\n",
1157 s->name, s->type, s->comment, s->domain));
1158 }
1159 }
1160
1161 file_lines_free(lines);
1162 return count;
1163}
1164
1165/*******************************************************************
1166 Fill in a server info structure.
1167******************************************************************/
1168
1169static int fill_srv_info(struct srv_info_struct *service,
1170 int uLevel, char **buf, int *buflen,
1171 char **stringbuf, int *stringspace, char *baseaddr)
1172{
1173 int struct_len;
1174 char* p;
1175 char* p2;
1176 int l2;
1177 int len;
1178
1179 switch (uLevel) {
1180 case 0:
1181 struct_len = 16;
1182 break;
1183 case 1:
1184 struct_len = 26;
1185 break;
1186 default:
1187 return -1;
1188 }
1189
1190 if (!buf) {
1191 len = 0;
1192 switch (uLevel) {
1193 case 1:
1194 len = strlen(service->comment)+1;
1195 break;
1196 }
1197
1198 *buflen = struct_len;
1199 *stringspace = len;
1200 return struct_len + len;
1201 }
1202
1203 len = struct_len;
1204 p = *buf;
1205 if (*buflen < struct_len) {
1206 return -1;
1207 }
1208 if (stringbuf) {
1209 p2 = *stringbuf;
1210 l2 = *stringspace;
1211 } else {
1212 p2 = p + struct_len;
1213 l2 = *buflen - struct_len;
1214 }
1215 if (!baseaddr) {
1216 baseaddr = p;
1217 }
1218
1219 switch (uLevel) {
1220 case 0:
1221 push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1222 break;
1223
1224 case 1:
1225 push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE);
1226 SIVAL(p,18,service->type);
1227 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1228 len += CopyAndAdvance(&p2,service->comment,&l2);
1229 break;
1230 }
1231
1232 if (stringbuf) {
1233 *buf = p + struct_len;
1234 *buflen -= struct_len;
1235 *stringbuf = p2;
1236 *stringspace = l2;
1237 } else {
1238 *buf = p2;
1239 *buflen -= len;
1240 }
1241 return len;
1242}
1243
1244
1245static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1246{
1247 return(strcmp(s1->name,s2->name));
1248}
1249
1250/****************************************************************************
1251 View list of servers available (or possibly domains). The info is
1252 extracted from lists saved by nmbd on the local host.
1253****************************************************************************/
1254
1255static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1256 int mdrcnt, int mprcnt, char **rdata,
1257 char **rparam, int *rdata_len, int *rparam_len)
1258{
1259 char *str1 = param+2;
1260 char *str2 = skip_string(str1,1);
1261 char *p = skip_string(str2,1);
1262 int uLevel = SVAL(p,0);
1263 int buf_len = SVAL(p,2);
1264 uint32 servertype = IVAL(p,4);
1265 char *p2;
1266 int data_len, fixed_len, string_len;
1267 int f_len = 0, s_len = 0;
1268 struct srv_info_struct *servers=NULL;
1269 int counted=0,total=0;
1270 int i,missed;
1271 fstring domain;
1272 BOOL domain_request;
1273 BOOL local_request;
1274
1275 /* If someone sets all the bits they don't really mean to set
1276 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1277 known servers. */
1278
1279 if (servertype == SV_TYPE_ALL) {
1280 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1281 }
1282
1283 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1284 any other bit (they may just set this bit on it's own) they
1285 want all the locally seen servers. However this bit can be
1286 set on its own so set the requested servers to be
1287 ALL - DOMAIN_ENUM. */
1288
1289 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
1290 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1291 }
1292
1293 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1294 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1295
1296 p += 8;
1297
1298 if (!prefix_ok(str1,"WrLehD")) {
1299 return False;
1300 }
1301 if (!check_server_info(uLevel,str2)) {
1302 return False;
1303 }
1304
1305 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1306 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1307 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1308
1309 if (strcmp(str1, "WrLehDz") == 0) {
1310 pull_ascii_fstring(domain, p);
1311 } else {
1312 fstrcpy(domain, lp_workgroup());
1313 }
1314
1315 if (lp_browse_list()) {
1316 total = get_server_info(servertype,&servers,domain);
1317 }
1318
1319 data_len = fixed_len = string_len = 0;
1320 missed = 0;
1321
1322 if (total > 0) {
1323 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1324 }
1325
1326 {
1327 char *lastname=NULL;
1328
1329 for (i=0;i<total;i++) {
1330 struct srv_info_struct *s = &servers[i];
1331
1332 if (lastname && strequal(lastname,s->name)) {
1333 continue;
1334 }
1335 lastname = s->name;
1336 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1337 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1338 s->name, s->type, s->comment, s->domain));
1339
1340 if (data_len <= buf_len) {
1341 counted++;
1342 fixed_len += f_len;
1343 string_len += s_len;
1344 } else {
1345 missed++;
1346 }
1347 }
1348 }
1349
1350 *rdata_len = fixed_len + string_len;
1351 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1352 if (!*rdata) {
1353 return False;
1354 }
1355 memset(*rdata,'\0',*rdata_len);
1356
1357 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1358 p = *rdata;
1359 f_len = fixed_len;
1360 s_len = string_len;
1361
1362 {
1363 char *lastname=NULL;
1364 int count2 = counted;
1365
1366 for (i = 0; i < total && count2;i++) {
1367 struct srv_info_struct *s = &servers[i];
1368
1369 if (lastname && strequal(lastname,s->name)) {
1370 continue;
1371 }
1372 lastname = s->name;
1373 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1374 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1375 s->name, s->type, s->comment, s->domain));
1376 count2--;
1377 }
1378 }
1379
1380 *rparam_len = 8;
1381 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1382 if (!*rparam) {
1383 return False;
1384 }
1385 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1386 SSVAL(*rparam,2,0);
1387 SSVAL(*rparam,4,counted);
1388 SSVAL(*rparam,6,counted+missed);
1389
1390 SAFE_FREE(servers);
1391
1392 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1393 domain,uLevel,counted,counted+missed));
1394
1395 return True;
1396}
1397
1398/****************************************************************************
1399 command 0x34 - suspected of being a "Lookup Names" stub api
1400 ****************************************************************************/
1401
1402static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1403 int mdrcnt, int mprcnt, char **rdata,
1404 char **rparam, int *rdata_len, int *rparam_len)
1405{
1406 char *str1 = param+2;
1407 char *str2 = skip_string(str1,1);
1408 char *p = skip_string(str2,1);
1409 int uLevel = SVAL(p,0);
1410 int buf_len = SVAL(p,2);
1411 int counted=0;
1412 int missed=0;
1413
1414 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1415 str1, str2, p, uLevel, buf_len));
1416
1417 if (!prefix_ok(str1,"zWrLeh")) {
1418 return False;
1419 }
1420
1421 *rdata_len = 0;
1422
1423 *rparam_len = 8;
1424 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1425 if (!*rparam) {
1426 return False;
1427 }
1428
1429 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1430 SSVAL(*rparam,2,0);
1431 SSVAL(*rparam,4,counted);
1432 SSVAL(*rparam,6,counted+missed);
1433
1434 return True;
1435}
1436
1437/****************************************************************************
1438 get info about a share
1439 ****************************************************************************/
1440
1441static BOOL check_share_info(int uLevel, char* id)
1442{
1443 switch( uLevel ) {
1444 case 0:
1445 if (strcmp(id,"B13") != 0) {
1446 return False;
1447 }
1448 break;
1449 case 1:
1450 if (strcmp(id,"B13BWz") != 0) {
1451 return False;
1452 }
1453 break;
1454 case 2:
1455 if (strcmp(id,"B13BWzWWWzB9B") != 0) {
1456 return False;
1457 }
1458 break;
1459 case 91:
1460 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) {
1461 return False;
1462 }
1463 break;
1464 default:
1465 return False;
1466 }
1467 return True;
1468}
1469
1470static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1471 char** buf, int* buflen,
1472 char** stringbuf, int* stringspace, char* baseaddr)
1473{
1474 int struct_len;
1475 char* p;
1476 char* p2;
1477 int l2;
1478 int len;
1479
1480 switch( uLevel ) {
1481 case 0:
1482 struct_len = 13;
1483 break;
1484 case 1:
1485 struct_len = 20;
1486 break;
1487 case 2:
1488 struct_len = 40;
1489 break;
1490 case 91:
1491 struct_len = 68;
1492 break;
1493 default:
1494 return -1;
1495 }
1496
1497
1498 if (!buf) {
1499 len = 0;
1500
1501 if (uLevel > 0) {
1502 len += StrlenExpanded(conn,snum,lp_comment(snum));
1503 }
1504 if (uLevel > 1) {
1505 len += strlen(lp_pathname(snum)) + 1;
1506 }
1507 if (buflen) {
1508 *buflen = struct_len;
1509 }
1510 if (stringspace) {
1511 *stringspace = len;
1512 }
1513 return struct_len + len;
1514 }
1515
1516 len = struct_len;
1517 p = *buf;
1518 if ((*buflen) < struct_len) {
1519 return -1;
1520 }
1521
1522 if (stringbuf) {
1523 p2 = *stringbuf;
1524 l2 = *stringspace;
1525 } else {
1526 p2 = p + struct_len;
1527 l2 = (*buflen) - struct_len;
1528 }
1529
1530 if (!baseaddr) {
1531 baseaddr = p;
1532 }
1533
1534 push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
1535
1536 if (uLevel > 0) {
1537 int type;
1538
1539 SCVAL(p,13,0);
1540 type = STYPE_DISKTREE;
1541 if (lp_print_ok(snum)) {
1542 type = STYPE_PRINTQ;
1543 }
1544 if (strequal("IPC",lp_fstype(snum))) {
1545 type = STYPE_IPC;
1546 }
1547 SSVAL(p,14,type); /* device type */
1548 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1549 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1550 }
1551
1552 if (uLevel > 1) {
1553 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1554 SSVALS(p,22,-1); /* max uses */
1555 SSVAL(p,24,1); /* current uses */
1556 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1557 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1558 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1559 }
1560
1561 if (uLevel > 2) {
1562 memset(p+40,0,SHPWLEN+2);
1563 SSVAL(p,50,0);
1564 SIVAL(p,52,0);
1565 SSVAL(p,56,0);
1566 SSVAL(p,58,0);
1567 SIVAL(p,60,0);
1568 SSVAL(p,64,0);
1569 SSVAL(p,66,0);
1570 }
1571
1572 if (stringbuf) {
1573 (*buf) = p + struct_len;
1574 (*buflen) -= struct_len;
1575 (*stringbuf) = p2;
1576 (*stringspace) = l2;
1577 } else {
1578 (*buf) = p2;
1579 (*buflen) -= len;
1580 }
1581
1582 return len;
1583}
1584
1585static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1586 int mdrcnt,int mprcnt,
1587 char **rdata,char **rparam,
1588 int *rdata_len,int *rparam_len)
1589{
1590 char *str1 = param+2;
1591 char *str2 = skip_string(str1,1);
1592 char *netname = skip_string(str2,1);
1593 char *p = skip_string(netname,1);
1594 int uLevel = SVAL(p,0);
1595 int snum = find_service(netname);
1596
1597 if (snum < 0) {
1598 return False;
1599 }
1600
1601 /* check it's a supported varient */
1602 if (!prefix_ok(str1,"zWrLh")) {
1603 return False;
1604 }
1605 if (!check_share_info(uLevel,str2)) {
1606 return False;
1607 }
1608
1609 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
1610 if (!*rdata) {
1611 return False;
1612 }
1613 p = *rdata;
1614 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1615 if (*rdata_len < 0) {
1616 return False;
1617 }
1618
1619 *rparam_len = 6;
1620 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1621 if (!*rparam) {
1622 return False;
1623 }
1624 SSVAL(*rparam,0,NERR_Success);
1625 SSVAL(*rparam,2,0); /* converter word */
1626 SSVAL(*rparam,4,*rdata_len);
1627
1628 return True;
1629}
1630
1631/****************************************************************************
1632 View the list of available shares.
1633
1634 This function is the server side of the NetShareEnum() RAP call.
1635 It fills the return buffer with share names and share comments.
1636 Note that the return buffer normally (in all known cases) allows only
1637 twelve byte strings for share names (plus one for a nul terminator).
1638 Share names longer than 12 bytes must be skipped.
1639 ****************************************************************************/
1640
1641static BOOL api_RNetShareEnum( connection_struct *conn,
1642 uint16 vuid,
1643 char *param,
1644 char *data,
1645 int mdrcnt,
1646 int mprcnt,
1647 char **rdata,
1648 char **rparam,
1649 int *rdata_len,
1650 int *rparam_len )
1651{
1652 char *str1 = param+2;
1653 char *str2 = skip_string(str1,1);
1654 char *p = skip_string(str2,1);
1655 int uLevel = SVAL(p,0);
1656 int buf_len = SVAL(p,2);
1657 char *p2;
1658 int count = 0;
1659 int total=0,counted=0;
1660 BOOL missed = False;
1661 int i;
1662 int data_len, fixed_len, string_len;
1663 int f_len = 0, s_len = 0;
1664
1665 if (!prefix_ok(str1,"WrLeh")) {
1666 return False;
1667 }
1668 if (!check_share_info(uLevel,str2)) {
1669 return False;
1670 }
1671
1672 /* Ensure all the usershares are loaded. */
1673 become_root();
1674 count = load_usershare_shares();
1675 unbecome_root();
1676
1677 data_len = fixed_len = string_len = 0;
1678 for (i=0;i<count;i++) {
1679 fstring servicename_dos;
1680 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1681 continue;
1682 }
1683 push_ascii_fstring(servicename_dos, lp_servicename(i));
1684 /* Maximum name length = 13. */
1685 if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) {
1686 total++;
1687 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1688 if (data_len <= buf_len) {
1689 counted++;
1690 fixed_len += f_len;
1691 string_len += s_len;
1692 } else {
1693 missed = True;
1694 }
1695 }
1696 }
1697
1698 *rdata_len = fixed_len + string_len;
1699 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1700 if (!*rdata) {
1701 return False;
1702 }
1703 memset(*rdata,0,*rdata_len);
1704
1705 p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */
1706 p = *rdata;
1707 f_len = fixed_len;
1708 s_len = string_len;
1709
1710 for( i = 0; i < count; i++ ) {
1711 fstring servicename_dos;
1712 if (!(lp_browseable(i) && lp_snum_ok(i))) {
1713 continue;
1714 }
1715
1716 push_ascii_fstring(servicename_dos, lp_servicename(i));
1717 if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) {
1718 if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) {
1719 break;
1720 }
1721 }
1722 }
1723
1724 *rparam_len = 8;
1725 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1726 if (!*rparam) {
1727 return False;
1728 }
1729 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1730 SSVAL(*rparam,2,0);
1731 SSVAL(*rparam,4,counted);
1732 SSVAL(*rparam,6,total);
1733
1734 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1735 counted,total,uLevel,
1736 buf_len,*rdata_len,mdrcnt));
1737
1738 return True;
1739}
1740
1741/****************************************************************************
1742 Add a share
1743 ****************************************************************************/
1744
1745static BOOL api_RNetShareAdd(connection_struct *conn,uint16 vuid, char *param,char *data,
1746 int mdrcnt,int mprcnt,
1747 char **rdata,char **rparam,
1748 int *rdata_len,int *rparam_len)
1749{
1750 char *str1 = param+2;
1751 char *str2 = skip_string(str1,1);
1752 char *p = skip_string(str2,1);
1753 int uLevel = SVAL(p,0);
1754 fstring sharename;
1755 fstring comment;
1756 pstring pathname;
1757 char *command, *cmdname;
1758 unsigned int offset;
1759 int snum;
1760 int res = ERRunsup;
1761
1762 /* check it's a supported varient */
1763 if (!prefix_ok(str1,RAP_WShareAdd_REQ)) {
1764 return False;
1765 }
1766 if (!check_share_info(uLevel,str2)) {
1767 return False;
1768 }
1769 if (uLevel != 2) {
1770 return False;
1771 }
1772
1773 pull_ascii_fstring(sharename,data);
1774 snum = find_service(sharename);
1775 if (snum >= 0) { /* already exists */
1776 res = ERRfilexists;
1777 goto error_exit;
1778 }
1779
1780 /* only support disk share adds */
1781 if (SVAL(data,14)!=STYPE_DISKTREE) {
1782 return False;
1783 }
1784
1785 offset = IVAL(data, 16);
1786 if (offset >= mdrcnt) {
1787 res = ERRinvalidparam;
1788 goto error_exit;
1789 }
1790
1791 pull_ascii_fstring(comment, offset? (data+offset) : "");
1792
1793 offset = IVAL(data, 26);
1794
1795 if (offset >= mdrcnt) {
1796 res = ERRinvalidparam;
1797 goto error_exit;
1798 }
1799
1800 pull_ascii_pstring(pathname, offset? (data+offset) : "");
1801
1802 string_replace(sharename, '"', ' ');
1803 string_replace(pathname, '"', ' ');
1804 string_replace(comment, '"', ' ');
1805
1806 cmdname = lp_add_share_cmd();
1807
1808 if (!cmdname || *cmdname == '\0') {
1809 return False;
1810 }
1811
1812 asprintf(&command, "%s \"%s\" \"%s\" \"%s\" \"%s\"",
1813 lp_add_share_cmd(), dyn_CONFIGFILE, sharename, pathname, comment);
1814
1815 if (command) {
1816 DEBUG(10,("api_RNetShareAdd: Running [%s]\n", command ));
1817
1818 if ((res = smbrun(command, NULL)) != 0) {
1819 DEBUG(1,("api_RNetShareAdd: Running [%s] returned (%d)\n", command, res ));
1820 SAFE_FREE(command);
1821 res = ERRnoaccess;
1822 goto error_exit;
1823 } else {
1824 SAFE_FREE(command);
1825 message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
1826 }
1827 } else {
1828 return False;
1829 }
1830
1831 *rparam_len = 6;
1832 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1833 if (!*rparam) {
1834 return False;
1835 }
1836 SSVAL(*rparam,0,NERR_Success);
1837 SSVAL(*rparam,2,0); /* converter word */
1838 SSVAL(*rparam,4,*rdata_len);
1839 *rdata_len = 0;
1840
1841 return True;
1842
1843 error_exit:
1844
1845 *rparam_len = 4;
1846 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1847 if (!*rparam) {
1848 return False;
1849 }
1850 *rdata_len = 0;
1851 SSVAL(*rparam,0,res);
1852 SSVAL(*rparam,2,0);
1853 return True;
1854}
1855
1856/****************************************************************************
1857 view list of groups available
1858 ****************************************************************************/
1859
1860static BOOL api_RNetGroupEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1861 int mdrcnt,int mprcnt,
1862 char **rdata,char **rparam,
1863 int *rdata_len,int *rparam_len)
1864{
1865 int i;
1866 int errflags=0;
1867 int resume_context, cli_buf_size;
1868 char *str1 = param+2;
1869 char *str2 = skip_string(str1,1);
1870 char *p = skip_string(str2,1);
1871
1872 struct pdb_search *search;
1873 struct samr_displayentry *entries;
1874
1875 int num_entries;
1876
1877 if (strcmp(str1,"WrLeh") != 0) {
1878 return False;
1879 }
1880
1881 /* parameters
1882 * W-> resume context (number of users to skip)
1883 * r -> return parameter pointer to receive buffer
1884 * L -> length of receive buffer
1885 * e -> return parameter number of entries
1886 * h -> return parameter total number of users
1887 */
1888
1889 if (strcmp("B21",str2) != 0) {
1890 return False;
1891 }
1892
1893 /* get list of domain groups SID_DOMAIN_GRP=2 */
1894 become_root();
1895 search = pdb_search_groups();
1896 unbecome_root();
1897
1898 if (search == NULL) {
1899 DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
1900 return False;
1901 }
1902
1903 resume_context = SVAL(p,0);
1904 cli_buf_size=SVAL(p+2,0);
1905 DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
1906 "%d\n", resume_context, cli_buf_size));
1907
1908 become_root();
1909 num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
1910 &entries);
1911 unbecome_root();
1912
1913 *rdata_len = cli_buf_size;
1914 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
1915 if (!*rdata) {
1916 return False;
1917 }
1918
1919 p = *rdata;
1920
1921 for(i=0; i<num_entries; i++) {
1922 fstring name;
1923 fstrcpy(name, entries[i].account_name);
1924 if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
1925 /* truncate the name at 21 chars. */
1926 memcpy(p, name, 21);
1927 DEBUG(10,("adding entry %d group %s\n", i, p));
1928 p += 21;
1929 p += 5; /* Both NT4 and W2k3SP1 do padding here.
1930 No idea why... */
1931 } else {
1932 /* set overflow error */
1933 DEBUG(3,("overflow on entry %d group %s\n", i, name));
1934 errflags=234;
1935 break;
1936 }
1937 }
1938
1939 pdb_search_destroy(search);
1940
1941 *rdata_len = PTR_DIFF(p,*rdata);
1942
1943 *rparam_len = 8;
1944 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1945 if (!*rparam) {
1946 return False;
1947 }
1948 SSVAL(*rparam, 0, errflags);
1949 SSVAL(*rparam, 2, 0); /* converter word */
1950 SSVAL(*rparam, 4, i); /* is this right?? */
1951 SSVAL(*rparam, 6, resume_context+num_entries); /* is this right?? */
1952
1953 return(True);
1954}
1955
1956/*******************************************************************
1957 Get groups that a user is a member of.
1958******************************************************************/
1959
1960static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
1961 int mdrcnt,int mprcnt,
1962 char **rdata,char **rparam,
1963 int *rdata_len,int *rparam_len)
1964{
1965 char *str1 = param+2;
1966 char *str2 = skip_string(str1,1);
1967 char *UserName = skip_string(str2,1);
1968 char *p = skip_string(UserName,1);
1969 int uLevel = SVAL(p,0);
1970 const char *level_string;
1971 int count=0;
1972 struct samu *sampw = NULL;
1973 BOOL ret = False;
1974 DOM_SID *sids;
1975 gid_t *gids;
1976 size_t num_groups;
1977 size_t i;
1978 NTSTATUS result;
1979 DOM_SID user_sid;
1980 enum lsa_SidType type;
1981 TALLOC_CTX *mem_ctx;
1982
1983 *rparam_len = 8;
1984 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
1985 if (!*rparam) {
1986 return False;
1987 }
1988
1989 /* check it's a supported varient */
1990
1991 if ( strcmp(str1,"zWrLeh") != 0 )
1992 return False;
1993
1994 switch( uLevel ) {
1995 case 0:
1996 level_string = "B21";
1997 break;
1998 default:
1999 return False;
2000 }
2001
2002 if (strcmp(level_string,str2) != 0)
2003 return False;
2004
2005 *rdata_len = mdrcnt + 1024;
2006 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2007 if (!*rdata) {
2008 return False;
2009 }
2010 SSVAL(*rparam,0,NERR_Success);
2011 SSVAL(*rparam,2,0); /* converter word */
2012
2013 p = *rdata;
2014
2015 mem_ctx = talloc_new(NULL);
2016 if (mem_ctx == NULL) {
2017 DEBUG(0, ("talloc_new failed\n"));
2018 return False;
2019 }
2020
2021 if ( !(sampw = samu_new(mem_ctx)) ) {
2022 DEBUG(0, ("samu_new() failed!\n"));
2023 TALLOC_FREE(mem_ctx);
2024 return False;
2025 }
2026
2027 /* Lookup the user information; This should only be one of
2028 our accounts (not remote domains) */
2029
2030 become_root(); /* ROOT BLOCK */
2031
2032 if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
2033 NULL, NULL, &user_sid, &type)) {
2034 DEBUG(10, ("lookup_name(%s) failed\n", UserName));
2035 goto done;
2036 }
2037
2038 if (type != SID_NAME_USER) {
2039 DEBUG(10, ("%s is a %s, not a user\n", UserName,
2040 sid_type_lookup(type)));
2041 goto done;
2042 }
2043
2044 if ( !pdb_getsampwsid(sampw, &user_sid) ) {
2045 DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
2046 sid_string_static(&user_sid), UserName));
2047 goto done;
2048 }
2049
2050 gids = NULL;
2051 sids = NULL;
2052 num_groups = 0;
2053
2054 result = pdb_enum_group_memberships(mem_ctx, sampw,
2055 &sids, &gids, &num_groups);
2056
2057 if (!NT_STATUS_IS_OK(result)) {
2058 DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
2059 UserName));
2060 goto done;
2061 }
2062
2063 for (i=0; i<num_groups; i++) {
2064
2065 const char *grp_name;
2066
2067 if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
2068 pstrcpy(p, grp_name);
2069 p += 21;
2070 count++;
2071 }
2072 }
2073
2074 *rdata_len = PTR_DIFF(p,*rdata);
2075
2076 SSVAL(*rparam,4,count); /* is this right?? */
2077 SSVAL(*rparam,6,count); /* is this right?? */
2078
2079 ret = True;
2080
2081done:
2082 unbecome_root(); /* END ROOT BLOCK */
2083
2084 TALLOC_FREE(mem_ctx);
2085
2086 return ret;
2087}
2088
2089/*******************************************************************
2090 Get all users.
2091******************************************************************/
2092
2093static BOOL api_RNetUserEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2094 int mdrcnt,int mprcnt,
2095 char **rdata,char **rparam,
2096 int *rdata_len,int *rparam_len)
2097{
2098 int count_sent=0;
2099 int num_users=0;
2100 int errflags=0;
2101 int i, resume_context, cli_buf_size;
2102 struct pdb_search *search;
2103 struct samr_displayentry *users;
2104
2105 char *str1 = param+2;
2106 char *str2 = skip_string(str1,1);
2107 char *p = skip_string(str2,1);
2108
2109 if (strcmp(str1,"WrLeh") != 0)
2110 return False;
2111 /* parameters
2112 * W-> resume context (number of users to skip)
2113 * r -> return parameter pointer to receive buffer
2114 * L -> length of receive buffer
2115 * e -> return parameter number of entries
2116 * h -> return parameter total number of users
2117 */
2118
2119 resume_context = SVAL(p,0);
2120 cli_buf_size=SVAL(p+2,0);
2121 DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n",
2122 resume_context, cli_buf_size));
2123
2124 *rparam_len = 8;
2125 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2126 if (!*rparam) {
2127 return False;
2128 }
2129
2130 /* check it's a supported varient */
2131 if (strcmp("B21",str2) != 0)
2132 return False;
2133
2134 *rdata_len = cli_buf_size;
2135 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2136 if (!*rdata) {
2137 return False;
2138 }
2139
2140 p = *rdata;
2141
2142 become_root();
2143 search = pdb_search_users(ACB_NORMAL);
2144 unbecome_root();
2145 if (search == NULL) {
2146 DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
2147 return False;
2148 }
2149
2150 become_root();
2151 num_users = pdb_search_entries(search, resume_context, 0xffffffff,
2152 &users);
2153 unbecome_root();
2154
2155 errflags=NERR_Success;
2156
2157 for (i=0; i<num_users; i++) {
2158 const char *name = users[i].account_name;
2159
2160 if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
2161 pstrcpy(p,name);
2162 DEBUG(10,("api_RNetUserEnum:adding entry %d username "
2163 "%s\n",count_sent,p));
2164 p += 21;
2165 count_sent++;
2166 } else {
2167 /* set overflow error */
2168 DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
2169 "username %s\n",count_sent,name));
2170 errflags=234;
2171 break;
2172 }
2173 }
2174
2175 pdb_search_destroy(search);
2176
2177 *rdata_len = PTR_DIFF(p,*rdata);
2178
2179 SSVAL(*rparam,0,errflags);
2180 SSVAL(*rparam,2,0); /* converter word */
2181 SSVAL(*rparam,4,count_sent); /* is this right?? */
2182 SSVAL(*rparam,6,num_users); /* is this right?? */
2183
2184 return True;
2185}
2186
2187/****************************************************************************
2188 Get the time of day info.
2189****************************************************************************/
2190
2191static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
2192 int mdrcnt,int mprcnt,
2193 char **rdata,char **rparam,
2194 int *rdata_len,int *rparam_len)
2195{
2196 struct tm *t;
2197 time_t unixdate = time(NULL);
2198 char *p;
2199
2200 *rparam_len = 4;
2201 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2202 if (!*rparam) {
2203 return False;
2204 }
2205
2206 *rdata_len = 21;
2207 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2208 if (!*rdata) {
2209 return False;
2210 }
2211
2212 SSVAL(*rparam,0,NERR_Success);
2213 SSVAL(*rparam,2,0); /* converter word */
2214
2215 p = *rdata;
2216
2217 srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at
2218 by NT in a "net time" operation,
2219 it seems to ignore the one below */
2220
2221 /* the client expects to get localtime, not GMT, in this bit
2222 (I think, this needs testing) */
2223 t = localtime(&unixdate);
2224 if (!t) {
2225 return False;
2226 }
2227
2228 SIVAL(p,4,0); /* msecs ? */
2229 SCVAL(p,8,t->tm_hour);
2230 SCVAL(p,9,t->tm_min);
2231 SCVAL(p,10,t->tm_sec);
2232 SCVAL(p,11,0); /* hundredths of seconds */
2233 SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */
2234 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
2235 SCVAL(p,16,t->tm_mday);
2236 SCVAL(p,17,t->tm_mon + 1);
2237 SSVAL(p,18,1900+t->tm_year);
2238 SCVAL(p,20,t->tm_wday);
2239
2240 return True;
2241}
2242
2243/****************************************************************************
2244 Set the user password.
2245*****************************************************************************/
2246
2247static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
2248 int mdrcnt,int mprcnt,
2249 char **rdata,char **rparam,
2250 int *rdata_len,int *rparam_len)
2251{
2252 char *p = skip_string(param+2,2);
2253 fstring user;
2254 fstring pass1,pass2;
2255
2256 pull_ascii_fstring(user,p);
2257
2258 p = skip_string(p,1);
2259
2260 memset(pass1,'\0',sizeof(pass1));
2261 memset(pass2,'\0',sizeof(pass2));
2262 memcpy(pass1,p,16);
2263 memcpy(pass2,p+16,16);
2264
2265 *rparam_len = 4;
2266 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2267 if (!*rparam) {
2268 return False;
2269 }
2270
2271 *rdata_len = 0;
2272
2273 SSVAL(*rparam,0,NERR_badpass);
2274 SSVAL(*rparam,2,0); /* converter word */
2275
2276 DEBUG(3,("Set password for <%s>\n",user));
2277
2278 /*
2279 * Attempt to verify the old password against smbpasswd entries
2280 * Win98 clients send old and new password in plaintext for this call.
2281 */
2282
2283 {
2284 auth_serversupplied_info *server_info = NULL;
2285 DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
2286
2287 if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
2288
2289 become_root();
2290 if (NT_STATUS_IS_OK(change_oem_password(server_info->sam_account, pass1, pass2, False, NULL))) {
2291 SSVAL(*rparam,0,NERR_Success);
2292 }
2293 unbecome_root();
2294
2295 TALLOC_FREE(server_info);
2296 }
2297 data_blob_clear_free(&password);
2298 }
2299
2300 /*
2301 * If the plaintext change failed, attempt
2302 * the old encrypted method. NT will generate this
2303 * after trying the samr method. Note that this
2304 * method is done as a last resort as this
2305 * password change method loses the NT password hash
2306 * and cannot change the UNIX password as no plaintext
2307 * is received.
2308 */
2309
2310 if(SVAL(*rparam,0) != NERR_Success) {
2311 struct samu *hnd = NULL;
2312
2313 if (check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &hnd)) {
2314 become_root();
2315 if (change_lanman_password(hnd,(uchar *)pass2)) {
2316 SSVAL(*rparam,0,NERR_Success);
2317 }
2318 unbecome_root();
2319 TALLOC_FREE(hnd);
2320 }
2321 }
2322
2323 memset((char *)pass1,'\0',sizeof(fstring));
2324 memset((char *)pass2,'\0',sizeof(fstring));
2325
2326 return(True);
2327}
2328
2329/****************************************************************************
2330 Set the user password (SamOEM version - gets plaintext).
2331****************************************************************************/
2332
2333static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
2334 int mdrcnt,int mprcnt,
2335 char **rdata,char **rparam,
2336 int *rdata_len,int *rparam_len)
2337{
2338 fstring user;
2339 char *p = param + 2;
2340 *rparam_len = 2;
2341 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2342 if (!*rparam) {
2343 return False;
2344 }
2345
2346 *rdata_len = 0;
2347
2348 SSVAL(*rparam,0,NERR_badpass);
2349
2350 /*
2351 * Check the parameter definition is correct.
2352 */
2353
2354 if(!strequal(param + 2, "zsT")) {
2355 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
2356 return False;
2357 }
2358 p = skip_string(p, 1);
2359
2360 if(!strequal(p, "B516B16")) {
2361 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
2362 return False;
2363 }
2364 p = skip_string(p,1);
2365 p += pull_ascii_fstring(user,p);
2366
2367 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
2368
2369 /*
2370 * Pass the user through the NT -> unix user mapping
2371 * function.
2372 */
2373
2374 (void)map_username(user);
2375
2376 if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
2377 SSVAL(*rparam,0,NERR_Success);
2378 }
2379
2380 return(True);
2381}
2382
2383/****************************************************************************
2384 delete a print job
2385 Form: <W> <>
2386 ****************************************************************************/
2387
2388static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
2389 int mdrcnt,int mprcnt,
2390 char **rdata,char **rparam,
2391 int *rdata_len,int *rparam_len)
2392{
2393 int function = SVAL(param,0);
2394 char *str1 = param+2;
2395 char *str2 = skip_string(str1,1);
2396 char *p = skip_string(str2,1);
2397 uint32 jobid;
2398 int snum;
2399 fstring sharename;
2400 int errcode;
2401 WERROR werr = WERR_OK;
2402
2403 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2404 return False;
2405
2406 /* check it's a supported varient */
2407 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
2408 return(False);
2409
2410 *rparam_len = 4;
2411 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2412 if (!*rparam) {
2413 return False;
2414 }
2415 *rdata_len = 0;
2416
2417 if (!print_job_exists(sharename, jobid)) {
2418 errcode = NERR_JobNotFound;
2419 goto out;
2420 }
2421
2422 snum = lp_servicenumber( sharename);
2423 if (snum == -1) {
2424 errcode = NERR_DestNotFound;
2425 goto out;
2426 }
2427
2428 errcode = NERR_notsupported;
2429
2430 switch (function) {
2431 case 81: /* delete */
2432 if (print_job_delete(&current_user, snum, jobid, &werr))
2433 errcode = NERR_Success;
2434 break;
2435 case 82: /* pause */
2436 if (print_job_pause(&current_user, snum, jobid, &werr))
2437 errcode = NERR_Success;
2438 break;
2439 case 83: /* resume */
2440 if (print_job_resume(&current_user, snum, jobid, &werr))
2441 errcode = NERR_Success;
2442 break;
2443 }
2444
2445 if (!W_ERROR_IS_OK(werr))
2446 errcode = W_ERROR_V(werr);
2447
2448 out:
2449 SSVAL(*rparam,0,errcode);
2450 SSVAL(*rparam,2,0); /* converter word */
2451
2452 return(True);
2453}
2454
2455/****************************************************************************
2456 Purge a print queue - or pause or resume it.
2457 ****************************************************************************/
2458
2459static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
2460 int mdrcnt,int mprcnt,
2461 char **rdata,char **rparam,
2462 int *rdata_len,int *rparam_len)
2463{
2464 int function = SVAL(param,0);
2465 char *str1 = param+2;
2466 char *str2 = skip_string(str1,1);
2467 char *QueueName = skip_string(str2,1);
2468 int errcode = NERR_notsupported;
2469 int snum;
2470 WERROR werr = WERR_OK;
2471
2472 /* check it's a supported varient */
2473 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
2474 return(False);
2475
2476 *rparam_len = 4;
2477 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2478 if (!*rparam) {
2479 return False;
2480 }
2481 *rdata_len = 0;
2482
2483 snum = print_queue_snum(QueueName);
2484
2485 if (snum == -1) {
2486 errcode = NERR_JobNotFound;
2487 goto out;
2488 }
2489
2490 switch (function) {
2491 case 74: /* Pause queue */
2492 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
2493 break;
2494 case 75: /* Resume queue */
2495 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
2496 break;
2497 case 103: /* Purge */
2498 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2499 break;
2500 }
2501
2502 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2503
2504 out:
2505 SSVAL(*rparam,0,errcode);
2506 SSVAL(*rparam,2,0); /* converter word */
2507
2508 return(True);
2509}
2510
2511/****************************************************************************
2512 set the property of a print job (undocumented?)
2513 ? function = 0xb -> set name of print job
2514 ? function = 0x6 -> move print job up/down
2515 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2516 or <WWsTP> <WB21BB16B10zWWzDDz>
2517****************************************************************************/
2518
2519static int check_printjob_info(struct pack_desc* desc,
2520 int uLevel, char* id)
2521{
2522 desc->subformat = NULL;
2523 switch( uLevel ) {
2524 case 0: desc->format = "W"; break;
2525 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2526 case 2: desc->format = "WWzWWDDzz"; break;
2527 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2528 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2529 default: return False;
2530 }
2531 if (strcmp(desc->format,id) != 0) return False;
2532 return True;
2533}
2534
2535static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2536 int mdrcnt,int mprcnt,
2537 char **rdata,char **rparam,
2538 int *rdata_len,int *rparam_len)
2539{
2540 struct pack_desc desc;
2541 char *str1 = param+2;
2542 char *str2 = skip_string(str1,1);
2543 char *p = skip_string(str2,1);
2544 uint32 jobid;
2545 fstring sharename;
2546 int uLevel = SVAL(p,2);
2547 int function = SVAL(p,4);
2548 int place, errcode;
2549
2550 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
2551 return False;
2552 *rparam_len = 4;
2553 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2554 if (!*rparam) {
2555 return False;
2556 }
2557
2558 if (!share_defined(sharename)) {
2559 DEBUG(0,("api_PrintJobInfo: sharen [%s] not defined\n",
2560 sharename));
2561 return False;
2562 }
2563
2564 *rdata_len = 0;
2565
2566 /* check it's a supported varient */
2567 if ((strcmp(str1,"WWsTP")) ||
2568 (!check_printjob_info(&desc,uLevel,str2)))
2569 return(False);
2570
2571 if (!print_job_exists(sharename, jobid)) {
2572 errcode=NERR_JobNotFound;
2573 goto out;
2574 }
2575
2576 errcode = NERR_notsupported;
2577
2578 switch (function) {
2579 case 0x6:
2580 /* change job place in the queue,
2581 data gives the new place */
2582 place = SVAL(data,0);
2583 if (print_job_set_place(sharename, jobid, place)) {
2584 errcode=NERR_Success;
2585 }
2586 break;
2587
2588 case 0xb:
2589 /* change print job name, data gives the name */
2590 if (print_job_set_name(sharename, jobid, data)) {
2591 errcode=NERR_Success;
2592 }
2593 break;
2594
2595 default:
2596 return False;
2597 }
2598
2599 out:
2600 SSVALS(*rparam,0,errcode);
2601 SSVAL(*rparam,2,0); /* converter word */
2602
2603 return(True);
2604}
2605
2606
2607/****************************************************************************
2608 Get info about the server.
2609****************************************************************************/
2610
2611static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2612 int mdrcnt,int mprcnt,
2613 char **rdata,char **rparam,
2614 int *rdata_len,int *rparam_len)
2615{
2616 char *str1 = param+2;
2617 char *str2 = skip_string(str1,1);
2618 char *p = skip_string(str2,1);
2619 int uLevel = SVAL(p,0);
2620 char *p2;
2621 int struct_len;
2622
2623 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2624
2625 /* check it's a supported varient */
2626 if (!prefix_ok(str1,"WrLh")) {
2627 return False;
2628 }
2629
2630 switch( uLevel ) {
2631 case 0:
2632 if (strcmp(str2,"B16") != 0) {
2633 return False;
2634 }
2635 struct_len = 16;
2636 break;
2637 case 1:
2638 if (strcmp(str2,"B16BBDz") != 0) {
2639 return False;
2640 }
2641 struct_len = 26;
2642 break;
2643 case 2:
2644 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) {
2645 return False;
2646 }
2647 struct_len = 134;
2648 break;
2649 case 3:
2650 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) {
2651 return False;
2652 }
2653 struct_len = 144;
2654 break;
2655 case 20:
2656 if (strcmp(str2,"DN") != 0) {
2657 return False;
2658 }
2659 struct_len = 6;
2660 break;
2661 case 50:
2662 if (strcmp(str2,"B16BBDzWWzzz") != 0) {
2663 return False;
2664 }
2665 struct_len = 42;
2666 break;
2667 default:
2668 return False;
2669 }
2670
2671 *rdata_len = mdrcnt;
2672 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2673 if (!*rdata) {
2674 return False;
2675 }
2676
2677 p = *rdata;
2678 p2 = p + struct_len;
2679 if (uLevel != 20) {
2680 srvstr_push(NULL, p,global_myname(),16,
2681 STR_ASCII|STR_UPPER|STR_TERMINATE);
2682 }
2683 p += 16;
2684 if (uLevel > 0) {
2685 struct srv_info_struct *servers=NULL;
2686 int i,count;
2687 pstring comment;
2688 uint32 servertype= lp_default_server_announce();
2689
2690 push_ascii(comment,lp_serverstring(), MAX_SERVER_STRING_LENGTH,STR_TERMINATE);
2691
2692 if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
2693 for (i=0;i<count;i++) {
2694 if (strequal(servers[i].name,global_myname())) {
2695 servertype = servers[i].type;
2696 push_ascii(comment,servers[i].comment,sizeof(pstring),STR_TERMINATE);
2697 }
2698 }
2699 }
2700
2701 SAFE_FREE(servers);
2702
2703 SCVAL(p,0,lp_major_announce_version());
2704 SCVAL(p,1,lp_minor_announce_version());
2705 SIVAL(p,2,servertype);
2706
2707 if (mdrcnt == struct_len) {
2708 SIVAL(p,6,0);
2709 } else {
2710 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2711 standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
2712 conn->connectpath, conn->gid,
2713 get_current_username(),
2714 current_user_info.domain,
2715 comment, sizeof(comment));
2716 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2717 p2 = skip_string(p2,1);
2718 }
2719 }
2720
2721 if (uLevel > 1) {
2722 return False; /* not yet implemented */
2723 }
2724
2725 *rdata_len = PTR_DIFF(p2,*rdata);
2726
2727 *rparam_len = 6;
2728 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2729 if (!*rparam) {
2730 return False;
2731 }
2732 SSVAL(*rparam,0,NERR_Success);
2733 SSVAL(*rparam,2,0); /* converter word */
2734 SSVAL(*rparam,4,*rdata_len);
2735
2736 return True;
2737}
2738
2739/****************************************************************************
2740 Get info about the server.
2741****************************************************************************/
2742
2743static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2744 int mdrcnt,int mprcnt,
2745 char **rdata,char **rparam,
2746 int *rdata_len,int *rparam_len)
2747{
2748 char *str1 = param+2;
2749 char *str2 = skip_string(str1,1);
2750 char *p = skip_string(str2,1);
2751 char *p2;
2752 int level = SVAL(p,0);
2753
2754 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2755
2756 *rparam_len = 6;
2757 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
2758 if (!*rparam) {
2759 return False;
2760 }
2761
2762 /* check it's a supported varient */
2763 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) {
2764 return False;
2765 }
2766
2767 *rdata_len = mdrcnt + 1024;
2768 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
2769 if (!*rdata) {
2770 return False;
2771 }
2772
2773 SSVAL(*rparam,0,NERR_Success);
2774 SSVAL(*rparam,2,0); /* converter word */
2775
2776 p = *rdata;
2777 p2 = p + 22;
2778
2779 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2780 pstrcpy(p2,get_local_machine_name());
2781 strupper_m(p2);
2782 p2 = skip_string(p2,1);
2783 p += 4;
2784
2785 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2786 pstrcpy(p2,current_user_info.smb_name);
2787 p2 = skip_string(p2,1);
2788 p += 4;
2789
2790 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2791 pstrcpy(p2,lp_workgroup());
2792 strupper_m(p2);
2793 p2 = skip_string(p2,1);
2794 p += 4;
2795
2796 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2797 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2798 p += 2;
2799
2800 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2801 pstrcpy(p2,lp_workgroup()); /* don't know. login domain?? */
2802 p2 = skip_string(p2,1);
2803 p += 4;
2804
2805 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2806 pstrcpy(p2,"");
2807 p2 = skip_string(p2,1);
2808 p += 4;
2809
2810 *rdata_len = PTR_DIFF(p2,*rdata);
2811
2812 SSVAL(*rparam,4,*rdata_len);
2813
2814 return True;
2815}
2816
2817/****************************************************************************
2818 get info about a user
2819
2820 struct user_info_11 {
2821 char usri11_name[21]; 0-20
2822 char usri11_pad; 21
2823 char *usri11_comment; 22-25
2824 char *usri11_usr_comment; 26-29
2825 unsigned short usri11_priv; 30-31
2826 unsigned long usri11_auth_flags; 32-35
2827 long usri11_password_age; 36-39
2828 char *usri11_homedir; 40-43
2829 char *usri11_parms; 44-47
2830 long usri11_last_logon; 48-51
2831 long usri11_last_logoff; 52-55
2832 unsigned short usri11_bad_pw_count; 56-57
2833 unsigned short usri11_num_logons; 58-59
2834 char *usri11_logon_server; 60-63
2835 unsigned short usri11_country_code; 64-65
2836 char *usri11_workstations; 66-69
2837 unsigned long usri11_max_storage; 70-73
2838 unsigned short usri11_units_per_week; 74-75
2839 unsigned char *usri11_logon_hours; 76-79
2840 unsigned short usri11_code_page; 80-81
2841 };
2842
2843where:
2844
2845 usri11_name specifies the user name for which information is retireved
2846
2847 usri11_pad aligns the next data structure element to a word boundary
2848
2849 usri11_comment is a null terminated ASCII comment
2850
2851 usri11_user_comment is a null terminated ASCII comment about the user
2852
2853 usri11_priv specifies the level of the privilege assigned to the user.
2854 The possible values are:
2855
2856Name Value Description
2857USER_PRIV_GUEST 0 Guest privilege
2858USER_PRIV_USER 1 User privilege
2859USER_PRV_ADMIN 2 Administrator privilege
2860
2861 usri11_auth_flags specifies the account operator privileges. The
2862 possible values are:
2863
2864Name Value Description
2865AF_OP_PRINT 0 Print operator
2866
2867
2868Leach, Naik [Page 28]
2869
2870
2871
2872
2873INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2874
2875
2876AF_OP_COMM 1 Communications operator
2877AF_OP_SERVER 2 Server operator
2878AF_OP_ACCOUNTS 3 Accounts operator
2879
2880
2881 usri11_password_age specifies how many seconds have elapsed since the
2882 password was last changed.
2883
2884 usri11_home_dir points to a null terminated ASCII string that contains
2885 the path name of the user's home directory.
2886
2887 usri11_parms points to a null terminated ASCII string that is set
2888 aside for use by applications.
2889
2890 usri11_last_logon specifies the time when the user last logged on.
2891 This value is stored as the number of seconds elapsed since
2892 00:00:00, January 1, 1970.
2893
2894 usri11_last_logoff specifies the time when the user last logged off.
2895 This value is stored as the number of seconds elapsed since
2896 00:00:00, January 1, 1970. A value of 0 means the last logoff
2897 time is unknown.
2898
2899 usri11_bad_pw_count specifies the number of incorrect passwords
2900 entered since the last successful logon.
2901
2902 usri11_log1_num_logons specifies the number of times this user has
2903 logged on. A value of -1 means the number of logons is unknown.
2904
2905 usri11_logon_server points to a null terminated ASCII string that
2906 contains the name of the server to which logon requests are sent.
2907 A null string indicates logon requests should be sent to the
2908 domain controller.
2909
2910 usri11_country_code specifies the country code for the user's language
2911 of choice.
2912
2913 usri11_workstations points to a null terminated ASCII string that
2914 contains the names of workstations the user may log on from.
2915 There may be up to 8 workstations, with the names separated by
2916 commas. A null strings indicates there are no restrictions.
2917
2918 usri11_max_storage specifies the maximum amount of disk space the user
2919 can occupy. A value of 0xffffffff indicates there are no
2920 restrictions.
2921
2922 usri11_units_per_week specifies the equal number of time units into
2923 which a week is divided. This value must be equal to 168.
2924
2925 usri11_logon_hours points to a 21 byte (168 bits) string that
2926 specifies the time during which the user can log on. Each bit
2927 represents one unique hour in a week. The first bit (bit 0, word
2928 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2929
2930
2931
2932Leach, Naik [Page 29]
2933
2934
2935
2936
2937INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2938
2939
2940 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2941 are no restrictions.
2942
2943 usri11_code_page specifies the code page for the user's language of
2944 choice
2945
2946All of the pointers in this data structure need to be treated
2947specially. The pointer is a 32 bit pointer. The higher 16 bits need
2948to be ignored. The converter word returned in the parameters section
2949needs to be subtracted from the lower 16 bits to calculate an offset
2950into the return buffer where this ASCII string resides.
2951
2952There is no auxiliary data in the response.
2953
2954 ****************************************************************************/
2955
2956#define usri11_name 0
2957#define usri11_pad 21
2958#define usri11_comment 22
2959#define usri11_usr_comment 26
2960#define usri11_full_name 30
2961#define usri11_priv 34
2962#define usri11_auth_flags 36
2963#define usri11_password_age 40
2964#define usri11_homedir 44
2965#define usri11_parms 48
2966#define usri11_last_logon 52
2967#define usri11_last_logoff 56
2968#define usri11_bad_pw_count 60
2969#define usri11_num_logons 62
2970#define usri11_logon_server 64
2971#define usri11_country_code 68
2972#define usri11_workstations 70
2973#define usri11_max_storage 74
2974#define usri11_units_per_week 78
2975#define usri11_logon_hours 80
2976#define usri11_code_page 84
2977#define usri11_end 86
2978
2979#define USER_PRIV_GUEST 0
2980#define USER_PRIV_USER 1
2981#define USER_PRIV_ADMIN 2
2982
2983#define AF_OP_PRINT 0
2984#define AF_OP_COMM 1
2985#define AF_OP_SERVER 2
2986#define AF_OP_ACCOUNTS 3
2987
2988
2989static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2990 int mdrcnt,int mprcnt,
2991 char **rdata,char **rparam,
2992 int *rdata_len,int *rparam_len)
2993{
2994 char *str1 = param+2;
2995 char *str2 = skip_string(str1,1);
2996 char *UserName = skip_string(str2,1);
2997 char *p = skip_string(UserName,1);
2998 int uLevel = SVAL(p,0);
2999 char *p2;
3000 const char *level_string;
3001
3002 /* get NIS home of a previously validated user - simeon */
3003 /* With share level security vuid will always be zero.
3004 Don't depend on vuser being non-null !!. JRA */
3005 user_struct *vuser = get_valid_user_struct(vuid);
3006 if(vuser != NULL) {
3007 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3008 vuser->user.unix_name));
3009 }
3010
3011 *rparam_len = 6;
3012 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3013 if (!*rparam) {
3014 return False;
3015 }
3016
3017 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
3018
3019 /* check it's a supported variant */
3020 if (strcmp(str1,"zWrLh") != 0) {
3021 return False;
3022 }
3023 switch( uLevel ) {
3024 case 0: level_string = "B21"; break;
3025 case 1: level_string = "B21BB16DWzzWz"; break;
3026 case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
3027 case 10: level_string = "B21Bzzz"; break;
3028 case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
3029 default: return False;
3030 }
3031
3032 if (strcmp(level_string,str2) != 0) {
3033 return False;
3034 }
3035
3036 *rdata_len = mdrcnt + 1024;
3037 *rdata = SMB_REALLOC_LIMIT(*rdata,*rdata_len);
3038 if (!*rdata) {
3039 return False;
3040 }
3041
3042 SSVAL(*rparam,0,NERR_Success);
3043 SSVAL(*rparam,2,0); /* converter word */
3044
3045 p = *rdata;
3046 p2 = p + usri11_end;
3047
3048 memset(p,0,21);
3049 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
3050
3051 if (uLevel > 0) {
3052 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
3053 *p2 = 0;
3054 }
3055
3056 if (uLevel >= 10) {
3057 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
3058 pstrcpy(p2,"Comment");
3059 p2 = skip_string(p2,1);
3060
3061 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
3062 pstrcpy(p2,"UserComment");
3063 p2 = skip_string(p2,1);
3064
3065 /* EEK! the cifsrap.txt doesn't have this in!!!! */
3066 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
3067 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3068 p2 = skip_string(p2,1);
3069 }
3070
3071 if (uLevel == 11) {
3072 /* modelled after NTAS 3.51 reply */
3073 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3074 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
3075 SIVALS(p,usri11_password_age,-1); /* password age */
3076 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
3077 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3078 p2 = skip_string(p2,1);
3079 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
3080 pstrcpy(p2,"");
3081 p2 = skip_string(p2,1);
3082 SIVAL(p,usri11_last_logon,0); /* last logon */
3083 SIVAL(p,usri11_last_logoff,0); /* last logoff */
3084 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
3085 SSVALS(p,usri11_num_logons,-1); /* num logons */
3086 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
3087 pstrcpy(p2,"\\\\*");
3088 p2 = skip_string(p2,1);
3089 SSVAL(p,usri11_country_code,0); /* country code */
3090
3091 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
3092 pstrcpy(p2,"");
3093 p2 = skip_string(p2,1);
3094
3095 SIVALS(p,usri11_max_storage,-1); /* max storage */
3096 SSVAL(p,usri11_units_per_week,168); /* units per week */
3097 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
3098
3099 /* a simple way to get logon hours at all times. */
3100 memset(p2,0xff,21);
3101 SCVAL(p2,21,0); /* fix zero termination */
3102 p2 = skip_string(p2,1);
3103
3104 SSVAL(p,usri11_code_page,0); /* code page */
3105 }
3106
3107 if (uLevel == 1 || uLevel == 2) {
3108 memset(p+22,' ',16); /* password */
3109 SIVALS(p,38,-1); /* password age */
3110 SSVAL(p,42,
3111 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3112 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
3113 pstrcpy(p2, vuser && vuser->homedir ? vuser->homedir : "");
3114 p2 = skip_string(p2,1);
3115 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
3116 *p2++ = 0;
3117 SSVAL(p,52,0); /* flags */
3118 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
3119 pstrcpy(p2,vuser && vuser->logon_script ? vuser->logon_script : "");
3120 p2 = skip_string(p2,1);
3121 if (uLevel == 2) {
3122 SIVAL(p,60,0); /* auth_flags */
3123 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
3124 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
3125 p2 = skip_string(p2,1);
3126 SIVAL(p,68,0); /* urs_comment */
3127 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
3128 pstrcpy(p2,"");
3129 p2 = skip_string(p2,1);
3130 SIVAL(p,76,0); /* workstations */
3131 SIVAL(p,80,0); /* last_logon */
3132 SIVAL(p,84,0); /* last_logoff */
3133 SIVALS(p,88,-1); /* acct_expires */
3134 SIVALS(p,92,-1); /* max_storage */
3135 SSVAL(p,96,168); /* units_per_week */
3136 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
3137 memset(p2,-1,21);
3138 p2 += 21;
3139 SSVALS(p,102,-1); /* bad_pw_count */
3140 SSVALS(p,104,-1); /* num_logons */
3141 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
3142 {
3143 pstring tmp;
3144 pstrcpy(tmp, "\\\\%L");
3145 standard_sub_basic("", "", tmp, sizeof(tmp));
3146 pstrcpy(p2, tmp);
3147 }
3148 p2 = skip_string(p2,1);
3149 SSVAL(p,110,49); /* country_code */
3150 SSVAL(p,112,860); /* code page */
3151 }
3152 }
3153
3154 *rdata_len = PTR_DIFF(p2,*rdata);
3155
3156 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
3157
3158 return(True);
3159}
3160
3161static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
3162 int mdrcnt,int mprcnt,
3163 char **rdata,char **rparam,
3164 int *rdata_len,int *rparam_len)
3165{
3166 char *str1 = param+2;
3167 char *str2 = skip_string(str1,1);
3168 char *p = skip_string(str2,1);
3169 int uLevel;
3170 struct pack_desc desc;
3171 char* name;
3172 /* With share level security vuid will always be zero.
3173 Don't depend on vuser being non-null !!. JRA */
3174 user_struct *vuser = get_valid_user_struct(vuid);
3175
3176 if(vuser != NULL) {
3177 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
3178 vuser->user.unix_name));
3179 }
3180
3181 uLevel = SVAL(p,0);
3182 name = p + 2;
3183
3184 memset((char *)&desc,'\0',sizeof(desc));
3185
3186 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
3187
3188 /* check it's a supported varient */
3189 if (strcmp(str1,"OOWb54WrLh") != 0) {
3190 return False;
3191 }
3192 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) {
3193 return False;
3194 }
3195 if (mdrcnt > 0) {
3196 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3197 if (!*rdata) {
3198 return False;
3199 }
3200 }
3201
3202 desc.base = *rdata;
3203 desc.buflen = mdrcnt;
3204 desc.subformat = NULL;
3205 desc.format = str2;
3206
3207 if (init_package(&desc,1,0)) {
3208 PACKI(&desc,"W",0); /* code */
3209 PACKS(&desc,"B21",name); /* eff. name */
3210 PACKS(&desc,"B",""); /* pad */
3211 PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
3212 PACKI(&desc,"D",0); /* auth flags XXX */
3213 PACKI(&desc,"W",0); /* num logons */
3214 PACKI(&desc,"W",0); /* bad pw count */
3215 PACKI(&desc,"D",0); /* last logon */
3216 PACKI(&desc,"D",-1); /* last logoff */
3217 PACKI(&desc,"D",-1); /* logoff time */
3218 PACKI(&desc,"D",-1); /* kickoff time */
3219 PACKI(&desc,"D",0); /* password age */
3220 PACKI(&desc,"D",0); /* password can change */
3221 PACKI(&desc,"D",-1); /* password must change */
3222
3223 {
3224 fstring mypath;
3225 fstrcpy(mypath,"\\\\");
3226 fstrcat(mypath,get_local_machine_name());
3227 strupper_m(mypath);
3228 PACKS(&desc,"z",mypath); /* computer */
3229 }
3230
3231 PACKS(&desc,"z",lp_workgroup());/* domain */
3232 PACKS(&desc,"z", vuser && vuser->logon_script ? vuser->logon_script :""); /* script path */
3233 PACKI(&desc,"D",0x00000000); /* reserved */
3234 }
3235
3236 *rdata_len = desc.usedlen;
3237 *rparam_len = 6;
3238 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3239 if (!*rparam) {
3240 return False;
3241 }
3242 SSVALS(*rparam,0,desc.errcode);
3243 SSVAL(*rparam,2,0);
3244 SSVAL(*rparam,4,desc.neededlen);
3245
3246 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
3247
3248 return True;
3249}
3250
3251/****************************************************************************
3252 api_WAccessGetUserPerms
3253****************************************************************************/
3254
3255static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
3256 int mdrcnt,int mprcnt,
3257 char **rdata,char **rparam,
3258 int *rdata_len,int *rparam_len)
3259{
3260 char *str1 = param+2;
3261 char *str2 = skip_string(str1,1);
3262 char *user = skip_string(str2,1);
3263 char *resource = skip_string(user,1);
3264
3265 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
3266
3267 /* check it's a supported varient */
3268 if (strcmp(str1,"zzh") != 0) {
3269 return False;
3270 }
3271 if (strcmp(str2,"") != 0) {
3272 return False;
3273 }
3274
3275 *rparam_len = 6;
3276 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3277 if (!*rparam) {
3278 return False;
3279 }
3280 SSVALS(*rparam,0,0); /* errorcode */
3281 SSVAL(*rparam,2,0); /* converter word */
3282 SSVAL(*rparam,4,0x7f); /* permission flags */
3283
3284 return True;
3285}
3286
3287/****************************************************************************
3288 api_WPrintJobEnumerate
3289 ****************************************************************************/
3290
3291static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
3292 int mdrcnt,int mprcnt,
3293 char **rdata,char **rparam,
3294 int *rdata_len,int *rparam_len)
3295{
3296 char *str1 = param+2;
3297 char *str2 = skip_string(str1,1);
3298 char *p = skip_string(str2,1);
3299 int uLevel;
3300 int count;
3301 int i;
3302 int snum;
3303 fstring sharename;
3304 uint32 jobid;
3305 struct pack_desc desc;
3306 print_queue_struct *queue=NULL;
3307 print_status_struct status;
3308 char *tmpdata=NULL;
3309
3310 uLevel = SVAL(p,2);
3311
3312 memset((char *)&desc,'\0',sizeof(desc));
3313 memset((char *)&status,'\0',sizeof(status));
3314
3315 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
3316
3317 /* check it's a supported varient */
3318 if (strcmp(str1,"WWrLh") != 0) {
3319 return False;
3320 }
3321 if (!check_printjob_info(&desc,uLevel,str2)) {
3322 return False;
3323 }
3324
3325 if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) {
3326 return False;
3327 }
3328
3329 snum = lp_servicenumber( sharename);
3330 if (snum < 0 || !VALID_SNUM(snum)) {
3331 return(False);
3332 }
3333
3334 count = print_queue_status(snum,&queue,&status);
3335 for (i = 0; i < count; i++) {
3336 if (queue[i].job == jobid) {
3337 break;
3338 }
3339 }
3340
3341 if (mdrcnt > 0) {
3342 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3343 if (!*rdata) {
3344 return False;
3345 }
3346 desc.base = *rdata;
3347 desc.buflen = mdrcnt;
3348 } else {
3349 /*
3350 * Don't return data but need to get correct length
3351 * init_package will return wrong size if buflen=0
3352 */
3353 desc.buflen = getlen(desc.format);
3354 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3355 }
3356
3357 if (init_package(&desc,1,0)) {
3358 if (i < count) {
3359 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3360 *rdata_len = desc.usedlen;
3361 } else {
3362 desc.errcode = NERR_JobNotFound;
3363 *rdata_len = 0;
3364 }
3365 }
3366
3367 *rparam_len = 6;
3368 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3369 if (!*rparam) {
3370 return False;
3371 }
3372 SSVALS(*rparam,0,desc.errcode);
3373 SSVAL(*rparam,2,0);
3374 SSVAL(*rparam,4,desc.neededlen);
3375
3376 SAFE_FREE(queue);
3377 SAFE_FREE(tmpdata);
3378
3379 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
3380
3381 return True;
3382}
3383
3384static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
3385 int mdrcnt,int mprcnt,
3386 char **rdata,char **rparam,
3387 int *rdata_len,int *rparam_len)
3388{
3389 char *str1 = param+2;
3390 char *str2 = skip_string(str1,1);
3391 char *p = skip_string(str2,1);
3392 char* name = p;
3393 int uLevel;
3394 int count;
3395 int i, succnt=0;
3396 int snum;
3397 struct pack_desc desc;
3398 print_queue_struct *queue=NULL;
3399 print_status_struct status;
3400
3401 memset((char *)&desc,'\0',sizeof(desc));
3402 memset((char *)&status,'\0',sizeof(status));
3403
3404 p = skip_string(p,1);
3405 uLevel = SVAL(p,0);
3406
3407 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
3408
3409 /* check it's a supported variant */
3410 if (strcmp(str1,"zWrLeh") != 0) {
3411 return False;
3412 }
3413
3414 if (uLevel > 2) {
3415 return False; /* defined only for uLevel 0,1,2 */
3416 }
3417
3418 if (!check_printjob_info(&desc,uLevel,str2)) {
3419 return False;
3420 }
3421
3422 snum = find_service(name);
3423 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3424 return False;
3425 }
3426
3427 count = print_queue_status(snum,&queue,&status);
3428 if (mdrcnt > 0) {
3429 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3430 if (!*rdata) {
3431 return False;
3432 }
3433 }
3434 desc.base = *rdata;
3435 desc.buflen = mdrcnt;
3436
3437 if (init_package(&desc,count,0)) {
3438 succnt = 0;
3439 for (i = 0; i < count; i++) {
3440 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
3441 if (desc.errcode == NERR_Success) {
3442 succnt = i+1;
3443 }
3444 }
3445 }
3446
3447 *rdata_len = desc.usedlen;
3448
3449 *rparam_len = 8;
3450 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3451 if (!*rparam) {
3452 return False;
3453 }
3454 SSVALS(*rparam,0,desc.errcode);
3455 SSVAL(*rparam,2,0);
3456 SSVAL(*rparam,4,succnt);
3457 SSVAL(*rparam,6,count);
3458
3459 SAFE_FREE(queue);
3460
3461 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
3462
3463 return True;
3464}
3465
3466static int check_printdest_info(struct pack_desc* desc,
3467 int uLevel, char* id)
3468{
3469 desc->subformat = NULL;
3470 switch( uLevel ) {
3471 case 0:
3472 desc->format = "B9";
3473 break;
3474 case 1:
3475 desc->format = "B9B21WWzW";
3476 break;
3477 case 2:
3478 desc->format = "z";
3479 break;
3480 case 3:
3481 desc->format = "zzzWWzzzWW";
3482 break;
3483 default:
3484 return False;
3485 }
3486 if (strcmp(desc->format,id) != 0) {
3487 return False;
3488 }
3489 return True;
3490}
3491
3492static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
3493 struct pack_desc* desc)
3494{
3495 char buf[100];
3496
3497 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
3498 buf[sizeof(buf)-1] = 0;
3499 strupper_m(buf);
3500
3501 if (uLevel <= 1) {
3502 PACKS(desc,"B9",buf); /* szName */
3503 if (uLevel == 1) {
3504 PACKS(desc,"B21",""); /* szUserName */
3505 PACKI(desc,"W",0); /* uJobId */
3506 PACKI(desc,"W",0); /* fsStatus */
3507 PACKS(desc,"z",""); /* pszStatus */
3508 PACKI(desc,"W",0); /* time */
3509 }
3510 }
3511
3512 if (uLevel == 2 || uLevel == 3) {
3513 PACKS(desc,"z",buf); /* pszPrinterName */
3514 if (uLevel == 3) {
3515 PACKS(desc,"z",""); /* pszUserName */
3516 PACKS(desc,"z",""); /* pszLogAddr */
3517 PACKI(desc,"W",0); /* uJobId */
3518 PACKI(desc,"W",0); /* fsStatus */
3519 PACKS(desc,"z",""); /* pszStatus */
3520 PACKS(desc,"z",""); /* pszComment */
3521 PACKS(desc,"z","NULL"); /* pszDrivers */
3522 PACKI(desc,"W",0); /* time */
3523 PACKI(desc,"W",0); /* pad1 */
3524 }
3525 }
3526}
3527
3528static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
3529 int mdrcnt,int mprcnt,
3530 char **rdata,char **rparam,
3531 int *rdata_len,int *rparam_len)
3532{
3533 char *str1 = param+2;
3534 char *str2 = skip_string(str1,1);
3535 char *p = skip_string(str2,1);
3536 char* PrinterName = p;
3537 int uLevel;
3538 struct pack_desc desc;
3539 int snum;
3540 char *tmpdata=NULL;
3541
3542 memset((char *)&desc,'\0',sizeof(desc));
3543
3544 p = skip_string(p,1);
3545 uLevel = SVAL(p,0);
3546
3547 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
3548
3549 /* check it's a supported varient */
3550 if (strcmp(str1,"zWrLh") != 0) {
3551 return False;
3552 }
3553 if (!check_printdest_info(&desc,uLevel,str2)) {
3554 return False;
3555 }
3556
3557 snum = find_service(PrinterName);
3558 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
3559 *rdata_len = 0;
3560 desc.errcode = NERR_DestNotFound;
3561 desc.neededlen = 0;
3562 } else {
3563 if (mdrcnt > 0) {
3564 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3565 if (!*rdata) {
3566 return False;
3567 }
3568 desc.base = *rdata;
3569 desc.buflen = mdrcnt;
3570 } else {
3571 /*
3572 * Don't return data but need to get correct length
3573 * init_package will return wrong size if buflen=0
3574 */
3575 desc.buflen = getlen(desc.format);
3576 desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen );
3577 }
3578 if (init_package(&desc,1,0)) {
3579 fill_printdest_info(conn,snum,uLevel,&desc);
3580 }
3581 *rdata_len = desc.usedlen;
3582 }
3583
3584 *rparam_len = 6;
3585 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3586 if (!*rparam) {
3587 return False;
3588 }
3589 SSVALS(*rparam,0,desc.errcode);
3590 SSVAL(*rparam,2,0);
3591 SSVAL(*rparam,4,desc.neededlen);
3592
3593 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3594 SAFE_FREE(tmpdata);
3595
3596 return True;
3597}
3598
3599static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3600 int mdrcnt,int mprcnt,
3601 char **rdata,char **rparam,
3602 int *rdata_len,int *rparam_len)
3603{
3604 char *str1 = param+2;
3605 char *str2 = skip_string(str1,1);
3606 char *p = skip_string(str2,1);
3607 int uLevel;
3608 int queuecnt;
3609 int i, n, succnt=0;
3610 struct pack_desc desc;
3611 int services = lp_numservices();
3612
3613 memset((char *)&desc,'\0',sizeof(desc));
3614
3615 uLevel = SVAL(p,0);
3616
3617 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3618
3619 /* check it's a supported varient */
3620 if (strcmp(str1,"WrLeh") != 0) {
3621 return False;
3622 }
3623 if (!check_printdest_info(&desc,uLevel,str2)) {
3624 return False;
3625 }
3626
3627 queuecnt = 0;
3628 for (i = 0; i < services; i++) {
3629 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3630 queuecnt++;
3631 }
3632 }
3633
3634 if (mdrcnt > 0) {
3635 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3636 if (!*rdata) {
3637 return False;
3638 }
3639 }
3640
3641 desc.base = *rdata;
3642 desc.buflen = mdrcnt;
3643 if (init_package(&desc,queuecnt,0)) {
3644 succnt = 0;
3645 n = 0;
3646 for (i = 0; i < services; i++) {
3647 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3648 fill_printdest_info(conn,i,uLevel,&desc);
3649 n++;
3650 if (desc.errcode == NERR_Success) {
3651 succnt = n;
3652 }
3653 }
3654 }
3655 }
3656
3657 *rdata_len = desc.usedlen;
3658
3659 *rparam_len = 8;
3660 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3661 if (!*rparam) {
3662 return False;
3663 }
3664 SSVALS(*rparam,0,desc.errcode);
3665 SSVAL(*rparam,2,0);
3666 SSVAL(*rparam,4,succnt);
3667 SSVAL(*rparam,6,queuecnt);
3668
3669 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3670
3671 return True;
3672}
3673
3674static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3675 int mdrcnt,int mprcnt,
3676 char **rdata,char **rparam,
3677 int *rdata_len,int *rparam_len)
3678{
3679 char *str1 = param+2;
3680 char *str2 = skip_string(str1,1);
3681 char *p = skip_string(str2,1);
3682 int uLevel;
3683 int succnt;
3684 struct pack_desc desc;
3685
3686 memset((char *)&desc,'\0',sizeof(desc));
3687
3688 uLevel = SVAL(p,0);
3689
3690 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3691
3692 /* check it's a supported varient */
3693 if (strcmp(str1,"WrLeh") != 0) {
3694 return False;
3695 }
3696 if (uLevel != 0 || strcmp(str2,"B41") != 0) {
3697 return False;
3698 }
3699
3700 if (mdrcnt > 0) {
3701 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3702 if (!*rdata) {
3703 return False;
3704 }
3705 }
3706 desc.base = *rdata;
3707 desc.buflen = mdrcnt;
3708 if (init_package(&desc,1,0)) {
3709 PACKS(&desc,"B41","NULL");
3710 }
3711
3712 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3713
3714 *rdata_len = desc.usedlen;
3715
3716 *rparam_len = 8;
3717 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3718 if (!*rparam) {
3719 return False;
3720 }
3721 SSVALS(*rparam,0,desc.errcode);
3722 SSVAL(*rparam,2,0);
3723 SSVAL(*rparam,4,succnt);
3724 SSVAL(*rparam,6,1);
3725
3726 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3727
3728 return True;
3729}
3730
3731static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3732 int mdrcnt,int mprcnt,
3733 char **rdata,char **rparam,
3734 int *rdata_len,int *rparam_len)
3735{
3736 char *str1 = param+2;
3737 char *str2 = skip_string(str1,1);
3738 char *p = skip_string(str2,1);
3739 int uLevel;
3740 int succnt;
3741 struct pack_desc desc;
3742
3743 memset((char *)&desc,'\0',sizeof(desc));
3744
3745 uLevel = SVAL(p,0);
3746
3747 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3748
3749 /* check it's a supported varient */
3750 if (strcmp(str1,"WrLeh") != 0) {
3751 return False;
3752 }
3753 if (uLevel != 0 || strcmp(str2,"B13") != 0) {
3754 return False;
3755 }
3756
3757 if (mdrcnt > 0) {
3758 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3759 if (!*rdata) {
3760 return False;
3761 }
3762 }
3763 desc.base = *rdata;
3764 desc.buflen = mdrcnt;
3765 desc.format = str2;
3766 if (init_package(&desc,1,0)) {
3767 PACKS(&desc,"B13","lpd");
3768 }
3769
3770 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3771
3772 *rdata_len = desc.usedlen;
3773
3774 *rparam_len = 8;
3775 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3776 if (!*rparam) {
3777 return False;
3778 }
3779 SSVALS(*rparam,0,desc.errcode);
3780 SSVAL(*rparam,2,0);
3781 SSVAL(*rparam,4,succnt);
3782 SSVAL(*rparam,6,1);
3783
3784 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3785
3786 return True;
3787}
3788
3789static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3790 int mdrcnt,int mprcnt,
3791 char **rdata,char **rparam,
3792 int *rdata_len,int *rparam_len)
3793{
3794 char *str1 = param+2;
3795 char *str2 = skip_string(str1,1);
3796 char *p = skip_string(str2,1);
3797 int uLevel;
3798 int succnt;
3799 struct pack_desc desc;
3800
3801 memset((char *)&desc,'\0',sizeof(desc));
3802
3803 uLevel = SVAL(p,0);
3804
3805 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3806
3807 /* check it's a supported varient */
3808 if (strcmp(str1,"WrLeh") != 0) {
3809 return False;
3810 }
3811 if (uLevel != 0 || strcmp(str2,"B9") != 0) {
3812 return False;
3813 }
3814
3815 if (mdrcnt > 0) {
3816 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3817 if (!*rdata) {
3818 return False;
3819 }
3820 }
3821 memset((char *)&desc,'\0',sizeof(desc));
3822 desc.base = *rdata;
3823 desc.buflen = mdrcnt;
3824 desc.format = str2;
3825 if (init_package(&desc,1,0)) {
3826 PACKS(&desc,"B13","lp0");
3827 }
3828
3829 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3830
3831 *rdata_len = desc.usedlen;
3832
3833 *rparam_len = 8;
3834 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3835 if (!*rparam) {
3836 return False;
3837 }
3838 SSVALS(*rparam,0,desc.errcode);
3839 SSVAL(*rparam,2,0);
3840 SSVAL(*rparam,4,succnt);
3841 SSVAL(*rparam,6,1);
3842
3843 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3844
3845 return True;
3846}
3847
3848
3849/****************************************************************************
3850 List open sessions
3851 ****************************************************************************/
3852static BOOL api_RNetSessionEnum(connection_struct *conn,uint16 vuid, char *param, char *data,
3853 int mdrcnt,int mprcnt,
3854 char **rdata,char **rparam,
3855 int *rdata_len,int *rparam_len)
3856
3857{
3858 char *str1 = param+2;
3859 char *str2 = skip_string(str1,1);
3860 char *p = skip_string(str2,1);
3861 int uLevel;
3862 struct pack_desc desc;
3863 struct sessionid *session_list;
3864 int i, num_sessions;
3865
3866 memset((char *)&desc,'\0',sizeof(desc));
3867
3868 uLevel = SVAL(p,0);
3869
3870 DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel));
3871 DEBUG(7,("RNetSessionEnum req string=%s\n",str1));
3872 DEBUG(7,("RNetSessionEnum ret string=%s\n",str2));
3873
3874 /* check it's a supported varient */
3875 if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) {
3876 return False;
3877 }
3878 if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) {
3879 return False;
3880 }
3881
3882 num_sessions = list_sessions(&session_list);
3883
3884 if (mdrcnt > 0) {
3885 *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
3886 if (!*rdata) {
3887 return False;
3888 }
3889 }
3890 memset((char *)&desc,'\0',sizeof(desc));
3891 desc.base = *rdata;
3892 desc.buflen = mdrcnt;
3893 desc.format = str2;
3894 if (!init_package(&desc,num_sessions,0)) {
3895 return False;
3896 }
3897
3898 for(i=0; i<num_sessions; i++) {
3899 PACKS(&desc, "z", session_list[i].remote_machine);
3900 PACKS(&desc, "z", session_list[i].username);
3901 PACKI(&desc, "W", 1); /* num conns */
3902 PACKI(&desc, "W", 0); /* num opens */
3903 PACKI(&desc, "W", 1); /* num users */
3904 PACKI(&desc, "D", 0); /* session time */
3905 PACKI(&desc, "D", 0); /* idle time */
3906 PACKI(&desc, "D", 0); /* flags */
3907 PACKS(&desc, "z", "Unknown Client"); /* client type string */
3908 }
3909
3910 *rdata_len = desc.usedlen;
3911
3912 *rparam_len = 8;
3913 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3914 if (!*rparam) {
3915 return False;
3916 }
3917 SSVALS(*rparam,0,desc.errcode);
3918 SSVAL(*rparam,2,0); /* converter */
3919 SSVAL(*rparam,4,num_sessions); /* count */
3920
3921 DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode));
3922
3923 return True;
3924}
3925
3926
3927/****************************************************************************
3928 The buffer was too small.
3929 ****************************************************************************/
3930
3931static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param, char *data,
3932 int mdrcnt, int mprcnt,
3933 char **rdata, char **rparam,
3934 int *rdata_len, int *rparam_len)
3935{
3936 *rparam_len = MIN(*rparam_len,mprcnt);
3937 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3938 if (!*rparam) {
3939 return False;
3940 }
3941
3942 *rdata_len = 0;
3943
3944 SSVAL(*rparam,0,NERR_BufTooSmall);
3945
3946 DEBUG(3,("Supplied buffer too small in API command\n"));
3947
3948 return True;
3949}
3950
3951/****************************************************************************
3952 The request is not supported.
3953 ****************************************************************************/
3954
3955static BOOL api_Unsupported(connection_struct *conn, uint16 vuid, char *param, char *data,
3956 int mdrcnt, int mprcnt,
3957 char **rdata, char **rparam,
3958 int *rdata_len, int *rparam_len)
3959{
3960 *rparam_len = 4;
3961 *rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
3962 if (!*rparam) {
3963 return False;
3964 }
3965
3966 *rdata_len = 0;
3967
3968 SSVAL(*rparam,0,NERR_notsupported);
3969 SSVAL(*rparam,2,0); /* converter word */
3970
3971 DEBUG(3,("Unsupported API command\n"));
3972
3973 return True;
3974}
3975
3976static const struct {
3977 const char *name;
3978 int id;
3979 BOOL (*fn)(connection_struct *,uint16,char *,char *,
3980 int,int,char **,char **,int *,int *);
3981 BOOL auth_user; /* Deny anonymous access? */
3982} api_commands[] = {
3983 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum, True},
3984 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo},
3985 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd},
3986 {"RNetSessionEnum", RAP_WsessionEnum, api_RNetSessionEnum, True},
3987 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo},
3988 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum, True},
3989 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers, True},
3990 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum, True},
3991 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo},
3992 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups},
3993 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo},
3994 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum, True},
3995 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo},
3996 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl},
3997 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl},
3998 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate},
3999 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo},
4000 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel},
4001 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel},
4002 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel},
4003 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum},
4004 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo},
4005 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD},
4006 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl},
4007 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum}, /* anon OK */
4008 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
4009 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword},
4010 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon},
4011 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo},
4012 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum},
4013 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum},
4014 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum},
4015 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword}, /* anon OK */
4016 {NULL, -1, api_Unsupported}
4017 /* The following RAP calls are not implemented by Samba:
4018
4019 RAP_WFileEnum2 - anon not OK
4020 */
4021};
4022
4023
4024/****************************************************************************
4025 Handle remote api calls
4026 ****************************************************************************/
4027
4028int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
4029 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
4030{
4031 int api_command;
4032 char *rdata = NULL;
4033 char *rparam = NULL;
4034 int rdata_len = 0;
4035 int rparam_len = 0;
4036 BOOL reply=False;
4037 int i;
4038
4039 if (!params) {
4040 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
4041 return 0;
4042 }
4043
4044 api_command = SVAL(params,0);
4045
4046 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
4047 api_command,
4048 params+2,
4049 skip_string(params+2,1),
4050 tdscnt,tpscnt,mdrcnt,mprcnt));
4051
4052 for (i=0;api_commands[i].name;i++) {
4053 if (api_commands[i].id == api_command && api_commands[i].fn) {
4054 DEBUG(3,("Doing %s\n",api_commands[i].name));
4055 break;
4056 }
4057 }
4058
4059 /* Check whether this api call can be done anonymously */
4060
4061 if (api_commands[i].auth_user && lp_restrict_anonymous()) {
4062 user_struct *user = get_valid_user_struct(vuid);
4063
4064 if (!user || user->guest) {
4065 return ERROR_NT(NT_STATUS_ACCESS_DENIED);
4066 }
4067 }
4068
4069 rdata = (char *)SMB_MALLOC(1024);
4070 if (rdata) {
4071 memset(rdata,'\0',1024);
4072 }
4073
4074 rparam = (char *)SMB_MALLOC(1024);
4075 if (rparam) {
4076 memset(rparam,'\0',1024);
4077 }
4078
4079 if(!rdata || !rparam) {
4080 DEBUG(0,("api_reply: malloc fail !\n"));
4081 SAFE_FREE(rdata);
4082 SAFE_FREE(rparam);
4083 return -1;
4084 }
4085
4086 reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
4087 &rdata,&rparam,&rdata_len,&rparam_len);
4088
4089
4090 if (rdata_len > mdrcnt || rparam_len > mprcnt) {
4091 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
4092 &rdata,&rparam,&rdata_len,&rparam_len);
4093 }
4094
4095 /* if we get False back then it's actually unsupported */
4096 if (!reply) {
4097 reply = api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
4098 &rdata,&rparam,&rdata_len,&rparam_len);
4099 }
4100
4101 /* If api_Unsupported returns false we can't return anything. */
4102 if (reply) {
4103 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
4104 }
4105
4106 SAFE_FREE(rdata);
4107 SAFE_FREE(rparam);
4108 return -1;
4109}
Note: See TracBrowser for help on using the repository browser.