Fix double free of SAM_ACCOUNT - make it clear when malloced
[Samba.git] / source / smbd / lanman.c
blob376cae81c04646002dc29555f5060ca0cc923868
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Inter-process communication and named pipe handling
5 Copyright (C) Andrew Tridgell 1992-1998
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 This file handles the named pipe and mailslot calls
26 in the SMBtrans protocol
29 #include "includes.h"
31 #ifdef CHECK_TYPES
32 #undef CHECK_TYPES
33 #endif
34 #define CHECK_TYPES 0
36 extern fstring local_machine;
37 extern pstring global_myname;
38 extern fstring global_myworkgroup;
40 #define NERR_Success 0
41 #define NERR_badpass 86
42 #define NERR_notsupported 50
44 #define NERR_BASE (2100)
45 #define NERR_BufTooSmall (NERR_BASE+23)
46 #define NERR_JobNotFound (NERR_BASE+51)
47 #define NERR_DestNotFound (NERR_BASE+52)
49 #define ACCESS_READ 0x01
50 #define ACCESS_WRITE 0x02
51 #define ACCESS_CREATE 0x04
53 #define SHPWLEN 8 /* share password length */
55 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
56 int mdrcnt,int mprcnt,
57 char **rdata,char **rparam,
58 int *rdata_len,int *rparam_len);
59 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
60 int mdrcnt,int mprcnt,
61 char **rdata,char **rparam,
62 int *rdata_len,int *rparam_len);
65 static int CopyExpanded(connection_struct *conn,
66 int snum, char** dst, char* src, int* n)
68 pstring buf;
69 int l;
71 if (!src || !dst || !n || !(*dst)) return(0);
73 StrnCpy(buf,src,sizeof(buf)/2);
74 pstring_sub(buf,"%S",lp_servicename(snum));
75 standard_sub_conn(conn,buf,sizeof(buf));
76 StrnCpy(*dst,buf,*n-1);
77 l = strlen(*dst) + 1;
78 (*dst) += l;
79 (*n) -= l;
80 return l;
83 static int CopyAndAdvance(char** dst, char* src, int* n)
85 int l;
86 if (!src || !dst || !n || !(*dst)) return(0);
87 StrnCpy(*dst,src,*n-1);
88 l = strlen(*dst) + 1;
89 (*dst) += l;
90 (*n) -= l;
91 return l;
94 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
96 pstring buf;
97 if (!s) return(0);
98 StrnCpy(buf,s,sizeof(buf)/2);
99 pstring_sub(buf,"%S",lp_servicename(snum));
100 standard_sub_conn(conn,buf,sizeof(buf));
101 return strlen(buf) + 1;
104 static char* Expand(connection_struct *conn, int snum, char* s)
106 static pstring buf;
107 if (!s) return(NULL);
108 StrnCpy(buf,s,sizeof(buf)/2);
109 pstring_sub(buf,"%S",lp_servicename(snum));
110 standard_sub_conn(conn,buf,sizeof(buf));
111 return &buf[0];
114 /*******************************************************************
115 check a API string for validity when we only need to check the prefix
116 ******************************************************************/
117 static BOOL prefix_ok(char *str,char *prefix)
119 return(strncmp(str,prefix,strlen(prefix)) == 0);
122 struct pack_desc {
123 char* format; /* formatstring for structure */
124 char* subformat; /* subformat for structure */
125 char* base; /* baseaddress of buffer */
126 int buflen; /* remaining size for fixed part; on init: length of base */
127 int subcount; /* count of substructures */
128 char* structbuf; /* pointer into buffer for remaining fixed part */
129 int stringlen; /* remaining size for variable part */
130 char* stringbuf; /* pointer into buffer for remaining variable part */
131 int neededlen; /* total needed size */
132 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
133 char* curpos; /* current position; pointer into format or subformat */
134 int errcode;
137 static int get_counter(char** p)
139 int i, n;
140 if (!p || !(*p)) return(1);
141 if (!isdigit((int)**p)) return 1;
142 for (n = 0;;) {
143 i = **p;
144 if (isdigit(i))
145 n = 10 * n + (i - '0');
146 else
147 return n;
148 (*p)++;
152 static int getlen(char* p)
154 int n = 0;
155 if (!p) return(0);
156 while (*p) {
157 switch( *p++ ) {
158 case 'W': /* word (2 byte) */
159 n += 2;
160 break;
161 case 'K': /* status word? (2 byte) */
162 n += 2;
163 break;
164 case 'N': /* count of substructures (word) at end */
165 n += 2;
166 break;
167 case 'D': /* double word (4 byte) */
168 case 'z': /* offset to zero terminated string (4 byte) */
169 case 'l': /* offset to user data (4 byte) */
170 n += 4;
171 break;
172 case 'b': /* offset to data (with counter) (4 byte) */
173 n += 4;
174 get_counter(&p);
175 break;
176 case 'B': /* byte (with optional counter) */
177 n += get_counter(&p);
178 break;
181 return n;
184 static BOOL init_package(struct pack_desc* p, int count, int subcount)
186 int n = p->buflen;
187 int i;
189 if (!p->format || !p->base) return(False);
191 i = count * getlen(p->format);
192 if (p->subformat) i += subcount * getlen(p->subformat);
193 p->structbuf = p->base;
194 p->neededlen = 0;
195 p->usedlen = 0;
196 p->subcount = 0;
197 p->curpos = p->format;
198 if (i > n) {
199 p->neededlen = i;
200 i = n = 0;
201 #if 0
203 * This is the old error code we used. Aparently
204 * WinNT/2k systems return ERRbuftoosmall (2123) and
205 * OS/2 needs this. I'm leaving this here so we can revert
206 * if needed. JRA.
208 p->errcode = ERRmoredata;
209 #else
210 p->errcode = ERRbuftoosmall;
211 #endif
213 else
214 p->errcode = NERR_Success;
215 p->buflen = i;
216 n -= i;
217 p->stringbuf = p->base + i;
218 p->stringlen = n;
219 return(p->errcode == NERR_Success);
222 #ifdef HAVE_STDARG_H
223 static int package(struct pack_desc* p, ...)
225 #else
226 static int package(va_alist)
227 va_dcl
229 struct pack_desc* p;
230 #endif
231 va_list args;
232 int needed=0, stringneeded;
233 char* str=NULL;
234 int is_string=0, stringused;
235 int32 temp;
237 #ifdef HAVE_STDARG_H
238 va_start(args,p);
239 #else
240 va_start(args);
241 p = va_arg(args,struct pack_desc *);
242 #endif
244 if (!*p->curpos) {
245 if (!p->subcount)
246 p->curpos = p->format;
247 else {
248 p->curpos = p->subformat;
249 p->subcount--;
252 #if CHECK_TYPES
253 str = va_arg(args,char*);
254 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
255 #endif
256 stringneeded = -1;
258 if (!p->curpos) {
259 va_end(args);
260 return(0);
263 switch( *p->curpos++ ) {
264 case 'W': /* word (2 byte) */
265 needed = 2;
266 temp = va_arg(args,int);
267 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
268 break;
269 case 'K': /* status word? (2 byte) */
270 needed = 2;
271 temp = va_arg(args,int);
272 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
273 break;
274 case 'N': /* count of substructures (word) at end */
275 needed = 2;
276 p->subcount = va_arg(args,int);
277 if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
278 break;
279 case 'D': /* double word (4 byte) */
280 needed = 4;
281 temp = va_arg(args,int);
282 if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
283 break;
284 case 'B': /* byte (with optional counter) */
285 needed = get_counter(&p->curpos);
287 char *s = va_arg(args,char*);
288 if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
290 break;
291 case 'z': /* offset to zero terminated string (4 byte) */
292 str = va_arg(args,char*);
293 stringneeded = (str ? strlen(str)+1 : 0);
294 is_string = 1;
295 break;
296 case 'l': /* offset to user data (4 byte) */
297 str = va_arg(args,char*);
298 stringneeded = va_arg(args,int);
299 is_string = 0;
300 break;
301 case 'b': /* offset to data (with counter) (4 byte) */
302 str = va_arg(args,char*);
303 stringneeded = get_counter(&p->curpos);
304 is_string = 0;
305 break;
307 va_end(args);
308 if (stringneeded >= 0) {
309 needed = 4;
310 if (p->buflen >= needed) {
311 stringused = stringneeded;
312 if (stringused > p->stringlen) {
313 stringused = (is_string ? p->stringlen : 0);
314 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
316 if (!stringused)
317 SIVAL(p->structbuf,0,0);
318 else {
319 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
320 memcpy(p->stringbuf,str?str:"",stringused);
321 if (is_string) p->stringbuf[stringused-1] = '\0';
322 p->stringbuf += stringused;
323 p->stringlen -= stringused;
324 p->usedlen += stringused;
327 p->neededlen += stringneeded;
329 p->neededlen += needed;
330 if (p->buflen >= needed) {
331 p->structbuf += needed;
332 p->buflen -= needed;
333 p->usedlen += needed;
335 else {
336 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
338 return 1;
341 #if CHECK_TYPES
342 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
343 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
344 #else
345 #define PACK(desc,t,v) package(desc,v)
346 #define PACKl(desc,t,v,l) package(desc,v,l)
347 #endif
349 static void PACKI(struct pack_desc* desc,char *t,int v)
351 PACK(desc,t,v);
354 static void PACKS(struct pack_desc* desc,char *t,char *v)
356 PACK(desc,t,v);
360 /****************************************************************************
361 get a print queue
362 ****************************************************************************/
363 static void PackDriverData(struct pack_desc* desc)
365 char drivdata[4+4+32];
366 SIVAL(drivdata,0,sizeof drivdata); /* cb */
367 SIVAL(drivdata,4,1000); /* lVersion */
368 memset(drivdata+8,0,32); /* szDeviceName */
369 pstrcpy(drivdata+8,"NULL");
370 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
373 static int check_printq_info(struct pack_desc* desc,
374 int uLevel, char *id1, char *id2)
376 desc->subformat = NULL;
377 switch( uLevel ) {
378 case 0:
379 desc->format = "B13";
380 break;
381 case 1:
382 desc->format = "B13BWWWzzzzzWW";
383 break;
384 case 2:
385 desc->format = "B13BWWWzzzzzWN";
386 desc->subformat = "WB21BB16B10zWWzDDz";
387 break;
388 case 3:
389 desc->format = "zWWWWzzzzWWzzl";
390 break;
391 case 4:
392 desc->format = "zWWWWzzzzWNzzl";
393 desc->subformat = "WWzWWDDzz";
394 break;
395 case 5:
396 desc->format = "z";
397 break;
398 case 51:
399 desc->format = "K";
400 break;
401 case 52:
402 desc->format = "WzzzzzzzzN";
403 desc->subformat = "z";
404 break;
405 default: return False;
407 if (strcmp(desc->format,id1) != 0) return False;
408 if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
409 return True;
413 #define RAP_JOB_STATUS_QUEUED 0
414 #define RAP_JOB_STATUS_PAUSED 1
415 #define RAP_JOB_STATUS_SPOOLING 2
416 #define RAP_JOB_STATUS_PRINTING 3
417 #define RAP_JOB_STATUS_PRINTED 4
419 #define RAP_QUEUE_STATUS_PAUSED 1
420 #define RAP_QUEUE_STATUS_ERROR 2
422 /* turn a print job status into a on the wire status
424 static int printj_status(int v)
426 switch (v) {
427 case LPQ_QUEUED:
428 return RAP_JOB_STATUS_QUEUED;
429 case LPQ_PAUSED:
430 return RAP_JOB_STATUS_PAUSED;
431 case LPQ_SPOOLING:
432 return RAP_JOB_STATUS_SPOOLING;
433 case LPQ_PRINTING:
434 return RAP_JOB_STATUS_PRINTING;
436 return 0;
439 /* turn a print queue status into a on the wire status
441 static int printq_status(int v)
443 switch (v) {
444 case LPQ_QUEUED:
445 return 0;
446 case LPQ_PAUSED:
447 return RAP_QUEUE_STATUS_PAUSED;
449 return RAP_QUEUE_STATUS_ERROR;
452 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
453 struct pack_desc* desc,
454 print_queue_struct* queue, int n)
456 time_t t = queue->time;
458 /* the client expects localtime */
459 t -= TimeDiff(t);
461 PACKI(desc,"W",queue->job); /* uJobId */
462 if (uLevel == 1) {
463 PACKS(desc,"B21",dos_to_unix_static(queue->fs_user)); /* szUserName */
464 PACKS(desc,"B",""); /* pad */
465 PACKS(desc,"B16",""); /* szNotifyName */
466 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
467 PACKS(desc,"z",""); /* pszParms */
468 PACKI(desc,"W",n+1); /* uPosition */
469 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
470 PACKS(desc,"z",""); /* pszStatus */
471 PACKI(desc,"D",t); /* ulSubmitted */
472 PACKI(desc,"D",queue->size); /* ulSize */
473 PACKS(desc,"z",dos_to_unix_static(queue->fs_file)); /* pszComment */
475 if (uLevel == 2 || uLevel == 3 || uLevel == 4) {
476 PACKI(desc,"W",queue->priority); /* uPriority */
477 PACKS(desc,"z",dos_to_unix_static(queue->fs_user)); /* pszUserName */
478 PACKI(desc,"W",n+1); /* uPosition */
479 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
480 PACKI(desc,"D",t); /* ulSubmitted */
481 PACKI(desc,"D",queue->size); /* ulSize */
482 PACKS(desc,"z","Samba"); /* pszComment */
483 PACKS(desc,"z",dos_to_unix_static(queue->fs_file)); /* pszDocument */
484 if (uLevel == 3) {
485 PACKS(desc,"z",""); /* pszNotifyName */
486 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
487 PACKS(desc,"z",""); /* pszParms */
488 PACKS(desc,"z",""); /* pszStatus */
489 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
490 PACKS(desc,"z","lpd"); /* pszQProcName */
491 PACKS(desc,"z",""); /* pszQProcParms */
492 PACKS(desc,"z","NULL"); /* pszDriverName */
493 PackDriverData(desc); /* pDriverData */
494 PACKS(desc,"z",""); /* pszPrinterName */
495 } else if (uLevel == 4) { /* OS2 */
496 PACKS(desc,"z",""); /* pszSpoolFileName */
497 PACKS(desc,"z",""); /* pszPortName */
498 PACKS(desc,"z",""); /* pszStatus */
499 PACKI(desc,"D",0); /* ulPagesSpooled */
500 PACKI(desc,"D",0); /* ulPagesSent */
501 PACKI(desc,"D",0); /* ulPagesPrinted */
502 PACKI(desc,"D",0); /* ulTimePrinted */
503 PACKI(desc,"D",0); /* ulExtendJobStatus */
504 PACKI(desc,"D",0); /* ulStartPage */
505 PACKI(desc,"D",0); /* ulEndPage */
510 /********************************************************************
511 Return a driver name given an snum.
512 Looks in a tdb first. Returns True if from tdb, False otherwise.
513 ********************************************************************/
515 static BOOL get_driver_name(int snum, pstring drivername)
517 NT_PRINTER_INFO_LEVEL *info = NULL;
518 BOOL in_tdb = False;
520 get_a_printer (&info, 2, lp_servicename(snum));
521 if (info != NULL) {
522 pstrcpy( drivername, info->info_2->drivername);
523 in_tdb = True;
524 free_a_printer(&info, 2);
525 } else {
526 pstrcpy( drivername, lp_printerdriver(snum));
529 return in_tdb;
532 /********************************************************************
533 Respond to the DosPrintQInfo command with a level of 52
534 This is used to get printer driver information for Win9x clients
535 ********************************************************************/
536 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
537 struct pack_desc* desc,
538 int count, print_queue_struct* queue,
539 print_status_struct* status)
541 int i;
542 BOOL ok = False;
543 pstring tok,driver,datafile,langmon,helpfile,datatype;
544 char *p;
545 char **lines = NULL;
546 pstring gen_line;
547 BOOL in_tdb = False;
548 fstring location;
549 pstring drivername;
552 * Check in the tdb *first* before checking the legacy
553 * files. This allows an NT upload to take precedence over
554 * the existing fileset. JRA.
556 * we need to lookup the driver name prior to making the call
557 * to get_a_printer_driver_9x_compatible() and not rely on the
558 * 'print driver' parameter --jerry
562 if ((get_driver_name(snum,drivername)) &&
563 ((ok = get_a_printer_driver_9x_compatible(gen_line, drivername)) == True))
565 in_tdb = True;
566 p = gen_line;
567 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
569 else
571 /* didn't find driver in tdb */
573 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
574 snum, drivername, lp_driverfile(snum)));
576 lines = file_lines_load(lp_driverfile(snum),NULL, False);
577 if (!lines)
579 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
580 strerror(errno)));
581 desc->errcode=NERR_notsupported;
582 goto done;
585 /* lookup the long printer driver name in the file description */
586 for (i=0;lines[i] && !ok;i++)
588 p = lines[i];
589 if (next_token(&p,tok,":",sizeof(tok)) &&
590 (strlen(drivername) == strlen(tok)) &&
591 (!strncmp(tok,drivername,strlen(drivername))))
593 ok = True;
598 if (ok)
600 /* driver file name */
601 if (!next_token(&p,driver,":",sizeof(driver)))
602 goto err;
604 /* data file name */
605 if (!next_token(&p,datafile,":",sizeof(datafile)))
606 goto err;
609 * for the next tokens - which may be empty - I have
610 * to check for empty tokens first because the
611 * next_token function will skip all empty token
612 * fields */
614 /* help file */
615 if (*p == ':')
617 *helpfile = '\0';
618 p++;
620 else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
621 goto err;
623 /* language monitor */
624 if (*p == ':')
626 *langmon = '\0';
627 p++;
629 else if (!next_token(&p,langmon,":",sizeof(langmon)))
630 goto err;
632 /* default data type */
633 if (!next_token(&p,datatype,":",sizeof(datatype)))
634 goto err;
636 PACKI(desc,"W",0x0400); /* don't know */
637 PACKS(desc,"z",drivername); /* long printer name */
638 PACKS(desc,"z",driver); /* Driverfile Name */
639 PACKS(desc,"z",datafile); /* Datafile name */
640 PACKS(desc,"z",langmon); /* language monitor */
641 if (in_tdb)
643 fstrcpy(location, "\\\\");
644 fstrcat(location, global_myname);
645 fstrcat(location, "\\print$\\WIN40\\0");
646 PACKS(desc,"z",location); /* share to retrieve files */
648 else
650 PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */
652 PACKS(desc,"z",datatype); /* default data type */
653 PACKS(desc,"z",helpfile); /* helpfile name */
654 PACKS(desc,"z",driver); /* driver name */
656 DEBUG(3,("printerdriver:%s:\n",drivername));
657 DEBUG(3,("Driver:%s:\n",driver));
658 DEBUG(3,("Data File:%s:\n",datafile));
659 DEBUG(3,("Language Monitor:%s:\n",langmon));
660 if (in_tdb)
661 DEBUG(3,("lp_driverlocation:%s:\n",location));
662 else
663 DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
664 DEBUG(3,("Data Type:%s:\n",datatype));
665 DEBUG(3,("Help File:%s:\n",helpfile));
666 PACKI(desc,"N",count); /* number of files to copy */
668 for (i=0;i<count;i++)
670 /* no need to check return value here
671 * - it was already tested in
672 * get_printerdrivernumber */
673 next_token(&p,tok,",",sizeof(tok));
674 PACKS(desc,"z",tok); /* driver files to copy */
675 DEBUG(3,("file:%s:\n",tok));
678 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
679 SERVICE(snum),count));
681 desc->errcode=NERR_Success;
682 goto done;
685 err:
687 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
688 desc->errcode=NERR_notsupported;
690 done:
691 file_lines_free(lines);
695 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
696 struct pack_desc* desc,
697 int count, print_queue_struct* queue,
698 print_status_struct* status)
700 switch (uLevel) {
701 case 1:
702 case 2:
703 PACKS(desc,"B13",SERVICE(snum));
704 break;
705 case 3:
706 case 4:
707 case 5:
708 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
709 break;
710 case 51:
711 PACKI(desc,"K",printq_status(status->status));
712 break;
715 if (uLevel == 1 || uLevel == 2) {
716 PACKS(desc,"B",""); /* alignment */
717 PACKI(desc,"W",5); /* priority */
718 PACKI(desc,"W",0); /* start time */
719 PACKI(desc,"W",0); /* until time */
720 PACKS(desc,"z",""); /* pSepFile */
721 PACKS(desc,"z","lpd"); /* pPrProc */
722 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
723 PACKS(desc,"z",""); /* pParms */
724 if (snum < 0) {
725 PACKS(desc,"z","UNKNOWN PRINTER");
726 PACKI(desc,"W",LPSTAT_ERROR);
728 else if (!status || !status->message[0]) {
729 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
730 PACKI(desc,"W",LPSTAT_OK); /* status */
731 } else {
732 PACKS(desc,"z",status->message);
733 PACKI(desc,"W",printq_status(status->status)); /* status */
735 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
738 if (uLevel == 3 || uLevel == 4) {
739 pstring drivername;
741 PACKI(desc,"W",5); /* uPriority */
742 PACKI(desc,"W",0); /* uStarttime */
743 PACKI(desc,"W",0); /* uUntiltime */
744 PACKI(desc,"W",5); /* pad1 */
745 PACKS(desc,"z",""); /* pszSepFile */
746 PACKS(desc,"z","WinPrint"); /* pszPrProc */
747 PACKS(desc,"z",NULL); /* pszParms */
748 PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */
749 /* "don't ask" that it's done this way to fix corrupted
750 Win9X/ME printer comments. */
751 if (!status) {
752 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
753 } else {
754 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
756 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
757 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
758 get_driver_name(snum,drivername);
759 PACKS(desc,"z",drivername); /* pszDriverName */
760 PackDriverData(desc); /* pDriverData */
763 if (uLevel == 2 || uLevel == 4) {
764 int i;
765 for (i=0;i<count;i++)
766 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
769 if (uLevel==52) {
770 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
774 /* This function returns the number of files for a given driver */
775 static int get_printerdrivernumber(int snum)
777 int i, result = 0;
778 BOOL ok = False;
779 pstring tok;
780 char *p;
781 char **lines = NULL;
782 pstring gen_line;
783 pstring drivername;
786 * Check in the tdb *first* before checking the legacy
787 * files. This allows an NT upload to take precedence over
788 * the existing fileset. JRA.
790 * we need to lookup the driver name prior to making the call
791 * to get_a_printer_driver_9x_compatible() and not rely on the
792 * 'print driver' parameter --jerry
795 if ((get_driver_name(snum,drivername)) &&
796 (ok = get_a_printer_driver_9x_compatible(gen_line, drivername) == True))
798 p = gen_line;
799 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", drivername, gen_line));
801 else
803 /* didn't find driver in tdb */
805 DEBUG(10,("snum: %d\nprinterdriver: [%s]\nlp_driverfile: [%s]\n",
806 snum, drivername, lp_driverfile(snum)));
808 lines = file_lines_load(lp_driverfile(snum), NULL, False);
809 if (!lines)
811 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
812 goto done;
815 /* lookup the long printer driver name in the file description */
816 for (i=0;lines[i] && !ok;i++)
818 p = lines[i];
819 if (next_token(&p,tok,":",sizeof(tok)) &&
820 (strlen(drivername) == strlen(tok)) &&
821 (!strncmp(tok,drivername,strlen(drivername))))
823 ok = True;
828 if( ok )
830 /* skip 5 fields */
831 i = 5;
832 while (*p && i) {
833 if (*p++ == ':') i--;
835 if (!*p || i) {
836 DEBUG(3,("Can't determine number of printer driver files\n"));
837 goto done;
840 /* count the number of files */
841 while (next_token(&p,tok,",",sizeof(tok)))
842 i++;
844 result = i;
847 done:
849 file_lines_free(lines);
851 return result;
854 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
855 uint16 vuid, char *param,char *data,
856 int mdrcnt,int mprcnt,
857 char **rdata,char **rparam,
858 int *rdata_len,int *rparam_len)
860 char *str1 = param+2;
861 char *str2 = skip_string(str1,1);
862 char *p = skip_string(str2,1);
863 char *QueueName = p;
864 int uLevel;
865 int count=0;
866 int snum;
867 char* str3;
868 struct pack_desc desc;
869 print_queue_struct *queue=NULL;
870 print_status_struct status;
871 char* tmpdata=NULL;
873 memset((char *)&status,'\0',sizeof(status));
874 memset((char *)&desc,'\0',sizeof(desc));
876 p = skip_string(p,1);
877 uLevel = SVAL(p,0);
878 str3 = p + 4;
880 /* remove any trailing username */
881 if ((p = strchr(QueueName,'%')))
882 *p = 0;
884 DEBUG(3,("api_DosPrintQGetInfo: uLevel=%d name=%s\n",uLevel,QueueName));
886 /* check it's a supported varient */
887 if (!prefix_ok(str1,"zWrLh"))
888 return False;
889 if (!check_printq_info(&desc,uLevel,str2,str3)) {
891 * Patch from Scott Moomaw <scott@bridgewater.edu>
892 * to return the 'invalid info level' error if an
893 * unknown level was requested.
895 *rdata_len = 0;
896 *rparam_len = 6;
897 *rparam = REALLOC(*rparam,*rparam_len);
898 SSVALS(*rparam,0,ERRunknownlevel);
899 SSVAL(*rparam,2,0);
900 SSVAL(*rparam,4,0);
901 return(True);
904 snum = lp_servicenumber(QueueName);
905 if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
906 int pnum = lp_servicenumber(PRINTERS_NAME);
907 if (pnum >= 0) {
908 lp_add_printer(QueueName,pnum);
909 snum = lp_servicenumber(QueueName);
913 if (snum < 0 || !VALID_SNUM(snum))
914 return(False);
916 if (uLevel==52) {
917 count = get_printerdrivernumber(snum);
918 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
919 } else {
920 count = print_queue_status(snum, &queue,&status);
923 if (mdrcnt > 0) {
924 *rdata = REALLOC(*rdata,mdrcnt);
925 desc.base = *rdata;
926 desc.buflen = mdrcnt;
927 } else {
929 * Don't return data but need to get correct length
930 * init_package will return wrong size if buflen=0
932 desc.buflen = getlen(desc.format);
933 desc.base = tmpdata = (char *) malloc (desc.buflen);
936 if (init_package(&desc,1,count)) {
937 desc.subcount = count;
938 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
942 * We must set the return code to ERRbuftoosmall
943 * in order to support lanman style printing with Win NT/2k
944 * clients --jerry
946 if (!mdrcnt && lp_disable_spoolss())
947 desc.errcode = ERRbuftoosmall;
949 *rdata_len = desc.usedlen;
951 *rparam_len = 6;
952 *rparam = REALLOC(*rparam,*rparam_len);
953 SSVALS(*rparam,0,desc.errcode);
954 SSVAL(*rparam,2,0);
955 SSVAL(*rparam,4,desc.neededlen);
957 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
959 SAFE_FREE(queue);
960 SAFE_FREE(tmpdata);
962 return(True);
965 /****************************************************************************
966 View list of all print jobs on all queues.
967 ****************************************************************************/
969 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
970 int mdrcnt, int mprcnt,
971 char **rdata, char** rparam,
972 int *rdata_len, int *rparam_len)
974 char *param_format = param+2;
975 char *output_format1 = skip_string(param_format,1);
976 char *p = skip_string(output_format1,1);
977 int uLevel = SVAL(p,0);
978 char *output_format2 = p + 4;
979 int services = lp_numservices();
980 int i, n;
981 struct pack_desc desc;
982 print_queue_struct **queue = NULL;
983 print_status_struct *status = NULL;
984 int* subcntarr = NULL;
985 int queuecnt, subcnt=0, succnt=0;
987 memset((char *)&desc,'\0',sizeof(desc));
989 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
991 if (!prefix_ok(param_format,"WrLeh")) return False;
992 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
994 * Patch from Scott Moomaw <scott@bridgewater.edu>
995 * to return the 'invalid info level' error if an
996 * unknown level was requested.
998 *rdata_len = 0;
999 *rparam_len = 6;
1000 *rparam = REALLOC(*rparam,*rparam_len);
1001 SSVALS(*rparam,0,ERRunknownlevel);
1002 SSVAL(*rparam,2,0);
1003 SSVAL(*rparam,4,0);
1004 return(True);
1007 queuecnt = 0;
1008 for (i = 0; i < services; i++)
1009 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
1010 queuecnt++;
1011 if (uLevel > 0) {
1012 if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
1013 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1014 return False;
1016 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
1017 if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
1018 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1019 return False;
1021 memset(status,0,queuecnt*sizeof(print_status_struct));
1022 if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
1023 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
1024 return False;
1026 subcnt = 0;
1027 n = 0;
1028 for (i = 0; i < services; i++)
1029 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1030 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
1031 subcnt += subcntarr[n];
1032 n++;
1035 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1036 desc.base = *rdata;
1037 desc.buflen = mdrcnt;
1039 if (init_package(&desc,queuecnt,subcnt)) {
1040 n = 0;
1041 succnt = 0;
1042 for (i = 0; i < services; i++)
1043 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1044 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1045 n++;
1046 if (desc.errcode == NERR_Success) succnt = n;
1050 SAFE_FREE(subcntarr);
1052 *rdata_len = desc.usedlen;
1053 *rparam_len = 8;
1054 *rparam = REALLOC(*rparam,*rparam_len);
1055 SSVALS(*rparam,0,desc.errcode);
1056 SSVAL(*rparam,2,0);
1057 SSVAL(*rparam,4,succnt);
1058 SSVAL(*rparam,6,queuecnt);
1060 for (i = 0; i < queuecnt; i++) {
1061 if (queue) SAFE_FREE(queue[i]);
1064 SAFE_FREE(queue);
1065 SAFE_FREE(status);
1067 return True;
1070 /****************************************************************************
1071 get info level for a server list query
1072 ****************************************************************************/
1073 static BOOL check_server_info(int uLevel, char* id)
1075 switch( uLevel ) {
1076 case 0:
1077 if (strcmp(id,"B16") != 0) return False;
1078 break;
1079 case 1:
1080 if (strcmp(id,"B16BBDz") != 0) return False;
1081 break;
1082 default:
1083 return False;
1085 return True;
1088 struct srv_info_struct
1090 fstring name;
1091 uint32 type;
1092 fstring comment;
1093 fstring domain;
1094 BOOL server_added;
1098 /*******************************************************************
1099 get server info lists from the files saved by nmbd. Return the
1100 number of entries
1101 ******************************************************************/
1102 static int get_server_info(uint32 servertype,
1103 struct srv_info_struct **servers,
1104 char *domain)
1106 int count=0;
1107 int alloced=0;
1108 char **lines;
1109 BOOL local_list_only;
1110 int i;
1112 lines = file_lines_load(lock_path(SERVER_LIST), NULL, False);
1113 if (!lines) {
1114 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1115 return(0);
1118 /* request for everything is code for request all servers */
1119 if (servertype == SV_TYPE_ALL)
1120 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1122 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1124 DEBUG(4,("Servertype search: %8x\n",servertype));
1126 for (i=0;lines[i];i++) {
1127 fstring stype;
1128 struct srv_info_struct *s;
1129 char *ptr = lines[i];
1130 BOOL ok = True;
1132 if (!*ptr) continue;
1134 if (count == alloced) {
1135 struct srv_info_struct *ts;
1137 alloced += 10;
1138 ts = (struct srv_info_struct *)
1139 Realloc(*servers,sizeof(**servers)*alloced);
1140 if (!ts) {
1141 DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
1142 return(0);
1144 else *servers = ts;
1145 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1147 s = &(*servers)[count];
1149 if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue;
1150 if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue;
1151 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1152 if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1153 /* this allows us to cope with an old nmbd */
1154 pstrcpy(s->domain,global_myworkgroup);
1157 if (sscanf(stype,"%X",&s->type) != 1) {
1158 DEBUG(4,("r:host file "));
1159 ok = False;
1162 /* Filter the servers/domains we return based on what was asked for. */
1164 /* Check to see if we are being asked for a local list only. */
1165 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1166 DEBUG(4,("r: local list only"));
1167 ok = False;
1170 /* doesn't match up: don't want it */
1171 if (!(servertype & s->type)) {
1172 DEBUG(4,("r:serv type "));
1173 ok = False;
1176 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1177 (s->type & SV_TYPE_DOMAIN_ENUM))
1179 DEBUG(4,("s: dom mismatch "));
1180 ok = False;
1183 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1185 ok = False;
1188 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1189 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1191 if (ok)
1193 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1194 s->name, s->type, s->comment, s->domain));
1196 s->server_added = True;
1197 count++;
1199 else
1201 DEBUG(4,("%20s %8x %25s %15s\n",
1202 s->name, s->type, s->comment, s->domain));
1206 file_lines_free(lines);
1207 return(count);
1211 /*******************************************************************
1212 fill in a server info structure
1213 ******************************************************************/
1214 static int fill_srv_info(struct srv_info_struct *service,
1215 int uLevel, char **buf, int *buflen,
1216 char **stringbuf, int *stringspace, char *baseaddr)
1218 int struct_len;
1219 char* p;
1220 char* p2;
1221 int l2;
1222 int len;
1224 switch (uLevel) {
1225 case 0: struct_len = 16; break;
1226 case 1: struct_len = 26; break;
1227 default: return -1;
1230 if (!buf)
1232 len = 0;
1233 switch (uLevel)
1235 case 1:
1236 len = strlen(service->comment)+1;
1237 break;
1240 if (buflen) *buflen = struct_len;
1241 if (stringspace) *stringspace = len;
1242 return struct_len + len;
1245 len = struct_len;
1246 p = *buf;
1247 if (*buflen < struct_len) return -1;
1248 if (stringbuf)
1250 p2 = *stringbuf;
1251 l2 = *stringspace;
1253 else
1255 p2 = p + struct_len;
1256 l2 = *buflen - struct_len;
1258 if (!baseaddr) baseaddr = p;
1260 switch (uLevel)
1262 case 0:
1263 StrnCpy(p,service->name,15);
1264 break;
1266 case 1:
1267 StrnCpy(p,service->name,15);
1268 SIVAL(p,18,service->type);
1269 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1270 len += CopyAndAdvance(&p2,service->comment,&l2);
1271 break;
1274 if (stringbuf)
1276 *buf = p + struct_len;
1277 *buflen -= struct_len;
1278 *stringbuf = p2;
1279 *stringspace = l2;
1281 else
1283 *buf = p2;
1284 *buflen -= len;
1286 return len;
1290 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1292 return(strcmp(s1->name,s2->name));
1295 /****************************************************************************
1296 view list of servers available (or possibly domains). The info is
1297 extracted from lists saved by nmbd on the local host
1298 ****************************************************************************/
1299 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1300 int mdrcnt, int mprcnt, char **rdata,
1301 char **rparam, int *rdata_len, int *rparam_len)
1303 char *str1 = param+2;
1304 char *str2 = skip_string(str1,1);
1305 char *p = skip_string(str2,1);
1306 int uLevel = SVAL(p,0);
1307 int buf_len = SVAL(p,2);
1308 uint32 servertype = IVAL(p,4);
1309 char *p2;
1310 int data_len, fixed_len, string_len;
1311 int f_len = 0, s_len = 0;
1312 struct srv_info_struct *servers=NULL;
1313 int counted=0,total=0;
1314 int i,missed;
1315 fstring domain;
1316 BOOL domain_request;
1317 BOOL local_request;
1319 /* If someone sets all the bits they don't really mean to set
1320 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1321 known servers. */
1323 if (servertype == SV_TYPE_ALL)
1324 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1326 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1327 any other bit (they may just set this bit on it's own) they
1328 want all the locally seen servers. However this bit can be
1329 set on its own so set the requested servers to be
1330 ALL - DOMAIN_ENUM. */
1332 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1333 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1335 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1336 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1338 p += 8;
1340 if (!prefix_ok(str1,"WrLehD")) return False;
1341 if (!check_server_info(uLevel,str2)) return False;
1343 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1344 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1345 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1347 if (strcmp(str1, "WrLehDz") == 0) {
1348 StrnCpy(domain, p, sizeof(fstring)-1);
1349 } else {
1350 StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);
1353 if (lp_browse_list())
1354 total = get_server_info(servertype,&servers,domain);
1356 data_len = fixed_len = string_len = 0;
1357 missed = 0;
1359 if (total > 0)
1360 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1363 char *lastname=NULL;
1365 for (i=0;i<total;i++)
1367 struct srv_info_struct *s = &servers[i];
1368 if (lastname && strequal(lastname,s->name)) continue;
1369 lastname = s->name;
1370 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1371 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1372 s->name, s->type, s->comment, s->domain));
1374 if (data_len <= buf_len) {
1375 counted++;
1376 fixed_len += f_len;
1377 string_len += s_len;
1378 } else {
1379 missed++;
1384 *rdata_len = fixed_len + string_len;
1385 *rdata = REALLOC(*rdata,*rdata_len);
1386 memset(*rdata,'\0',*rdata_len);
1388 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1389 p = *rdata;
1390 f_len = fixed_len;
1391 s_len = string_len;
1394 char *lastname=NULL;
1395 int count2 = counted;
1396 for (i = 0; i < total && count2;i++)
1398 struct srv_info_struct *s = &servers[i];
1399 if (lastname && strequal(lastname,s->name)) continue;
1400 lastname = s->name;
1401 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1402 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1403 s->name, s->type, s->comment, s->domain));
1404 count2--;
1408 *rparam_len = 8;
1409 *rparam = REALLOC(*rparam,*rparam_len);
1410 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1411 SSVAL(*rparam,2,0);
1412 SSVAL(*rparam,4,counted);
1413 SSVAL(*rparam,6,counted+missed);
1415 SAFE_FREE(servers);
1417 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1418 domain,uLevel,counted,counted+missed));
1420 return(True);
1423 /****************************************************************************
1424 command 0x34 - suspected of being a "Lookup Names" stub api
1425 ****************************************************************************/
1426 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1427 int mdrcnt, int mprcnt, char **rdata,
1428 char **rparam, int *rdata_len, int *rparam_len)
1430 char *str1 = param+2;
1431 char *str2 = skip_string(str1,1);
1432 char *p = skip_string(str2,1);
1433 int uLevel = SVAL(p,0);
1434 int buf_len = SVAL(p,2);
1435 int counted=0;
1436 int missed=0;
1438 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1439 str1, str2, p, uLevel, buf_len));
1441 if (!prefix_ok(str1,"zWrLeh")) return False;
1443 *rdata_len = 0;
1445 *rparam_len = 8;
1446 *rparam = REALLOC(*rparam,*rparam_len);
1448 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1449 SSVAL(*rparam,2,0);
1450 SSVAL(*rparam,4,counted);
1451 SSVAL(*rparam,6,counted+missed);
1453 return(True);
1456 /****************************************************************************
1457 get info about a share
1458 ****************************************************************************/
1459 static BOOL check_share_info(int uLevel, char* id)
1461 switch( uLevel ) {
1462 case 0:
1463 if (strcmp(id,"B13") != 0) return False;
1464 break;
1465 case 1:
1466 if (strcmp(id,"B13BWz") != 0) return False;
1467 break;
1468 case 2:
1469 if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1470 break;
1471 case 91:
1472 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1473 break;
1474 default: return False;
1476 return True;
1479 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1480 char** buf, int* buflen,
1481 char** stringbuf, int* stringspace, char* baseaddr)
1483 int struct_len;
1484 char* p;
1485 char* p2;
1486 int l2;
1487 int len;
1489 switch( uLevel ) {
1490 case 0: struct_len = 13; break;
1491 case 1: struct_len = 20; break;
1492 case 2: struct_len = 40; break;
1493 case 91: struct_len = 68; break;
1494 default: return -1;
1498 if (!buf)
1500 len = 0;
1501 if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1502 if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1503 if (buflen) *buflen = struct_len;
1504 if (stringspace) *stringspace = len;
1505 return struct_len + len;
1508 len = struct_len;
1509 p = *buf;
1510 if ((*buflen) < struct_len) return -1;
1511 if (stringbuf)
1513 p2 = *stringbuf;
1514 l2 = *stringspace;
1516 else
1518 p2 = p + struct_len;
1519 l2 = (*buflen) - struct_len;
1521 if (!baseaddr) baseaddr = p;
1523 StrnCpy(p,lp_servicename(snum),13);
1525 if (uLevel > 0)
1527 int type;
1528 SCVAL(p,13,0);
1529 type = STYPE_DISKTREE;
1530 if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1531 if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1532 SSVAL(p,14,type); /* device type */
1533 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1534 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1537 if (uLevel > 1)
1539 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1540 SSVALS(p,22,-1); /* max uses */
1541 SSVAL(p,24,1); /* current uses */
1542 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1543 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1544 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1547 if (uLevel > 2)
1549 memset(p+40,0,SHPWLEN+2);
1550 SSVAL(p,50,0);
1551 SIVAL(p,52,0);
1552 SSVAL(p,56,0);
1553 SSVAL(p,58,0);
1554 SIVAL(p,60,0);
1555 SSVAL(p,64,0);
1556 SSVAL(p,66,0);
1559 if (stringbuf)
1561 (*buf) = p + struct_len;
1562 (*buflen) -= struct_len;
1563 (*stringbuf) = p2;
1564 (*stringspace) = l2;
1566 else
1568 (*buf) = p2;
1569 (*buflen) -= len;
1571 return len;
1574 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1575 int mdrcnt,int mprcnt,
1576 char **rdata,char **rparam,
1577 int *rdata_len,int *rparam_len)
1579 char *str1 = param+2;
1580 char *str2 = skip_string(str1,1);
1581 char *netname = skip_string(str2,1);
1582 char *p = skip_string(netname,1);
1583 int uLevel = SVAL(p,0);
1584 int snum = find_service(netname);
1586 if (snum < 0) return False;
1588 /* check it's a supported varient */
1589 if (!prefix_ok(str1,"zWrLh")) return False;
1590 if (!check_share_info(uLevel,str2)) return False;
1592 *rdata = REALLOC(*rdata,mdrcnt);
1593 p = *rdata;
1594 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1595 if (*rdata_len < 0) return False;
1597 *rparam_len = 6;
1598 *rparam = REALLOC(*rparam,*rparam_len);
1599 SSVAL(*rparam,0,NERR_Success);
1600 SSVAL(*rparam,2,0); /* converter word */
1601 SSVAL(*rparam,4,*rdata_len);
1603 return(True);
1606 /****************************************************************************
1607 view list of shares available
1608 ****************************************************************************/
1609 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1610 int mdrcnt,int mprcnt,
1611 char **rdata,char **rparam,
1612 int *rdata_len,int *rparam_len)
1614 char *str1 = param+2;
1615 char *str2 = skip_string(str1,1);
1616 char *p = skip_string(str2,1);
1617 int uLevel = SVAL(p,0);
1618 int buf_len = SVAL(p,2);
1619 char *p2;
1620 int count=lp_numservices();
1621 int total=0,counted=0;
1622 BOOL missed = False;
1623 int i;
1624 int data_len, fixed_len, string_len;
1625 int f_len = 0, s_len = 0;
1627 if (!prefix_ok(str1,"WrLeh")) return False;
1628 if (!check_share_info(uLevel,str2)) return False;
1630 data_len = fixed_len = string_len = 0;
1631 for (i=0;i<count;i++)
1632 if (lp_browseable(i) && lp_snum_ok(i))
1634 total++;
1635 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1636 if (data_len <= buf_len)
1638 counted++;
1639 fixed_len += f_len;
1640 string_len += s_len;
1642 else
1643 missed = True;
1645 *rdata_len = fixed_len + string_len;
1646 *rdata = REALLOC(*rdata,*rdata_len);
1647 memset(*rdata,0,*rdata_len);
1649 p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
1650 p = *rdata;
1651 f_len = fixed_len;
1652 s_len = string_len;
1653 for (i = 0; i < count;i++)
1654 if (lp_browseable(i) && lp_snum_ok(i))
1655 if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1656 break;
1658 *rparam_len = 8;
1659 *rparam = REALLOC(*rparam,*rparam_len);
1660 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1661 SSVAL(*rparam,2,0);
1662 SSVAL(*rparam,4,counted);
1663 SSVAL(*rparam,6,total);
1665 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1666 counted,total,uLevel,
1667 buf_len,*rdata_len,mdrcnt));
1668 return(True);
1673 /****************************************************************************
1674 get the time of day info
1675 ****************************************************************************/
1676 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1677 int mdrcnt,int mprcnt,
1678 char **rdata,char **rparam,
1679 int *rdata_len,int *rparam_len)
1681 char *p;
1682 *rparam_len = 4;
1683 *rparam = REALLOC(*rparam,*rparam_len);
1685 *rdata_len = 21;
1686 *rdata = REALLOC(*rdata,*rdata_len);
1688 SSVAL(*rparam,0,NERR_Success);
1689 SSVAL(*rparam,2,0); /* converter word */
1691 p = *rdata;
1694 struct tm *t;
1695 time_t unixdate = time(NULL);
1697 put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1698 by NT in a "net time" operation,
1699 it seems to ignore the one below */
1701 /* the client expects to get localtime, not GMT, in this bit
1702 (I think, this needs testing) */
1703 t = LocalTime(&unixdate);
1705 SIVAL(p,4,0); /* msecs ? */
1706 SCVAL(p,8,t->tm_hour);
1707 SCVAL(p,9,t->tm_min);
1708 SCVAL(p,10,t->tm_sec);
1709 SCVAL(p,11,0); /* hundredths of seconds */
1710 SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1711 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
1712 SCVAL(p,16,t->tm_mday);
1713 SCVAL(p,17,t->tm_mon + 1);
1714 SSVAL(p,18,1900+t->tm_year);
1715 SCVAL(p,20,t->tm_wday);
1719 return(True);
1722 /****************************************************************************
1723 Set the user password.
1724 *****************************************************************************/
1726 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1727 int mdrcnt,int mprcnt,
1728 char **rdata,char **rparam,
1729 int *rdata_len,int *rparam_len)
1731 char *p = skip_string(param+2,2);
1732 fstring user;
1733 fstring pass1,pass2;
1735 fstrcpy(user,p);
1737 p = skip_string(p,1);
1739 memset(pass1,'\0',sizeof(pass1));
1740 memset(pass2,'\0',sizeof(pass2));
1741 memcpy(pass1,p,16);
1742 memcpy(pass2,p+16,16);
1744 *rparam_len = 4;
1745 *rparam = REALLOC(*rparam,*rparam_len);
1747 *rdata_len = 0;
1749 SSVAL(*rparam,0,NERR_badpass);
1750 SSVAL(*rparam,2,0); /* converter word */
1752 DEBUG(3,("Set password for <%s>\n",user));
1755 * Pass the user through the NT -> unix user mapping
1756 * function.
1759 (void)map_username(user);
1762 * Do any UNIX username case mangling.
1764 (void)Get_Pwnam( user, True);
1767 * Attempt to verify the old password against smbpasswd entries
1768 * Win98 clients send old and new password in plaintext for this call.
1772 fstring saved_pass2;
1773 SAM_ACCOUNT *sampass = NULL;
1776 * Save the new password as change_oem_password overwrites it
1777 * with zeros.
1780 fstrcpy(saved_pass2, pass2);
1782 if (check_plaintext_password(user,pass1,strlen(pass1),&sampass) &&
1783 change_oem_password(sampass,pass2,False))
1785 SSVAL(*rparam,0,NERR_Success);
1788 * If unix password sync was requested, attempt to change
1789 * the /etc/passwd database also. Return failure if this cannot
1790 * be done.
1793 if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1794 SSVAL(*rparam,0,NERR_badpass);
1797 if (sampass)
1798 pdb_free_sam(sampass);
1802 * If the above failed, attempt the plaintext password change.
1803 * This tests against the /etc/passwd database only.
1806 if(SVAL(*rparam,0) != NERR_Success)
1808 if (password_ok(user, pass1,strlen(pass1),NULL) &&
1809 chgpasswd(user,pass1,pass2,False))
1811 SSVAL(*rparam,0,NERR_Success);
1816 * If the plaintext change failed, attempt
1817 * the old encrypted method. NT will generate this
1818 * after trying the samr method. Note that this
1819 * method is done as a last resort as this
1820 * password change method loses the NT password hash
1821 * and cannot change the UNIX password as no plaintext
1822 * is received.
1825 if(SVAL(*rparam,0) != NERR_Success)
1827 SAM_ACCOUNT *sampass = NULL;
1829 if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &sampass) &&
1830 change_lanman_password(sampass,(unsigned char *)pass1,(unsigned char *)pass2))
1832 SSVAL(*rparam,0,NERR_Success);
1834 pdb_free_sam(sampass);
1837 memset((char *)pass1,'\0',sizeof(fstring));
1838 memset((char *)pass2,'\0',sizeof(fstring));
1840 return(True);
1843 /****************************************************************************
1844 Set the user password (SamOEM version - gets plaintext).
1845 ****************************************************************************/
1847 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1848 int mdrcnt,int mprcnt,
1849 char **rdata,char **rparam,
1850 int *rdata_len,int *rparam_len)
1852 fstring user;
1853 char *p = param + 2;
1854 *rparam_len = 2;
1855 *rparam = REALLOC(*rparam,*rparam_len);
1857 *rdata_len = 0;
1859 SSVAL(*rparam,0,NERR_badpass);
1862 * Check the parameter definition is correct.
1864 if(!strequal(param + 2, "zsT")) {
1865 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1866 return False;
1868 p = skip_string(p, 1);
1870 if(!strequal(p, "B516B16")) {
1871 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1872 return False;
1874 p = skip_string(p,1);
1876 fstrcpy(user,p);
1877 p = skip_string(p,1);
1879 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1882 * Pass the user through the NT -> unix user mapping
1883 * function.
1886 (void)map_username(user);
1889 * Do any UNIX username case mangling.
1891 (void)Get_Pwnam( user, True);
1893 if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1895 SSVAL(*rparam,0,NERR_Success);
1898 return(True);
1901 /****************************************************************************
1902 delete a print job
1903 Form: <W> <>
1904 ****************************************************************************/
1905 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1906 int mdrcnt,int mprcnt,
1907 char **rdata,char **rparam,
1908 int *rdata_len,int *rparam_len)
1910 int function = SVAL(param,0);
1911 char *str1 = param+2;
1912 char *str2 = skip_string(str1,1);
1913 char *p = skip_string(str2,1);
1914 int jobid, errcode;
1915 extern struct current_user current_user;
1916 WERROR werr = WERR_OK;
1918 jobid = SVAL(p,0);
1920 /* check it's a supported varient */
1921 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1922 return(False);
1924 *rparam_len = 4;
1925 *rparam = REALLOC(*rparam,*rparam_len);
1926 *rdata_len = 0;
1928 if (!print_job_exists(jobid)) {
1929 errcode = NERR_JobNotFound;
1930 goto out;
1933 errcode = NERR_notsupported;
1935 switch (function) {
1936 case 81: /* delete */
1937 if (print_job_delete(&current_user, jobid, &werr))
1938 errcode = NERR_Success;
1939 break;
1940 case 82: /* pause */
1941 if (print_job_pause(&current_user, jobid, &werr))
1942 errcode = NERR_Success;
1943 break;
1944 case 83: /* resume */
1945 if (print_job_resume(&current_user, jobid, &werr))
1946 errcode = NERR_Success;
1947 break;
1950 if (!W_ERROR_IS_OK(werr))
1951 errcode = W_ERROR_V(werr);
1953 out:
1954 SSVAL(*rparam,0,errcode);
1955 SSVAL(*rparam,2,0); /* converter word */
1957 return(True);
1960 /****************************************************************************
1961 Purge a print queue - or pause or resume it.
1962 ****************************************************************************/
1963 static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param,char *data,
1964 int mdrcnt,int mprcnt,
1965 char **rdata,char **rparam,
1966 int *rdata_len,int *rparam_len)
1968 int function = SVAL(param,0);
1969 char *str1 = param+2;
1970 char *str2 = skip_string(str1,1);
1971 char *QueueName = skip_string(str2,1);
1972 int errcode = NERR_notsupported;
1973 int snum;
1974 WERROR werr = WERR_OK;
1975 extern struct current_user current_user;
1977 /* check it's a supported varient */
1978 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1979 return(False);
1981 *rparam_len = 4;
1982 *rparam = REALLOC(*rparam,*rparam_len);
1983 *rdata_len = 0;
1985 snum = print_queue_snum(QueueName);
1987 if (snum == -1) {
1988 errcode = NERR_JobNotFound;
1989 goto out;
1992 switch (function) {
1993 case 74: /* Pause queue */
1994 if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
1995 break;
1996 case 75: /* Resume queue */
1997 if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
1998 break;
1999 case 103: /* Purge */
2000 if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
2001 break;
2004 if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
2005 out:
2006 SSVAL(*rparam,0,errcode);
2007 SSVAL(*rparam,2,0); /* converter word */
2009 return(True);
2013 /****************************************************************************
2014 set the property of a print job (undocumented?)
2015 ? function = 0xb -> set name of print job
2016 ? function = 0x6 -> move print job up/down
2017 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
2018 or <WWsTP> <WB21BB16B10zWWzDDz>
2019 ****************************************************************************/
2020 static int check_printjob_info(struct pack_desc* desc,
2021 int uLevel, char* id)
2023 desc->subformat = NULL;
2024 switch( uLevel ) {
2025 case 0: desc->format = "W"; break;
2026 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
2027 case 2: desc->format = "WWzWWDDzz"; break;
2028 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
2029 case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break;
2030 default: return False;
2032 if (strcmp(desc->format,id) != 0) return False;
2033 return True;
2036 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
2037 int mdrcnt,int mprcnt,
2038 char **rdata,char **rparam,
2039 int *rdata_len,int *rparam_len)
2041 struct pack_desc desc;
2042 char *str1 = param+2;
2043 char *str2 = skip_string(str1,1);
2044 char *p = skip_string(str2,1);
2045 int jobid;
2046 int uLevel = SVAL(p,2);
2047 int function = SVAL(p,4);
2048 int place, errcode;
2050 jobid = SVAL(p,0);
2051 *rparam_len = 4;
2052 *rparam = REALLOC(*rparam,*rparam_len);
2054 *rdata_len = 0;
2056 /* check it's a supported varient */
2057 if ((strcmp(str1,"WWsTP")) ||
2058 (!check_printjob_info(&desc,uLevel,str2)))
2059 return(False);
2061 if (!print_job_exists(jobid)) {
2062 errcode=NERR_JobNotFound;
2063 goto out;
2066 errcode = NERR_notsupported;
2068 switch (function) {
2069 case 0x6:
2070 /* change job place in the queue,
2071 data gives the new place */
2072 place = SVAL(data,0);
2073 if (print_job_set_place(jobid, place)) {
2074 errcode=NERR_Success;
2076 break;
2078 case 0xb:
2079 /* change print job name, data gives the name */
2080 if (print_job_set_name(jobid, data)) {
2081 errcode=NERR_Success;
2083 break;
2085 default:
2086 return False;
2089 out:
2090 SSVALS(*rparam,0,errcode);
2091 SSVAL(*rparam,2,0); /* converter word */
2093 return(True);
2097 /****************************************************************************
2098 get info about the server
2099 ****************************************************************************/
2100 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2101 int mdrcnt,int mprcnt,
2102 char **rdata,char **rparam,
2103 int *rdata_len,int *rparam_len)
2105 char *str1 = param+2;
2106 char *str2 = skip_string(str1,1);
2107 char *p = skip_string(str2,1);
2108 int uLevel = SVAL(p,0);
2109 char *p2;
2110 int struct_len;
2112 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2114 /* check it's a supported varient */
2115 if (!prefix_ok(str1,"WrLh")) return False;
2116 switch( uLevel ) {
2117 case 0:
2118 if (strcmp(str2,"B16") != 0) return False;
2119 struct_len = 16;
2120 break;
2121 case 1:
2122 if (strcmp(str2,"B16BBDz") != 0) return False;
2123 struct_len = 26;
2124 break;
2125 case 2:
2126 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2127 != 0) return False;
2128 struct_len = 134;
2129 break;
2130 case 3:
2131 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2132 != 0) return False;
2133 struct_len = 144;
2134 break;
2135 case 20:
2136 if (strcmp(str2,"DN") != 0) return False;
2137 struct_len = 6;
2138 break;
2139 case 50:
2140 if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2141 struct_len = 42;
2142 break;
2143 default: return False;
2146 *rdata_len = mdrcnt;
2147 *rdata = REALLOC(*rdata,*rdata_len);
2149 p = *rdata;
2150 p2 = p + struct_len;
2151 if (uLevel != 20) {
2152 StrnCpy(p,local_machine,16);
2153 strupper(p);
2155 p += 16;
2156 if (uLevel > 0)
2158 struct srv_info_struct *servers=NULL;
2159 int i,count;
2160 pstring comment;
2161 uint32 servertype= lp_default_server_announce();
2163 pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2165 if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2166 for (i=0;i<count;i++)
2167 if (strequal(servers[i].name,local_machine))
2169 servertype = servers[i].type;
2170 pstrcpy(comment,servers[i].comment);
2173 SAFE_FREE(servers);
2175 SCVAL(p,0,lp_major_announce_version());
2176 SCVAL(p,1,lp_minor_announce_version());
2177 SIVAL(p,2,servertype);
2179 if (mdrcnt == struct_len) {
2180 SIVAL(p,6,0);
2181 } else {
2182 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2183 standard_sub_conn(conn,comment,sizeof(comment));
2184 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2185 p2 = skip_string(p2,1);
2188 if (uLevel > 1)
2190 return False; /* not yet implemented */
2193 *rdata_len = PTR_DIFF(p2,*rdata);
2195 *rparam_len = 6;
2196 *rparam = REALLOC(*rparam,*rparam_len);
2197 SSVAL(*rparam,0,NERR_Success);
2198 SSVAL(*rparam,2,0); /* converter word */
2199 SSVAL(*rparam,4,*rdata_len);
2201 return(True);
2205 /****************************************************************************
2206 get info about the server
2207 ****************************************************************************/
2208 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2209 int mdrcnt,int mprcnt,
2210 char **rdata,char **rparam,
2211 int *rdata_len,int *rparam_len)
2213 char *str1 = param+2;
2214 char *str2 = skip_string(str1,1);
2215 char *p = skip_string(str2,1);
2216 char *p2;
2217 extern userdom_struct current_user_info;
2218 int level = SVAL(p,0);
2220 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2222 *rparam_len = 6;
2223 *rparam = REALLOC(*rparam,*rparam_len);
2225 /* check it's a supported varient */
2226 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2227 return(False);
2229 *rdata_len = mdrcnt + 1024;
2230 *rdata = REALLOC(*rdata,*rdata_len);
2232 SSVAL(*rparam,0,NERR_Success);
2233 SSVAL(*rparam,2,0); /* converter word */
2235 p = *rdata;
2236 p2 = p + 22;
2239 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2240 pstrcpy(p2,local_machine);
2241 strupper(p2);
2242 p2 = skip_string(p2,1);
2243 p += 4;
2245 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2246 pstrcpy(p2,current_user_info.smb_name);
2247 p2 = skip_string(p2,1);
2248 p += 4;
2250 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2251 pstrcpy(p2,global_myworkgroup);
2252 strupper(p2);
2253 p2 = skip_string(p2,1);
2254 p += 4;
2256 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2257 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2258 p += 2;
2260 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2261 pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
2262 p2 = skip_string(p2,1);
2263 p += 4;
2265 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2266 pstrcpy(p2,"");
2267 p2 = skip_string(p2,1);
2268 p += 4;
2270 *rdata_len = PTR_DIFF(p2,*rdata);
2272 SSVAL(*rparam,4,*rdata_len);
2274 return(True);
2277 /****************************************************************************
2278 get info about a user
2280 struct user_info_11 {
2281 char usri11_name[21]; 0-20
2282 char usri11_pad; 21
2283 char *usri11_comment; 22-25
2284 char *usri11_usr_comment; 26-29
2285 unsigned short usri11_priv; 30-31
2286 unsigned long usri11_auth_flags; 32-35
2287 long usri11_password_age; 36-39
2288 char *usri11_homedir; 40-43
2289 char *usri11_parms; 44-47
2290 long usri11_last_logon; 48-51
2291 long usri11_last_logoff; 52-55
2292 unsigned short usri11_bad_pw_count; 56-57
2293 unsigned short usri11_num_logons; 58-59
2294 char *usri11_logon_server; 60-63
2295 unsigned short usri11_country_code; 64-65
2296 char *usri11_workstations; 66-69
2297 unsigned long usri11_max_storage; 70-73
2298 unsigned short usri11_units_per_week; 74-75
2299 unsigned char *usri11_logon_hours; 76-79
2300 unsigned short usri11_code_page; 80-81
2303 where:
2305 usri11_name specifies the user name for which information is retireved
2307 usri11_pad aligns the next data structure element to a word boundary
2309 usri11_comment is a null terminated ASCII comment
2311 usri11_user_comment is a null terminated ASCII comment about the user
2313 usri11_priv specifies the level of the privilege assigned to the user.
2314 The possible values are:
2316 Name Value Description
2317 USER_PRIV_GUEST 0 Guest privilege
2318 USER_PRIV_USER 1 User privilege
2319 USER_PRV_ADMIN 2 Administrator privilege
2321 usri11_auth_flags specifies the account operator privileges. The
2322 possible values are:
2324 Name Value Description
2325 AF_OP_PRINT 0 Print operator
2328 Leach, Naik [Page 28]
2332 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2335 AF_OP_COMM 1 Communications operator
2336 AF_OP_SERVER 2 Server operator
2337 AF_OP_ACCOUNTS 3 Accounts operator
2340 usri11_password_age specifies how many seconds have elapsed since the
2341 password was last changed.
2343 usri11_home_dir points to a null terminated ASCII string that contains
2344 the path name of the user's home directory.
2346 usri11_parms points to a null terminated ASCII string that is set
2347 aside for use by applications.
2349 usri11_last_logon specifies the time when the user last logged on.
2350 This value is stored as the number of seconds elapsed since
2351 00:00:00, January 1, 1970.
2353 usri11_last_logoff specifies the time when the user last logged off.
2354 This value is stored as the number of seconds elapsed since
2355 00:00:00, January 1, 1970. A value of 0 means the last logoff
2356 time is unknown.
2358 usri11_bad_pw_count specifies the number of incorrect passwords
2359 entered since the last successful logon.
2361 usri11_log1_num_logons specifies the number of times this user has
2362 logged on. A value of -1 means the number of logons is unknown.
2364 usri11_logon_server points to a null terminated ASCII string that
2365 contains the name of the server to which logon requests are sent.
2366 A null string indicates logon requests should be sent to the
2367 domain controller.
2369 usri11_country_code specifies the country code for the user's language
2370 of choice.
2372 usri11_workstations points to a null terminated ASCII string that
2373 contains the names of workstations the user may log on from.
2374 There may be up to 8 workstations, with the names separated by
2375 commas. A null strings indicates there are no restrictions.
2377 usri11_max_storage specifies the maximum amount of disk space the user
2378 can occupy. A value of 0xffffffff indicates there are no
2379 restrictions.
2381 usri11_units_per_week specifies the equal number of time units into
2382 which a week is divided. This value must be equal to 168.
2384 usri11_logon_hours points to a 21 byte (168 bits) string that
2385 specifies the time during which the user can log on. Each bit
2386 represents one unique hour in a week. The first bit (bit 0, word
2387 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2391 Leach, Naik [Page 29]
2395 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2398 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2399 are no restrictions.
2401 usri11_code_page specifies the code page for the user's language of
2402 choice
2404 All of the pointers in this data structure need to be treated
2405 specially. The pointer is a 32 bit pointer. The higher 16 bits need
2406 to be ignored. The converter word returned in the parameters section
2407 needs to be subtracted from the lower 16 bits to calculate an offset
2408 into the return buffer where this ASCII string resides.
2410 There is no auxiliary data in the response.
2412 ****************************************************************************/
2414 #define usri11_name 0
2415 #define usri11_pad 21
2416 #define usri11_comment 22
2417 #define usri11_usr_comment 26
2418 #define usri11_full_name 30
2419 #define usri11_priv 34
2420 #define usri11_auth_flags 36
2421 #define usri11_password_age 40
2422 #define usri11_homedir 44
2423 #define usri11_parms 48
2424 #define usri11_last_logon 52
2425 #define usri11_last_logoff 56
2426 #define usri11_bad_pw_count 60
2427 #define usri11_num_logons 62
2428 #define usri11_logon_server 64
2429 #define usri11_country_code 68
2430 #define usri11_workstations 70
2431 #define usri11_max_storage 74
2432 #define usri11_units_per_week 78
2433 #define usri11_logon_hours 80
2434 #define usri11_code_page 84
2435 #define usri11_end 86
2437 #define USER_PRIV_GUEST 0
2438 #define USER_PRIV_USER 1
2439 #define USER_PRIV_ADMIN 2
2441 #define AF_OP_PRINT 0
2442 #define AF_OP_COMM 1
2443 #define AF_OP_SERVER 2
2444 #define AF_OP_ACCOUNTS 3
2447 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2448 int mdrcnt,int mprcnt,
2449 char **rdata,char **rparam,
2450 int *rdata_len,int *rparam_len)
2452 char *str1 = param+2;
2453 char *str2 = skip_string(str1,1);
2454 char *UserName = skip_string(str2,1);
2455 char *p = skip_string(UserName,1);
2456 int uLevel = SVAL(p,0);
2457 char *p2;
2459 /* get NIS home of a previously validated user - simeon */
2460 /* With share level security vuid will always be zero.
2461 Don't depend on vuser being non-null !!. JRA */
2462 user_struct *vuser = get_valid_user_struct(vuid);
2463 if(vuser != NULL)
2464 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
2465 vuser->user.unix_name));
2467 *rparam_len = 6;
2468 *rparam = REALLOC(*rparam,*rparam_len);
2470 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2472 /* check it's a supported variant */
2473 if (strcmp(str1,"zWrLh") != 0) return False;
2474 switch( uLevel )
2476 case 0: p2 = "B21"; break;
2477 case 1: p2 = "B21BB16DWzzWz"; break;
2478 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2479 case 10: p2 = "B21Bzzz"; break;
2480 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2481 default: return False;
2484 if (strcmp(p2,str2) != 0) return False;
2486 *rdata_len = mdrcnt + 1024;
2487 *rdata = REALLOC(*rdata,*rdata_len);
2489 SSVAL(*rparam,0,NERR_Success);
2490 SSVAL(*rparam,2,0); /* converter word */
2492 p = *rdata;
2493 p2 = p + usri11_end;
2495 memset(p,0,21);
2496 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2498 if (uLevel > 0)
2500 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2501 *p2 = 0;
2503 if (uLevel >= 10)
2505 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2506 pstrcpy(p2,"Comment");
2507 p2 = skip_string(p2,1);
2509 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2510 pstrcpy(p2,"UserComment");
2511 p2 = skip_string(p2,1);
2513 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2514 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2515 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2516 p2 = skip_string(p2,1);
2519 if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2521 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2522 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
2523 SIVALS(p,usri11_password_age,-1); /* password age */
2524 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2525 pstrcpy(p2, lp_logon_home());
2526 standard_sub_conn(conn, p2,*rdata_len-(p2 - *rdata));
2527 p2 = skip_string(p2,1);
2528 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2529 pstrcpy(p2,"");
2530 p2 = skip_string(p2,1);
2531 SIVAL(p,usri11_last_logon,0); /* last logon */
2532 SIVAL(p,usri11_last_logoff,0); /* last logoff */
2533 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
2534 SSVALS(p,usri11_num_logons,-1); /* num logons */
2535 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2536 pstrcpy(p2,"\\\\*");
2537 p2 = skip_string(p2,1);
2538 SSVAL(p,usri11_country_code,0); /* country code */
2540 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2541 pstrcpy(p2,"");
2542 p2 = skip_string(p2,1);
2544 SIVALS(p,usri11_max_storage,-1); /* max storage */
2545 SSVAL(p,usri11_units_per_week,168); /* units per week */
2546 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2548 /* a simple way to get logon hours at all times. */
2549 memset(p2,0xff,21);
2550 SCVAL(p2,21,0); /* fix zero termination */
2551 p2 = skip_string(p2,1);
2553 SSVAL(p,usri11_code_page,0); /* code page */
2555 if (uLevel == 1 || uLevel == 2)
2557 memset(p+22,' ',16); /* password */
2558 SIVALS(p,38,-1); /* password age */
2559 SSVAL(p,42,
2560 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2561 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2562 pstrcpy(p2,lp_logon_home());
2563 standard_sub_conn(conn, p2,*rdata_len-(p2 - *rdata));
2564 p2 = skip_string(p2,1);
2565 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2566 *p2++ = 0;
2567 SSVAL(p,52,0); /* flags */
2568 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
2569 pstrcpy(p2,lp_logon_script());
2570 standard_sub_conn( conn, p2,*rdata_len-(p2 - *rdata));
2571 p2 = skip_string(p2,1);
2572 if (uLevel == 2)
2574 SIVAL(p,60,0); /* auth_flags */
2575 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2576 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2577 p2 = skip_string(p2,1);
2578 SIVAL(p,68,0); /* urs_comment */
2579 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2580 pstrcpy(p2,"");
2581 p2 = skip_string(p2,1);
2582 SIVAL(p,76,0); /* workstations */
2583 SIVAL(p,80,0); /* last_logon */
2584 SIVAL(p,84,0); /* last_logoff */
2585 SIVALS(p,88,-1); /* acct_expires */
2586 SIVALS(p,92,-1); /* max_storage */
2587 SSVAL(p,96,168); /* units_per_week */
2588 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2589 memset(p2,-1,21);
2590 p2 += 21;
2591 SSVALS(p,102,-1); /* bad_pw_count */
2592 SSVALS(p,104,-1); /* num_logons */
2593 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2594 pstrcpy(p2,"\\\\%L");
2595 standard_sub_conn(conn, p2,*rdata_len-(p2 - *rdata));
2596 p2 = skip_string(p2,1);
2597 SSVAL(p,110,49); /* country_code */
2598 SSVAL(p,112,860); /* code page */
2602 *rdata_len = PTR_DIFF(p2,*rdata);
2604 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
2606 return(True);
2609 /*******************************************************************
2610 get groups that a user is a member of
2611 ******************************************************************/
2612 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2613 int mdrcnt,int mprcnt,
2614 char **rdata,char **rparam,
2615 int *rdata_len,int *rparam_len)
2617 char *str1 = param+2;
2618 char *str2 = skip_string(str1,1);
2619 char *UserName = skip_string(str2,1);
2620 char *p = skip_string(UserName,1);
2621 int uLevel = SVAL(p,0);
2622 char *p2;
2623 int count=0;
2625 *rparam_len = 8;
2626 *rparam = REALLOC(*rparam,*rparam_len);
2628 /* check it's a supported varient */
2629 if (strcmp(str1,"zWrLeh") != 0) return False;
2630 switch( uLevel ) {
2631 case 0: p2 = "B21"; break;
2632 default: return False;
2634 if (strcmp(p2,str2) != 0) return False;
2636 *rdata_len = mdrcnt + 1024;
2637 *rdata = REALLOC(*rdata,*rdata_len);
2639 SSVAL(*rparam,0,NERR_Success);
2640 SSVAL(*rparam,2,0); /* converter word */
2642 p = *rdata;
2644 /* XXXX we need a real SAM database some day */
2645 pstrcpy(p,"Users"); p += 21; count++;
2646 pstrcpy(p,"Domain Users"); p += 21; count++;
2647 pstrcpy(p,"Guests"); p += 21; count++;
2648 pstrcpy(p,"Domain Guests"); p += 21; count++;
2650 *rdata_len = PTR_DIFF(p,*rdata);
2652 SSVAL(*rparam,4,count); /* is this right?? */
2653 SSVAL(*rparam,6,count); /* is this right?? */
2655 return(True);
2659 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2660 int mdrcnt,int mprcnt,
2661 char **rdata,char **rparam,
2662 int *rdata_len,int *rparam_len)
2664 char *str1 = param+2;
2665 char *str2 = skip_string(str1,1);
2666 char *p = skip_string(str2,1);
2667 int uLevel;
2668 struct pack_desc desc;
2669 char* name;
2671 uLevel = SVAL(p,0);
2672 name = p + 2;
2674 memset((char *)&desc,'\0',sizeof(desc));
2676 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2678 /* check it's a supported varient */
2679 if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2680 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2681 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2682 desc.base = *rdata;
2683 desc.buflen = mdrcnt;
2684 desc.subformat = NULL;
2685 desc.format = str2;
2687 if (init_package(&desc,1,0))
2689 PACKI(&desc,"W",0); /* code */
2690 PACKS(&desc,"B21",name); /* eff. name */
2691 PACKS(&desc,"B",""); /* pad */
2692 PACKI(&desc,"W",
2693 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2694 PACKI(&desc,"D",0); /* auth flags XXX */
2695 PACKI(&desc,"W",0); /* num logons */
2696 PACKI(&desc,"W",0); /* bad pw count */
2697 PACKI(&desc,"D",0); /* last logon */
2698 PACKI(&desc,"D",-1); /* last logoff */
2699 PACKI(&desc,"D",-1); /* logoff time */
2700 PACKI(&desc,"D",-1); /* kickoff time */
2701 PACKI(&desc,"D",0); /* password age */
2702 PACKI(&desc,"D",0); /* password can change */
2703 PACKI(&desc,"D",-1); /* password must change */
2705 fstring mypath;
2706 fstrcpy(mypath,"\\\\");
2707 fstrcat(mypath,local_machine);
2708 strupper(mypath);
2709 PACKS(&desc,"z",mypath); /* computer */
2711 PACKS(&desc,"z",global_myworkgroup);/* domain */
2713 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2714 /* made sure all macros are fully substituted and available */
2716 pstring logon_script;
2717 pstrcpy(logon_script,lp_logon_script());
2718 standard_sub_conn( conn, logon_script,sizeof(logon_script) );
2719 PACKS(&desc,"z", logon_script); /* script path */
2721 /* End of JHT mods */
2723 PACKI(&desc,"D",0x00000000); /* reserved */
2726 *rdata_len = desc.usedlen;
2727 *rparam_len = 6;
2728 *rparam = REALLOC(*rparam,*rparam_len);
2729 SSVALS(*rparam,0,desc.errcode);
2730 SSVAL(*rparam,2,0);
2731 SSVAL(*rparam,4,desc.neededlen);
2733 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2734 return(True);
2738 /****************************************************************************
2739 api_WAccessGetUserPerms
2740 ****************************************************************************/
2741 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2742 int mdrcnt,int mprcnt,
2743 char **rdata,char **rparam,
2744 int *rdata_len,int *rparam_len)
2746 char *str1 = param+2;
2747 char *str2 = skip_string(str1,1);
2748 char *user = skip_string(str2,1);
2749 char *resource = skip_string(user,1);
2751 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2753 /* check it's a supported varient */
2754 if (strcmp(str1,"zzh") != 0) return False;
2755 if (strcmp(str2,"") != 0) return False;
2757 *rparam_len = 6;
2758 *rparam = REALLOC(*rparam,*rparam_len);
2759 SSVALS(*rparam,0,0); /* errorcode */
2760 SSVAL(*rparam,2,0); /* converter word */
2761 SSVAL(*rparam,4,0x7f); /* permission flags */
2763 return(True);
2766 /****************************************************************************
2767 api_WPrintJobEnumerate
2768 ****************************************************************************/
2769 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2770 int mdrcnt,int mprcnt,
2771 char **rdata,char **rparam,
2772 int *rdata_len,int *rparam_len)
2774 char *str1 = param+2;
2775 char *str2 = skip_string(str1,1);
2776 char *p = skip_string(str2,1);
2777 int uLevel;
2778 int count;
2779 int i;
2780 int snum;
2781 int job;
2782 struct pack_desc desc;
2783 print_queue_struct *queue=NULL;
2784 print_status_struct status;
2785 char *tmpdata=NULL;
2787 uLevel = SVAL(p,2);
2789 memset((char *)&desc,'\0',sizeof(desc));
2790 memset((char *)&status,'\0',sizeof(status));
2792 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2794 /* check it's a supported varient */
2795 if (strcmp(str1,"WWrLh") != 0) return False;
2796 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2798 job = SVAL(p,0);
2799 snum = print_job_snum(job);
2801 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2803 count = print_queue_status(snum,&queue,&status);
2804 for (i = 0; i < count; i++) {
2805 if (queue[i].job == job) break;
2808 if (mdrcnt > 0) {
2809 *rdata = REALLOC(*rdata,mdrcnt);
2810 desc.base = *rdata;
2811 desc.buflen = mdrcnt;
2812 } else {
2814 * Don't return data but need to get correct length
2815 * init_package will return wrong size if buflen=0
2817 desc.buflen = getlen(desc.format);
2818 desc.base = tmpdata = (char *)malloc ( desc.buflen );
2821 if (init_package(&desc,1,0)) {
2822 if (i < count) {
2823 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2824 *rdata_len = desc.usedlen;
2826 else {
2827 desc.errcode = NERR_JobNotFound;
2828 *rdata_len = 0;
2832 *rparam_len = 6;
2833 *rparam = REALLOC(*rparam,*rparam_len);
2834 SSVALS(*rparam,0,desc.errcode);
2835 SSVAL(*rparam,2,0);
2836 SSVAL(*rparam,4,desc.neededlen);
2838 SAFE_FREE(queue);
2839 SAFE_FREE(tmpdata);
2841 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2842 return(True);
2845 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2846 int mdrcnt,int mprcnt,
2847 char **rdata,char **rparam,
2848 int *rdata_len,int *rparam_len)
2850 char *str1 = param+2;
2851 char *str2 = skip_string(str1,1);
2852 char *p = skip_string(str2,1);
2853 char* name = p;
2854 int uLevel;
2855 int count;
2856 int i, succnt=0;
2857 int snum;
2858 struct pack_desc desc;
2859 print_queue_struct *queue=NULL;
2860 print_status_struct status;
2862 memset((char *)&desc,'\0',sizeof(desc));
2863 memset((char *)&status,'\0',sizeof(status));
2865 p = skip_string(p,1);
2866 uLevel = SVAL(p,0);
2868 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2870 /* check it's a supported varient */
2871 if (strcmp(str1,"zWrLeh") != 0) return False;
2872 if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2873 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2875 snum = lp_servicenumber(name);
2876 if (snum < 0 && pcap_printername_ok(name,NULL)) {
2877 int pnum = lp_servicenumber(PRINTERS_NAME);
2878 if (pnum >= 0) {
2879 lp_add_printer(name,pnum);
2880 snum = lp_servicenumber(name);
2884 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2886 count = print_queue_status(snum,&queue,&status);
2887 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2888 desc.base = *rdata;
2889 desc.buflen = mdrcnt;
2891 if (init_package(&desc,count,0)) {
2892 succnt = 0;
2893 for (i = 0; i < count; i++) {
2894 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2895 if (desc.errcode == NERR_Success) succnt = i+1;
2899 *rdata_len = desc.usedlen;
2901 *rparam_len = 8;
2902 *rparam = REALLOC(*rparam,*rparam_len);
2903 SSVALS(*rparam,0,desc.errcode);
2904 SSVAL(*rparam,2,0);
2905 SSVAL(*rparam,4,succnt);
2906 SSVAL(*rparam,6,count);
2908 SAFE_FREE(queue);
2910 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2911 return(True);
2914 static int check_printdest_info(struct pack_desc* desc,
2915 int uLevel, char* id)
2917 desc->subformat = NULL;
2918 switch( uLevel ) {
2919 case 0: desc->format = "B9"; break;
2920 case 1: desc->format = "B9B21WWzW"; break;
2921 case 2: desc->format = "z"; break;
2922 case 3: desc->format = "zzzWWzzzWW"; break;
2923 default: return False;
2925 if (strcmp(desc->format,id) != 0) return False;
2926 return True;
2929 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2930 struct pack_desc* desc)
2932 char buf[100];
2933 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2934 buf[sizeof(buf)-1] = 0;
2935 strupper(buf);
2936 if (uLevel <= 1) {
2937 PACKS(desc,"B9",buf); /* szName */
2938 if (uLevel == 1) {
2939 PACKS(desc,"B21",""); /* szUserName */
2940 PACKI(desc,"W",0); /* uJobId */
2941 PACKI(desc,"W",0); /* fsStatus */
2942 PACKS(desc,"z",""); /* pszStatus */
2943 PACKI(desc,"W",0); /* time */
2946 if (uLevel == 2 || uLevel == 3) {
2947 PACKS(desc,"z",buf); /* pszPrinterName */
2948 if (uLevel == 3) {
2949 PACKS(desc,"z",""); /* pszUserName */
2950 PACKS(desc,"z",""); /* pszLogAddr */
2951 PACKI(desc,"W",0); /* uJobId */
2952 PACKI(desc,"W",0); /* fsStatus */
2953 PACKS(desc,"z",""); /* pszStatus */
2954 PACKS(desc,"z",""); /* pszComment */
2955 PACKS(desc,"z","NULL"); /* pszDrivers */
2956 PACKI(desc,"W",0); /* time */
2957 PACKI(desc,"W",0); /* pad1 */
2962 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2963 int mdrcnt,int mprcnt,
2964 char **rdata,char **rparam,
2965 int *rdata_len,int *rparam_len)
2967 char *str1 = param+2;
2968 char *str2 = skip_string(str1,1);
2969 char *p = skip_string(str2,1);
2970 char* PrinterName = p;
2971 int uLevel;
2972 struct pack_desc desc;
2973 int snum;
2974 char *tmpdata=NULL;
2976 memset((char *)&desc,'\0',sizeof(desc));
2978 p = skip_string(p,1);
2979 uLevel = SVAL(p,0);
2981 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2983 /* check it's a supported varient */
2984 if (strcmp(str1,"zWrLh") != 0) return False;
2985 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2987 snum = lp_servicenumber(PrinterName);
2988 if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2989 int pnum = lp_servicenumber(PRINTERS_NAME);
2990 if (pnum >= 0) {
2991 lp_add_printer(PrinterName,pnum);
2992 snum = lp_servicenumber(PrinterName);
2996 if (snum < 0) {
2997 *rdata_len = 0;
2998 desc.errcode = NERR_DestNotFound;
2999 desc.neededlen = 0;
3001 else {
3002 if (mdrcnt > 0) {
3003 *rdata = REALLOC(*rdata,mdrcnt);
3004 desc.base = *rdata;
3005 desc.buflen = mdrcnt;
3006 } else {
3008 * Don't return data but need to get correct length
3009 * init_package will return wrong size if buflen=0
3011 desc.buflen = getlen(desc.format);
3012 desc.base = tmpdata = (char *)malloc ( desc.buflen );
3014 if (init_package(&desc,1,0)) {
3015 fill_printdest_info(conn,snum,uLevel,&desc);
3017 *rdata_len = desc.usedlen;
3020 *rparam_len = 6;
3021 *rparam = REALLOC(*rparam,*rparam_len);
3022 SSVALS(*rparam,0,desc.errcode);
3023 SSVAL(*rparam,2,0);
3024 SSVAL(*rparam,4,desc.neededlen);
3026 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
3027 SAFE_FREE(tmpdata);
3028 return(True);
3031 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3032 int mdrcnt,int mprcnt,
3033 char **rdata,char **rparam,
3034 int *rdata_len,int *rparam_len)
3036 char *str1 = param+2;
3037 char *str2 = skip_string(str1,1);
3038 char *p = skip_string(str2,1);
3039 int uLevel;
3040 int queuecnt;
3041 int i, n, succnt=0;
3042 struct pack_desc desc;
3043 int services = lp_numservices();
3045 memset((char *)&desc,'\0',sizeof(desc));
3047 uLevel = SVAL(p,0);
3049 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
3051 /* check it's a supported varient */
3052 if (strcmp(str1,"WrLeh") != 0) return False;
3053 if (!check_printdest_info(&desc,uLevel,str2)) return False;
3055 queuecnt = 0;
3056 for (i = 0; i < services; i++)
3057 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
3058 queuecnt++;
3060 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3061 desc.base = *rdata;
3062 desc.buflen = mdrcnt;
3063 if (init_package(&desc,queuecnt,0)) {
3064 succnt = 0;
3065 n = 0;
3066 for (i = 0; i < services; i++) {
3067 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
3068 fill_printdest_info(conn,i,uLevel,&desc);
3069 n++;
3070 if (desc.errcode == NERR_Success) succnt = n;
3075 *rdata_len = desc.usedlen;
3077 *rparam_len = 8;
3078 *rparam = REALLOC(*rparam,*rparam_len);
3079 SSVALS(*rparam,0,desc.errcode);
3080 SSVAL(*rparam,2,0);
3081 SSVAL(*rparam,4,succnt);
3082 SSVAL(*rparam,6,queuecnt);
3084 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3085 return(True);
3088 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3089 int mdrcnt,int mprcnt,
3090 char **rdata,char **rparam,
3091 int *rdata_len,int *rparam_len)
3093 char *str1 = param+2;
3094 char *str2 = skip_string(str1,1);
3095 char *p = skip_string(str2,1);
3096 int uLevel;
3097 int succnt;
3098 struct pack_desc desc;
3100 memset((char *)&desc,'\0',sizeof(desc));
3102 uLevel = SVAL(p,0);
3104 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3106 /* check it's a supported varient */
3107 if (strcmp(str1,"WrLeh") != 0) return False;
3108 if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3110 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3111 desc.base = *rdata;
3112 desc.buflen = mdrcnt;
3113 if (init_package(&desc,1,0)) {
3114 PACKS(&desc,"B41","NULL");
3117 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3119 *rdata_len = desc.usedlen;
3121 *rparam_len = 8;
3122 *rparam = REALLOC(*rparam,*rparam_len);
3123 SSVALS(*rparam,0,desc.errcode);
3124 SSVAL(*rparam,2,0);
3125 SSVAL(*rparam,4,succnt);
3126 SSVAL(*rparam,6,1);
3128 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3129 return(True);
3132 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3133 int mdrcnt,int mprcnt,
3134 char **rdata,char **rparam,
3135 int *rdata_len,int *rparam_len)
3137 char *str1 = param+2;
3138 char *str2 = skip_string(str1,1);
3139 char *p = skip_string(str2,1);
3140 int uLevel;
3141 int succnt;
3142 struct pack_desc desc;
3144 memset((char *)&desc,'\0',sizeof(desc));
3146 uLevel = SVAL(p,0);
3148 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3150 /* check it's a supported varient */
3151 if (strcmp(str1,"WrLeh") != 0) return False;
3152 if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3154 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3155 desc.base = *rdata;
3156 desc.buflen = mdrcnt;
3157 desc.format = str2;
3158 if (init_package(&desc,1,0)) {
3159 PACKS(&desc,"B13","lpd");
3162 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3164 *rdata_len = desc.usedlen;
3166 *rparam_len = 8;
3167 *rparam = REALLOC(*rparam,*rparam_len);
3168 SSVALS(*rparam,0,desc.errcode);
3169 SSVAL(*rparam,2,0);
3170 SSVAL(*rparam,4,succnt);
3171 SSVAL(*rparam,6,1);
3173 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3174 return(True);
3177 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3178 int mdrcnt,int mprcnt,
3179 char **rdata,char **rparam,
3180 int *rdata_len,int *rparam_len)
3182 char *str1 = param+2;
3183 char *str2 = skip_string(str1,1);
3184 char *p = skip_string(str2,1);
3185 int uLevel;
3186 int succnt;
3187 struct pack_desc desc;
3189 memset((char *)&desc,'\0',sizeof(desc));
3191 uLevel = SVAL(p,0);
3193 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3195 /* check it's a supported varient */
3196 if (strcmp(str1,"WrLeh") != 0) return False;
3197 if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3199 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3200 memset((char *)&desc,'\0',sizeof(desc));
3201 desc.base = *rdata;
3202 desc.buflen = mdrcnt;
3203 desc.format = str2;
3204 if (init_package(&desc,1,0)) {
3205 PACKS(&desc,"B13","lp0");
3208 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3210 *rdata_len = desc.usedlen;
3212 *rparam_len = 8;
3213 *rparam = REALLOC(*rparam,*rparam_len);
3214 SSVALS(*rparam,0,desc.errcode);
3215 SSVAL(*rparam,2,0);
3216 SSVAL(*rparam,4,succnt);
3217 SSVAL(*rparam,6,1);
3219 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3220 return(True);
3223 /****************************************************************************
3224 The buffer was too small
3225 ****************************************************************************/
3227 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3228 int mdrcnt,int mprcnt,
3229 char **rdata,char **rparam,
3230 int *rdata_len,int *rparam_len)
3232 *rparam_len = MIN(*rparam_len,mprcnt);
3233 *rparam = REALLOC(*rparam,*rparam_len);
3235 *rdata_len = 0;
3237 SSVAL(*rparam,0,NERR_BufTooSmall);
3239 DEBUG(3,("Supplied buffer too small in API command\n"));
3241 return(True);
3245 /****************************************************************************
3246 The request is not supported
3247 ****************************************************************************/
3249 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3250 int mdrcnt,int mprcnt,
3251 char **rdata,char **rparam,
3252 int *rdata_len,int *rparam_len)
3254 *rparam_len = 4;
3255 *rparam = REALLOC(*rparam,*rparam_len);
3257 *rdata_len = 0;
3259 SSVAL(*rparam,0,NERR_notsupported);
3260 SSVAL(*rparam,2,0); /* converter word */
3262 DEBUG(3,("Unsupported API command\n"));
3264 return(True);
3270 struct
3272 char *name;
3273 int id;
3274 BOOL (*fn)(connection_struct *,uint16,char *,char *,
3275 int,int,char **,char **,int *,int *);
3276 int flags;
3277 } api_commands[] = {
3278 {"RNetShareEnum", RAP_WshareEnum, api_RNetShareEnum,0},
3279 {"RNetShareGetInfo", RAP_WshareGetInfo, api_RNetShareGetInfo,0},
3280 #if 0 /* Not yet implemented. */
3281 {"RNetShareAdd", RAP_WshareAdd, api_RNetShareAdd,0},
3282 #endif
3283 {"RNetServerGetInfo", RAP_WserverGetInfo, api_RNetServerGetInfo,0},
3284 #if 0 /* Not yet implemented. */
3285 {"RNetGroupEnum", RAP_WGroupEnum, api_RNetGroupEnum,0},
3286 #endif
3287 {"RNetGroupGetUsers", RAP_WGroupGetUsers, api_RNetGroupGetUsers,0},
3288 #if 0 /* Not yet implemented. */
3289 {"RNetUserEnum", RAP_WUserEnum, api_RNetUserEnum,0},
3290 #endif
3291 {"RNetUserGetInfo", RAP_WUserGetInfo, api_RNetUserGetInfo,0},
3292 {"NetUserGetGroups", RAP_WUserGetGroups, api_NetUserGetGroups,0},
3293 {"NetWkstaGetInfo", RAP_WWkstaGetInfo, api_NetWkstaGetInfo,0},
3294 {"DosPrintQEnum", RAP_WPrintQEnum, api_DosPrintQEnum,0},
3295 {"DosPrintQGetInfo", RAP_WPrintQGetInfo, api_DosPrintQGetInfo,0},
3296 {"WPrintQueuePause", RAP_WPrintQPause, api_WPrintQueueCtrl,0},
3297 {"WPrintQueueResume", RAP_WPrintQContinue, api_WPrintQueueCtrl,0},
3298 {"WPrintJobEnumerate",RAP_WPrintJobEnum, api_WPrintJobEnumerate,0},
3299 {"WPrintJobGetInfo", RAP_WPrintJobGetInfo, api_WPrintJobGetInfo,0},
3300 {"RDosPrintJobDel", RAP_WPrintJobDel, api_RDosPrintJobDel,0},
3301 {"RDosPrintJobPause", RAP_WPrintJobPause, api_RDosPrintJobDel,0},
3302 {"RDosPrintJobResume",RAP_WPrintJobContinue, api_RDosPrintJobDel,0},
3303 {"WPrintDestEnum", RAP_WPrintDestEnum, api_WPrintDestEnum,0},
3304 {"WPrintDestGetInfo", RAP_WPrintDestGetInfo, api_WPrintDestGetInfo,0},
3305 {"NetRemoteTOD", RAP_NetRemoteTOD, api_NetRemoteTOD,0},
3306 {"WPrintQueuePurge", RAP_WPrintQPurge, api_WPrintQueueCtrl,0},
3307 {"NetServerEnum", RAP_NetServerEnum2, api_RNetServerEnum,0},
3308 {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms,0},
3309 {"SetUserPassword", RAP_WUserPasswordSet2, api_SetUserPassword,0},
3310 {"WWkstaUserLogon", RAP_WWkstaUserLogon, api_WWkstaUserLogon,0},
3311 {"PrintJobInfo", RAP_WPrintJobSetInfo, api_PrintJobInfo,0},
3312 {"WPrintDriverEnum", RAP_WPrintDriverEnum, api_WPrintDriverEnum,0},
3313 {"WPrintQProcEnum", RAP_WPrintQProcessorEnum,api_WPrintQProcEnum,0},
3314 {"WPrintPortEnum", RAP_WPrintPortEnum, api_WPrintPortEnum,0},
3315 {"SamOEMChangePassword",RAP_SamOEMChgPasswordUser2_P,api_SamOEMChangePassword,0},
3316 {NULL, -1, api_Unsupported,0}};
3319 /****************************************************************************
3320 Handle remote api calls
3321 ****************************************************************************/
3323 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3324 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3326 int api_command;
3327 char *rdata = NULL;
3328 char *rparam = NULL;
3329 int rdata_len = 0;
3330 int rparam_len = 0;
3331 BOOL reply=False;
3332 int i;
3334 if (!params) {
3335 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3336 return 0;
3339 api_command = SVAL(params,0);
3341 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3342 api_command,
3343 params+2,
3344 skip_string(params+2,1),
3345 tdscnt,tpscnt,mdrcnt,mprcnt));
3347 for (i=0;api_commands[i].name;i++) {
3348 if (api_commands[i].id == api_command && api_commands[i].fn) {
3349 DEBUG(3,("Doing %s\n",api_commands[i].name));
3350 break;
3354 rdata = (char *)malloc(1024);
3355 if (rdata)
3356 memset(rdata,'\0',1024);
3358 rparam = (char *)malloc(1024);
3359 if (rparam)
3360 memset(rparam,'\0',1024);
3362 if(!rdata || !rparam) {
3363 DEBUG(0,("api_reply: malloc fail !\n"));
3364 return -1;
3367 reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3368 &rdata,&rparam,&rdata_len,&rparam_len);
3371 if (rdata_len > mdrcnt ||
3372 rparam_len > mprcnt) {
3373 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3374 &rdata,&rparam,&rdata_len,&rparam_len);
3377 /* if we get False back then it's actually unsupported */
3378 if (!reply)
3379 api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3380 &rdata,&rparam,&rdata_len,&rparam_len);
3382 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3384 SAFE_FREE(rdata);
3385 SAFE_FREE(rparam);
3387 return -1;