Fix for Win9x driver downloads when information is
[Samba.git] / source / smbd / lanman.c
blob712016285e41667216f7c5ac48f6b38d1f4137b6
1 #define OLD_NTDOMAIN 1
2 /*
3 Unix SMB/Netbios implementation.
4 Version 1.9.
5 Inter-process communication and named pipe handling
6 Copyright (C) Andrew Tridgell 1992-1998
8 SMB Version handling
9 Copyright (C) John H Terpstra 1995-1998
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 This file handles the named pipe and mailslot calls
27 in the SMBtrans protocol
30 #include "includes.h"
32 #ifdef CHECK_TYPES
33 #undef CHECK_TYPES
34 #endif
35 #define CHECK_TYPES 0
37 extern int DEBUGLEVEL;
39 extern fstring local_machine;
40 extern fstring global_myname;
41 extern fstring global_myworkgroup;
43 #define NERR_Success 0
44 #define NERR_badpass 86
45 #define NERR_notsupported 50
47 #define NERR_BASE (2100)
48 #define NERR_BufTooSmall (NERR_BASE+23)
49 #define NERR_JobNotFound (NERR_BASE+51)
50 #define NERR_DestNotFound (NERR_BASE+52)
52 #define ACCESS_READ 0x01
53 #define ACCESS_WRITE 0x02
54 #define ACCESS_CREATE 0x04
56 #define SHPWLEN 8 /* share password length */
58 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
59 int mdrcnt,int mprcnt,
60 char **rdata,char **rparam,
61 int *rdata_len,int *rparam_len);
62 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
63 int mdrcnt,int mprcnt,
64 char **rdata,char **rparam,
65 int *rdata_len,int *rparam_len);
68 static int CopyExpanded(connection_struct *conn,
69 int snum, char** dst, char* src, int* n)
71 pstring buf;
72 int l;
74 if (!src || !dst || !n || !(*dst)) return(0);
76 StrnCpy(buf,src,sizeof(buf)/2);
77 pstring_sub(buf,"%S",lp_servicename(snum));
78 standard_sub_conn(conn,buf);
79 StrnCpy(*dst,buf,*n);
80 l = strlen(*dst) + 1;
81 (*dst) += l;
82 (*n) -= l;
83 return l;
86 static int CopyAndAdvance(char** dst, char* src, int* n)
88 int l;
89 if (!src || !dst || !n || !(*dst)) return(0);
90 StrnCpy(*dst,src,*n-1);
91 l = strlen(*dst) + 1;
92 (*dst) += l;
93 (*n) -= l;
94 return l;
97 static int StrlenExpanded(connection_struct *conn, int snum, char* s)
99 pstring buf;
100 if (!s) return(0);
101 StrnCpy(buf,s,sizeof(buf)/2);
102 pstring_sub(buf,"%S",lp_servicename(snum));
103 standard_sub_conn(conn,buf);
104 return strlen(buf) + 1;
107 static char* Expand(connection_struct *conn, int snum, char* s)
109 static pstring buf;
110 if (!s) return(NULL);
111 StrnCpy(buf,s,sizeof(buf)/2);
112 pstring_sub(buf,"%S",lp_servicename(snum));
113 standard_sub_conn(conn,buf);
114 return &buf[0];
117 /*******************************************************************
118 check a API string for validity when we only need to check the prefix
119 ******************************************************************/
120 static BOOL prefix_ok(char *str,char *prefix)
122 return(strncmp(str,prefix,strlen(prefix)) == 0);
125 struct pack_desc {
126 char* format; /* formatstring for structure */
127 char* subformat; /* subformat for structure */
128 char* base; /* baseaddress of buffer */
129 int buflen; /* remaining size for fixed part; on init: length of base */
130 int subcount; /* count of substructures */
131 char* structbuf; /* pointer into buffer for remaining fixed part */
132 int stringlen; /* remaining size for variable part */
133 char* stringbuf; /* pointer into buffer for remaining variable part */
134 int neededlen; /* total needed size */
135 int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
136 char* curpos; /* current position; pointer into format or subformat */
137 int errcode;
140 static int get_counter(char** p)
142 int i, n;
143 if (!p || !(*p)) return(1);
144 if (!isdigit((int)**p)) return 1;
145 for (n = 0;;) {
146 i = **p;
147 if (isdigit(i))
148 n = 10 * n + (i - '0');
149 else
150 return n;
151 (*p)++;
155 static int getlen(char* p)
157 int n = 0;
158 if (!p) return(0);
159 while (*p) {
160 switch( *p++ ) {
161 case 'W': /* word (2 byte) */
162 n += 2;
163 break;
164 case 'K': /* status word? (2 byte) */
165 n += 2;
166 break;
167 case 'N': /* count of substructures (word) at end */
168 n += 2;
169 break;
170 case 'D': /* double word (4 byte) */
171 case 'z': /* offset to zero terminated string (4 byte) */
172 case 'l': /* offset to user data (4 byte) */
173 n += 4;
174 break;
175 case 'b': /* offset to data (with counter) (4 byte) */
176 n += 4;
177 get_counter(&p);
178 break;
179 case 'B': /* byte (with optional counter) */
180 n += get_counter(&p);
181 break;
184 return n;
187 static BOOL init_package(struct pack_desc* p, int count, int subcount)
189 int n = p->buflen;
190 int i;
192 if (!p->format || !p->base) return(False);
194 i = count * getlen(p->format);
195 if (p->subformat) i += subcount * getlen(p->subformat);
196 p->structbuf = p->base;
197 p->neededlen = 0;
198 p->usedlen = 0;
199 p->subcount = 0;
200 p->curpos = p->format;
201 if (i > n) {
202 p->neededlen = i;
203 i = n = 0;
204 p->errcode = ERRmoredata;
206 else
207 p->errcode = NERR_Success;
208 p->buflen = i;
209 n -= i;
210 p->stringbuf = p->base + i;
211 p->stringlen = n;
212 return(p->errcode == NERR_Success);
215 #ifdef HAVE_STDARG_H
216 static int package(struct pack_desc* p, ...)
218 #else
219 static int package(va_alist)
220 va_dcl
222 struct pack_desc* p;
223 #endif
224 va_list args;
225 int needed=0, stringneeded;
226 char* str=NULL;
227 int is_string=0, stringused;
228 int32 temp;
230 #ifdef HAVE_STDARG_H
231 va_start(args,p);
232 #else
233 va_start(args);
234 p = va_arg(args,struct pack_desc *);
235 #endif
237 if (!*p->curpos) {
238 if (!p->subcount)
239 p->curpos = p->format;
240 else {
241 p->curpos = p->subformat;
242 p->subcount--;
245 #if CHECK_TYPES
246 str = va_arg(args,char*);
247 SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
248 #endif
249 stringneeded = -1;
251 if (!p->curpos) {
252 va_end(args);
253 return(0);
256 switch( *p->curpos++ ) {
257 case 'W': /* word (2 byte) */
258 needed = 2;
259 temp = va_arg(args,int);
260 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
261 break;
262 case 'K': /* status word? (2 byte) */
263 needed = 2;
264 temp = va_arg(args,int);
265 if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
266 break;
267 case 'N': /* count of substructures (word) at end */
268 needed = 2;
269 p->subcount = va_arg(args,int);
270 if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
271 break;
272 case 'D': /* double word (4 byte) */
273 needed = 4;
274 temp = va_arg(args,int);
275 if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
276 break;
277 case 'B': /* byte (with optional counter) */
278 needed = get_counter(&p->curpos);
280 char *s = va_arg(args,char*);
281 if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
283 break;
284 case 'z': /* offset to zero terminated string (4 byte) */
285 str = va_arg(args,char*);
286 stringneeded = (str ? strlen(str)+1 : 0);
287 is_string = 1;
288 break;
289 case 'l': /* offset to user data (4 byte) */
290 str = va_arg(args,char*);
291 stringneeded = va_arg(args,int);
292 is_string = 0;
293 break;
294 case 'b': /* offset to data (with counter) (4 byte) */
295 str = va_arg(args,char*);
296 stringneeded = get_counter(&p->curpos);
297 is_string = 0;
298 break;
300 va_end(args);
301 if (stringneeded >= 0) {
302 needed = 4;
303 if (p->buflen >= needed) {
304 stringused = stringneeded;
305 if (stringused > p->stringlen) {
306 stringused = (is_string ? p->stringlen : 0);
307 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
309 if (!stringused)
310 SIVAL(p->structbuf,0,0);
311 else {
312 SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
313 memcpy(p->stringbuf,str?str:"",stringused);
314 if (is_string) p->stringbuf[stringused-1] = '\0';
315 p->stringbuf += stringused;
316 p->stringlen -= stringused;
317 p->usedlen += stringused;
320 p->neededlen += stringneeded;
322 p->neededlen += needed;
323 if (p->buflen >= needed) {
324 p->structbuf += needed;
325 p->buflen -= needed;
326 p->usedlen += needed;
328 else {
329 if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
331 return 1;
334 #if CHECK_TYPES
335 #define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
336 #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
337 #else
338 #define PACK(desc,t,v) package(desc,v)
339 #define PACKl(desc,t,v,l) package(desc,v,l)
340 #endif
342 static void PACKI(struct pack_desc* desc,char *t,int v)
344 PACK(desc,t,v);
347 static void PACKS(struct pack_desc* desc,char *t,char *v)
349 PACK(desc,t,v);
353 /****************************************************************************
354 get a print queue
355 ****************************************************************************/
356 static void PackDriverData(struct pack_desc* desc)
358 char drivdata[4+4+32];
359 SIVAL(drivdata,0,sizeof drivdata); /* cb */
360 SIVAL(drivdata,4,1000); /* lVersion */
361 memset(drivdata+8,0,32); /* szDeviceName */
362 pstrcpy(drivdata+8,"NULL");
363 PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
366 static int check_printq_info(struct pack_desc* desc,
367 int uLevel, char *id1, char *id2)
369 desc->subformat = NULL;
370 switch( uLevel ) {
371 case 0:
372 desc->format = "B13";
373 break;
374 case 1:
375 desc->format = "B13BWWWzzzzzWW";
376 break;
377 case 2:
378 desc->format = "B13BWWWzzzzzWN";
379 desc->subformat = "WB21BB16B10zWWzDDz";
380 break;
381 case 3:
382 desc->format = "zWWWWzzzzWWzzl";
383 break;
384 case 4:
385 desc->format = "zWWWWzzzzWNzzl";
386 desc->subformat = "WWzWWDDzz";
387 break;
388 case 5:
389 desc->format = "z";
390 break;
391 case 51:
392 desc->format = "K";
393 break;
394 case 52:
395 desc->format = "WzzzzzzzzN";
396 desc->subformat = "z";
397 break;
398 default: return False;
400 if (strcmp(desc->format,id1) != 0) return False;
401 if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
402 return True;
406 #define JOB_STATUS_QUEUED 0
407 #define JOB_STATUS_PAUSED 1
408 #define JOB_STATUS_SPOOLING 2
409 #define JOB_STATUS_PRINTING 3
410 #define JOB_STATUS_PRINTED 4
412 #define QUEUE_STATUS_PAUSED 1
413 #define QUEUE_STATUS_ERROR 2
415 /* turn a print job status into a on the wire status
417 static int printj_status(int v)
419 switch (v) {
420 case LPQ_QUEUED:
421 return JOB_STATUS_QUEUED;
422 case LPQ_PAUSED:
423 return JOB_STATUS_PAUSED;
424 case LPQ_SPOOLING:
425 return JOB_STATUS_SPOOLING;
426 case LPQ_PRINTING:
427 return JOB_STATUS_PRINTING;
429 return 0;
432 /* turn a print queue status into a on the wire status
434 static int printq_status(int v)
436 switch (v) {
437 case LPQ_QUEUED:
438 return 0;
439 case LPQ_PAUSED:
440 return QUEUE_STATUS_PAUSED;
442 return QUEUE_STATUS_ERROR;
445 static void fill_printjob_info(connection_struct *conn, int snum, int uLevel,
446 struct pack_desc* desc,
447 print_queue_struct* queue, int n)
449 time_t t = queue->time;
451 /* the client expects localtime */
452 t -= TimeDiff(t);
454 PACKI(desc,"W",queue->job); /* uJobId */
455 if (uLevel == 1) {
456 PACKS(desc,"B21",queue->user); /* szUserName */
457 PACKS(desc,"B",""); /* pad */
458 PACKS(desc,"B16",""); /* szNotifyName */
459 PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
460 PACKS(desc,"z",""); /* pszParms */
461 PACKI(desc,"W",n+1); /* uPosition */
462 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
463 PACKS(desc,"z",""); /* pszStatus */
464 PACKI(desc,"D",t); /* ulSubmitted */
465 PACKI(desc,"D",queue->size); /* ulSize */
466 PACKS(desc,"z",queue->file); /* pszComment */
468 if (uLevel == 2 || uLevel == 3) {
469 PACKI(desc,"W",queue->priority); /* uPriority */
470 PACKS(desc,"z",queue->user); /* pszUserName */
471 PACKI(desc,"W",n+1); /* uPosition */
472 PACKI(desc,"W",printj_status(queue->status)); /* fsStatus */
473 PACKI(desc,"D",t); /* ulSubmitted */
474 PACKI(desc,"D",queue->size); /* ulSize */
475 PACKS(desc,"z","Samba"); /* pszComment */
476 PACKS(desc,"z",queue->file); /* pszDocument */
477 if (uLevel == 3) {
478 PACKS(desc,"z",""); /* pszNotifyName */
479 PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
480 PACKS(desc,"z",""); /* pszParms */
481 PACKS(desc,"z",""); /* pszStatus */
482 PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
483 PACKS(desc,"z","lpd"); /* pszQProcName */
484 PACKS(desc,"z",""); /* pszQProcParms */
485 PACKS(desc,"z","NULL"); /* pszDriverName */
486 PackDriverData(desc); /* pDriverData */
487 PACKS(desc,"z",""); /* pszPrinterName */
492 /********************************************************************
493 Respond to the DosPrintQInfo command with a level of 52
494 This is used to get printer driver information for Win9x clients
495 ********************************************************************/
496 static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
497 struct pack_desc* desc,
498 int count, print_queue_struct* queue,
499 print_status_struct* status)
501 int i;
502 BOOL ok;
503 pstring tok,driver,datafile,langmon,helpfile,datatype;
504 char *p;
505 char **lines = NULL;
506 pstring gen_line;
507 NT_PRINTER_INFO_LEVEL *info = NULL;
508 BOOL in_tdb = False;
509 fstring location;
512 * Check in the tdb *first* before checking the legacy
513 * files. This allows an NT upload to take precedence over
514 * the existing fileset. JRA.
516 * we need to lookup the driver name prior to making the call
517 * to get_a_printer_driver_9x_compatible() and not rely on the
518 * 'print driver' parameter --jerry
521 get_a_printer (&info, 2, lp_servicename(snum));
522 if ((info != NULL) &&
523 ((ok = get_a_printer_driver_9x_compatible(gen_line, info->info_2->drivername)) == True))
525 in_tdb = True;
526 p = gen_line;
527 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n",
528 info->info_2->drivername, gen_line));
530 else
532 /* didn't find driver in tdb */
534 DEBUG(10,("snum: %d\nlp_printerdriver: [%s]\nlp_driverfile: [%s]\n",
535 snum, lp_printerdriver(snum), lp_driverfile(snum)));
537 lines = file_lines_load(lp_driverfile(snum),NULL);
538 if (!lines)
540 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
541 strerror(errno)));
542 desc->errcode=NERR_notsupported;
543 return;
545 else
547 /* lookup the long printer driver name in the file description */
548 for (i=0;lines[i] && !ok;i++)
550 p = lines[i];
551 if (next_token(&p,tok,":",sizeof(tok)) &&
552 (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
553 (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
554 ok = True;
559 if (ok)
561 /* driver file name */
562 if (!next_token(&p,driver,":",sizeof(driver)))
563 goto err;
565 /* data file name */
566 if (!next_token(&p,datafile,":",sizeof(datafile)))
567 goto err;
570 * for the next tokens - which may be empty - I have
571 * to check for empty tokens first because the
572 * next_token function will skip all empty token
573 * fields */
575 /* help file */
576 if (*p == ':')
578 *helpfile = '\0';
579 p++;
581 else if (!next_token(&p,helpfile,":",sizeof(helpfile)))
582 goto err;
584 /* language monitor */
585 if (*p == ':')
587 *langmon = '\0';
588 p++;
590 else if (!next_token(&p,langmon,":",sizeof(langmon)))
591 goto err;
593 /* default data type */
594 if (!next_token(&p,datatype,":",sizeof(datatype)))
595 goto err;
597 PACKI(desc,"W",0x0400); /* don't know */
598 if (in_tdb)
600 PACKS(desc,"z",info->info_2->drivername); /* long printer name */
602 else
604 PACKS(desc,"z",lp_printerdriver(snum)); /* long printer name */
606 PACKS(desc,"z",driver); /* Driverfile Name */
607 PACKS(desc,"z",datafile); /* Datafile name */
608 PACKS(desc,"z",langmon); /* language monitor */
609 if (in_tdb)
611 fstrcpy(location, "\\\\");
612 fstrcat(location, global_myname);
613 fstrcat(location, "\\print$\\WIN40\\0");
614 PACKS(desc,"z",location); /* share to retrieve files */
616 else
618 PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */
620 PACKS(desc,"z",datatype); /* default data type */
621 PACKS(desc,"z",helpfile); /* helpfile name */
622 PACKS(desc,"z",driver); /* driver name */
624 if (in_tdb)
625 DEBUG(3,("lp_printerdriver:%s:\n",info->info_2->drivername));
626 else
627 DEBUG(3,("lp_printerdriver:%s:\n",lp_printerdriver(snum)));
629 DEBUG(3,("Driver:%s:\n",driver));
630 DEBUG(3,("Data File:%s:\n",datafile));
631 DEBUG(3,("Language Monitor:%s:\n",langmon));
632 if (in_tdb)
633 DEBUG(3,("lp_driverlocation:%s:\n",location));
634 else
635 DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
636 DEBUG(3,("Data Type:%s:\n",datatype));
637 DEBUG(3,("Help File:%s:\n",helpfile));
638 PACKI(desc,"N",count); /* number of files to copy */
640 for (i=0;i<count;i++)
642 /* no need to check return value here
643 * - it was already tested in
644 * get_printerdrivernumber */
645 next_token(&p,tok,",",sizeof(tok));
646 PACKS(desc,"z",tok); /* driver files to copy */
647 DEBUG(3,("file:%s:\n",tok));
650 DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
651 SERVICE(snum),count));
653 desc->errcode=NERR_Success;
654 file_lines_free(lines);
655 return;
658 err:
660 DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
661 desc->errcode=NERR_notsupported;
662 file_lines_free(lines);
666 static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
667 struct pack_desc* desc,
668 int count, print_queue_struct* queue,
669 print_status_struct* status)
671 switch (uLevel) {
672 case 1:
673 case 2:
674 PACKS(desc,"B13",SERVICE(snum));
675 break;
676 case 3:
677 case 4:
678 case 5:
679 PACKS(desc,"z",Expand(conn,snum,SERVICE(snum)));
680 break;
681 case 51:
682 PACKI(desc,"K",printq_status(status->status));
683 break;
686 if (uLevel == 1 || uLevel == 2) {
687 PACKS(desc,"B",""); /* alignment */
688 PACKI(desc,"W",5); /* priority */
689 PACKI(desc,"W",0); /* start time */
690 PACKI(desc,"W",0); /* until time */
691 PACKS(desc,"z",""); /* pSepFile */
692 PACKS(desc,"z","lpd"); /* pPrProc */
693 PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
694 PACKS(desc,"z",""); /* pParms */
695 if (snum < 0) {
696 PACKS(desc,"z","UNKNOWN PRINTER");
697 PACKI(desc,"W",LPSTAT_ERROR);
699 else if (!status || !status->message[0]) {
700 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
701 PACKI(desc,"W",LPSTAT_OK); /* status */
702 } else {
703 PACKS(desc,"z",status->message);
704 PACKI(desc,"W",printq_status(status->status)); /* status */
706 PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
709 if (uLevel == 3 || uLevel == 4) {
710 PACKI(desc,"W",5); /* uPriority */
711 PACKI(desc,"W",0); /* uStarttime */
712 PACKI(desc,"W",0); /* uUntiltime */
713 PACKI(desc,"W",5); /* pad1 */
714 PACKS(desc,"z",""); /* pszSepFile */
715 PACKS(desc,"z","WinPrint"); /* pszPrProc */
716 PACKS(desc,"z",""); /* pszParms */
717 if (!status || !status->message[0]) {
718 PACKS(desc,"z",Expand(conn,snum,lp_comment(snum))); /* pszComment */
719 PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
720 } else {
721 PACKS(desc,"z",status->message); /* pszComment */
722 PACKI(desc,"W",printq_status(status->status)); /* fsStatus */
724 PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
725 PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
726 PACKS(desc,"z",lp_printerdriver(snum)); /* pszDriverName */
727 PackDriverData(desc); /* pDriverData */
730 if (uLevel == 2 || uLevel == 4) {
731 int i;
732 for (i=0;i<count;i++)
733 fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
736 if (uLevel==52) {
737 fill_printq_info_52(conn, snum, uLevel, desc, count, queue, status);
741 /* This function returns the number of files for a given driver */
742 static int get_printerdrivernumber(int snum)
744 int i;
745 BOOL ok;
746 pstring tok;
747 char *p;
748 char **lines = NULL;
749 pstring gen_line;
750 NT_PRINTER_INFO_LEVEL *info = NULL;
753 * Check in the tdb *first* before checking the legacy
754 * files. This allows an NT upload to take precedence over
755 * the existing fileset. JRA.
757 * we need to lookup the driver name prior to making the call
758 * to get_a_printer_driver_9x_compatible() and not rely on the
759 * 'print driver' parameter --jerry
762 get_a_printer (&info, 2, lp_servicename(snum));
763 if ((info != NULL) &&
764 (ok = get_a_printer_driver_9x_compatible(gen_line, info->info_2->drivername) == True))
766 p = gen_line;
767 DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", lp_printerdriver(snum), gen_line));
769 else
771 /* didn't find driver in tdb */
773 DEBUG(10,("snum: %d\nlp_printerdriver: [%s]\nlp_driverfile: [%s]\n",
774 snum, lp_printerdriver(snum), lp_driverfile(snum)));
776 lines = file_lines_load(lp_driverfile(snum), NULL);
777 if (!lines)
779 DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
781 else
783 /* lookup the long printer driver name in the file description */
784 for (i=0;lines[i] && !ok;i++)
786 p = lines[i];
787 if (next_token(&p,tok,":",sizeof(tok)) &&
788 (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
789 (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
790 ok = True;
795 if( ok )
797 /* skip 5 fields */
798 i = 5;
799 while (*p && i) {
800 if (*p++ == ':') i--;
802 if (!*p || i)
803 goto err;
805 /* count the number of files */
806 while (next_token(&p,tok,",",sizeof(tok)))
807 i++;
809 file_lines_free(lines);
810 return(i);
813 err:
815 DEBUG(3,("Can't determine number of printer driver files\n"));
816 file_lines_free(lines);
817 return (0);
820 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
821 uint16 vuid, char *param,char *data,
822 int mdrcnt,int mprcnt,
823 char **rdata,char **rparam,
824 int *rdata_len,int *rparam_len)
826 char *str1 = param+2;
827 char *str2 = skip_string(str1,1);
828 char *p = skip_string(str2,1);
829 char *QueueName = p;
830 int uLevel;
831 int count=0;
832 int snum;
833 char* str3;
834 struct pack_desc desc;
835 print_queue_struct *queue=NULL;
836 print_status_struct status;
838 memset((char *)&status,'\0',sizeof(status));
839 memset((char *)&desc,'\0',sizeof(desc));
841 p = skip_string(p,1);
842 uLevel = SVAL(p,0);
843 str3 = p + 4;
845 /* remove any trailing username */
846 if ((p = strchr(QueueName,'%'))) *p = 0;
848 DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
850 /* check it's a supported varient */
851 if (!prefix_ok(str1,"zWrLh")) return False;
852 if (!check_printq_info(&desc,uLevel,str2,str3)) {
854 * Patch from Scott Moomaw <scott@bridgewater.edu>
855 * to return the 'invalid info level' error if an
856 * unknown level was requested.
858 *rdata_len = 0;
859 *rparam_len = 6;
860 *rparam = REALLOC(*rparam,*rparam_len);
861 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
862 SSVAL(*rparam,2,0);
863 SSVAL(*rparam,4,0);
864 return(True);
867 snum = lp_servicenumber(QueueName);
868 if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
869 int pnum = lp_servicenumber(PRINTERS_NAME);
870 if (pnum >= 0) {
871 lp_add_printer(QueueName,pnum);
872 snum = lp_servicenumber(QueueName);
876 if (snum < 0 || !VALID_SNUM(snum)) return(False);
878 if (uLevel==52) {
879 count = get_printerdrivernumber(snum);
880 DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
881 } else {
882 count = print_queue_status(snum, &queue,&status);
885 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
886 desc.base = *rdata;
887 desc.buflen = mdrcnt;
888 if (init_package(&desc,1,count)) {
889 desc.subcount = count;
890 fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
891 } else if(uLevel == 0) {
892 #if 0
894 * This is a *disgusting* hack.
895 * This is *so* bad that even I'm embarrassed (and I
896 * have no shame). Here's the deal :
897 * Until we get the correct SPOOLSS code into smbd
898 * then when we're running with NT SMB support then
899 * NT makes this call with a level of zero, and then
900 * immediately follows it with an open request to
901 * the \\SRVSVC pipe. If we allow that open to
902 * succeed then NT barfs when it cannot open the
903 * \\SPOOLSS pipe immediately after and continually
904 * whines saying "Printer name is invalid" forever
905 * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
906 * to fail, then NT downgrades to using the downlevel code
907 * and everything works as well as before. I hate
908 * myself for adding this code.... JRA.
911 fail_next_srvsvc_open();
912 #endif
915 *rdata_len = desc.usedlen;
917 *rparam_len = 6;
918 *rparam = REALLOC(*rparam,*rparam_len);
919 SSVALS(*rparam,0,desc.errcode);
920 SSVAL(*rparam,2,0);
921 SSVAL(*rparam,4,desc.neededlen);
923 DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
925 if (queue) free(queue);
927 return(True);
930 /****************************************************************************
931 View list of all print jobs on all queues.
932 ****************************************************************************/
934 static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
935 int mdrcnt, int mprcnt,
936 char **rdata, char** rparam,
937 int *rdata_len, int *rparam_len)
939 char *param_format = param+2;
940 char *output_format1 = skip_string(param_format,1);
941 char *p = skip_string(output_format1,1);
942 int uLevel = SVAL(p,0);
943 char *output_format2 = p + 4;
944 int services = lp_numservices();
945 int i, n;
946 struct pack_desc desc;
947 print_queue_struct **queue = NULL;
948 print_status_struct *status = NULL;
949 int* subcntarr = NULL;
950 int queuecnt, subcnt=0, succnt=0;
952 memset((char *)&desc,'\0',sizeof(desc));
954 DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
956 if (!prefix_ok(param_format,"WrLeh")) return False;
957 if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
959 * Patch from Scott Moomaw <scott@bridgewater.edu>
960 * to return the 'invalid info level' error if an
961 * unknown level was requested.
963 *rdata_len = 0;
964 *rparam_len = 6;
965 *rparam = REALLOC(*rparam,*rparam_len);
966 SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
967 SSVAL(*rparam,2,0);
968 SSVAL(*rparam,4,0);
969 return(True);
972 queuecnt = 0;
973 for (i = 0; i < services; i++)
974 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
975 queuecnt++;
976 if (uLevel > 0) {
977 if((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
978 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
979 return False;
981 memset(queue,0,queuecnt*sizeof(print_queue_struct*));
982 if((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
983 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
984 return False;
986 memset(status,0,queuecnt*sizeof(print_status_struct));
987 if((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
988 DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
989 return False;
991 subcnt = 0;
992 n = 0;
993 for (i = 0; i < services; i++)
994 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
995 subcntarr[n] = print_queue_status(i, &queue[n],&status[n]);
996 subcnt += subcntarr[n];
997 n++;
1000 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
1001 desc.base = *rdata;
1002 desc.buflen = mdrcnt;
1004 if (init_package(&desc,queuecnt,subcnt)) {
1005 n = 0;
1006 succnt = 0;
1007 for (i = 0; i < services; i++)
1008 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
1009 fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
1010 n++;
1011 if (desc.errcode == NERR_Success) succnt = n;
1015 if (subcntarr) free(subcntarr);
1017 *rdata_len = desc.usedlen;
1018 *rparam_len = 8;
1019 *rparam = REALLOC(*rparam,*rparam_len);
1020 SSVALS(*rparam,0,desc.errcode);
1021 SSVAL(*rparam,2,0);
1022 SSVAL(*rparam,4,succnt);
1023 SSVAL(*rparam,6,queuecnt);
1025 for (i = 0; i < queuecnt; i++) {
1026 if (queue && queue[i]) free(queue[i]);
1029 if (queue) free(queue);
1030 if (status) free(status);
1032 return True;
1035 /****************************************************************************
1036 get info level for a server list query
1037 ****************************************************************************/
1038 static BOOL check_server_info(int uLevel, char* id)
1040 switch( uLevel ) {
1041 case 0:
1042 if (strcmp(id,"B16") != 0) return False;
1043 break;
1044 case 1:
1045 if (strcmp(id,"B16BBDz") != 0) return False;
1046 break;
1047 default:
1048 return False;
1050 return True;
1053 struct srv_info_struct
1055 fstring name;
1056 uint32 type;
1057 fstring comment;
1058 fstring domain;
1059 BOOL server_added;
1063 /*******************************************************************
1064 get server info lists from the files saved by nmbd. Return the
1065 number of entries
1066 ******************************************************************/
1067 static int get_server_info(uint32 servertype,
1068 struct srv_info_struct **servers,
1069 char *domain)
1071 int count=0;
1072 int alloced=0;
1073 char **lines;
1074 BOOL local_list_only;
1075 int i;
1077 lines = file_lines_load(lock_path(SERVER_LIST), NULL);
1078 if (!lines) {
1079 DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
1080 return(0);
1083 /* request for everything is code for request all servers */
1084 if (servertype == SV_TYPE_ALL)
1085 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1087 local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
1089 DEBUG(4,("Servertype search: %8x\n",servertype));
1091 for (i=0;lines[i];i++) {
1092 fstring stype;
1093 struct srv_info_struct *s;
1094 char *ptr = lines[i];
1095 BOOL ok = True;
1097 if (!*ptr) continue;
1099 if (count == alloced) {
1100 alloced += 10;
1101 (*servers) = (struct srv_info_struct *)
1102 Realloc(*servers,sizeof(**servers)*alloced);
1103 if (!(*servers)) return(0);
1104 memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
1106 s = &(*servers)[count];
1108 if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue;
1109 if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue;
1110 if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
1111 if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
1112 /* this allows us to cope with an old nmbd */
1113 pstrcpy(s->domain,global_myworkgroup);
1116 if (sscanf(stype,"%X",&s->type) != 1) {
1117 DEBUG(4,("r:host file "));
1118 ok = False;
1121 /* Filter the servers/domains we return based on what was asked for. */
1123 /* Check to see if we are being asked for a local list only. */
1124 if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
1125 DEBUG(4,("r: local list only"));
1126 ok = False;
1129 /* doesn't match up: don't want it */
1130 if (!(servertype & s->type)) {
1131 DEBUG(4,("r:serv type "));
1132 ok = False;
1135 if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
1136 (s->type & SV_TYPE_DOMAIN_ENUM))
1138 DEBUG(4,("s: dom mismatch "));
1139 ok = False;
1142 if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1144 ok = False;
1147 /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
1148 s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
1150 if (ok)
1152 DEBUG(4,("**SV** %20s %8x %25s %15s\n",
1153 s->name, s->type, s->comment, s->domain));
1155 s->server_added = True;
1156 count++;
1158 else
1160 DEBUG(4,("%20s %8x %25s %15s\n",
1161 s->name, s->type, s->comment, s->domain));
1165 file_lines_free(lines);
1166 return(count);
1170 /*******************************************************************
1171 fill in a server info structure
1172 ******************************************************************/
1173 static int fill_srv_info(struct srv_info_struct *service,
1174 int uLevel, char **buf, int *buflen,
1175 char **stringbuf, int *stringspace, char *baseaddr)
1177 int struct_len;
1178 char* p;
1179 char* p2;
1180 int l2;
1181 int len;
1183 switch (uLevel) {
1184 case 0: struct_len = 16; break;
1185 case 1: struct_len = 26; break;
1186 default: return -1;
1189 if (!buf)
1191 len = 0;
1192 switch (uLevel)
1194 case 1:
1195 len = strlen(service->comment)+1;
1196 break;
1199 if (buflen) *buflen = struct_len;
1200 if (stringspace) *stringspace = len;
1201 return struct_len + len;
1204 len = struct_len;
1205 p = *buf;
1206 if (*buflen < struct_len) return -1;
1207 if (stringbuf)
1209 p2 = *stringbuf;
1210 l2 = *stringspace;
1212 else
1214 p2 = p + struct_len;
1215 l2 = *buflen - struct_len;
1217 if (!baseaddr) baseaddr = p;
1219 switch (uLevel)
1221 case 0:
1222 StrnCpy(p,service->name,15);
1223 break;
1225 case 1:
1226 StrnCpy(p,service->name,15);
1227 SIVAL(p,18,service->type);
1228 SIVAL(p,22,PTR_DIFF(p2,baseaddr));
1229 len += CopyAndAdvance(&p2,service->comment,&l2);
1230 break;
1233 if (stringbuf)
1235 *buf = p + struct_len;
1236 *buflen -= struct_len;
1237 *stringbuf = p2;
1238 *stringspace = l2;
1240 else
1242 *buf = p2;
1243 *buflen -= len;
1245 return len;
1249 static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
1251 return(strcmp(s1->name,s2->name));
1254 /****************************************************************************
1255 view list of servers available (or possibly domains). The info is
1256 extracted from lists saved by nmbd on the local host
1257 ****************************************************************************/
1258 static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
1259 int mdrcnt, int mprcnt, char **rdata,
1260 char **rparam, int *rdata_len, int *rparam_len)
1262 char *str1 = param+2;
1263 char *str2 = skip_string(str1,1);
1264 char *p = skip_string(str2,1);
1265 int uLevel = SVAL(p,0);
1266 int buf_len = SVAL(p,2);
1267 uint32 servertype = IVAL(p,4);
1268 char *p2;
1269 int data_len, fixed_len, string_len;
1270 int f_len = 0, s_len = 0;
1271 struct srv_info_struct *servers=NULL;
1272 int counted=0,total=0;
1273 int i,missed;
1274 fstring domain;
1275 BOOL domain_request;
1276 BOOL local_request;
1278 /* If someone sets all the bits they don't really mean to set
1279 DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
1280 known servers. */
1282 if (servertype == SV_TYPE_ALL)
1283 servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
1285 /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
1286 any other bit (they may just set this bit on it's own) they
1287 want all the locally seen servers. However this bit can be
1288 set on its own so set the requested servers to be
1289 ALL - DOMAIN_ENUM. */
1291 if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
1292 servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
1294 domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
1295 local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
1297 p += 8;
1299 if (!prefix_ok(str1,"WrLehD")) return False;
1300 if (!check_server_info(uLevel,str2)) return False;
1302 DEBUG(4, ("server request level: %s %8x ", str2, servertype));
1303 DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
1304 DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
1306 if (strcmp(str1, "WrLehDz") == 0) {
1307 StrnCpy(domain, p, sizeof(fstring)-1);
1308 } else {
1309 StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);
1312 if (lp_browse_list())
1313 total = get_server_info(servertype,&servers,domain);
1315 data_len = fixed_len = string_len = 0;
1316 missed = 0;
1318 qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
1321 char *lastname=NULL;
1323 for (i=0;i<total;i++)
1325 struct srv_info_struct *s = &servers[i];
1326 if (lastname && strequal(lastname,s->name)) continue;
1327 lastname = s->name;
1328 data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
1329 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1330 s->name, s->type, s->comment, s->domain));
1332 if (data_len <= buf_len) {
1333 counted++;
1334 fixed_len += f_len;
1335 string_len += s_len;
1336 } else {
1337 missed++;
1342 *rdata_len = fixed_len + string_len;
1343 *rdata = REALLOC(*rdata,*rdata_len);
1344 memset(*rdata,'\0',*rdata_len);
1346 p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
1347 p = *rdata;
1348 f_len = fixed_len;
1349 s_len = string_len;
1352 char *lastname=NULL;
1353 int count2 = counted;
1354 for (i = 0; i < total && count2;i++)
1356 struct srv_info_struct *s = &servers[i];
1357 if (lastname && strequal(lastname,s->name)) continue;
1358 lastname = s->name;
1359 fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
1360 DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
1361 s->name, s->type, s->comment, s->domain));
1362 count2--;
1366 *rparam_len = 8;
1367 *rparam = REALLOC(*rparam,*rparam_len);
1368 SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
1369 SSVAL(*rparam,2,0);
1370 SSVAL(*rparam,4,counted);
1371 SSVAL(*rparam,6,counted+missed);
1373 if (servers) free(servers);
1375 DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
1376 domain,uLevel,counted,counted+missed));
1378 return(True);
1381 /****************************************************************************
1382 command 0x34 - suspected of being a "Lookup Names" stub api
1383 ****************************************************************************/
1384 static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
1385 int mdrcnt, int mprcnt, char **rdata,
1386 char **rparam, int *rdata_len, int *rparam_len)
1388 char *str1 = param+2;
1389 char *str2 = skip_string(str1,1);
1390 char *p = skip_string(str2,1);
1391 int uLevel = SVAL(p,0);
1392 int buf_len = SVAL(p,2);
1393 int counted=0;
1394 int missed=0;
1396 DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
1397 str1, str2, p, uLevel, buf_len));
1399 if (!prefix_ok(str1,"zWrLeh")) return False;
1401 *rdata_len = 0;
1403 *rparam_len = 8;
1404 *rparam = REALLOC(*rparam,*rparam_len);
1406 SSVAL(*rparam,0,0x08AC); /* informational warning message */
1407 SSVAL(*rparam,2,0);
1408 SSVAL(*rparam,4,counted);
1409 SSVAL(*rparam,6,counted+missed);
1411 return(True);
1414 /****************************************************************************
1415 get info about a share
1416 ****************************************************************************/
1417 static BOOL check_share_info(int uLevel, char* id)
1419 switch( uLevel ) {
1420 case 0:
1421 if (strcmp(id,"B13") != 0) return False;
1422 break;
1423 case 1:
1424 if (strcmp(id,"B13BWz") != 0) return False;
1425 break;
1426 case 2:
1427 if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
1428 break;
1429 case 91:
1430 if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
1431 break;
1432 default: return False;
1434 return True;
1437 static int fill_share_info(connection_struct *conn, int snum, int uLevel,
1438 char** buf, int* buflen,
1439 char** stringbuf, int* stringspace, char* baseaddr)
1441 int struct_len;
1442 char* p;
1443 char* p2;
1444 int l2;
1445 int len;
1447 switch( uLevel ) {
1448 case 0: struct_len = 13; break;
1449 case 1: struct_len = 20; break;
1450 case 2: struct_len = 40; break;
1451 case 91: struct_len = 68; break;
1452 default: return -1;
1456 if (!buf)
1458 len = 0;
1459 if (uLevel > 0) len += StrlenExpanded(conn,snum,lp_comment(snum));
1460 if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
1461 if (buflen) *buflen = struct_len;
1462 if (stringspace) *stringspace = len;
1463 return struct_len + len;
1466 len = struct_len;
1467 p = *buf;
1468 if ((*buflen) < struct_len) return -1;
1469 if (stringbuf)
1471 p2 = *stringbuf;
1472 l2 = *stringspace;
1474 else
1476 p2 = p + struct_len;
1477 l2 = (*buflen) - struct_len;
1479 if (!baseaddr) baseaddr = p;
1481 StrnCpy(p,lp_servicename(snum),13);
1483 if (uLevel > 0)
1485 int type;
1486 CVAL(p,13) = 0;
1487 type = STYPE_DISKTREE;
1488 if (lp_print_ok(snum)) type = STYPE_PRINTQ;
1489 if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
1490 SSVAL(p,14,type); /* device type */
1491 SIVAL(p,16,PTR_DIFF(p2,baseaddr));
1492 len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
1495 if (uLevel > 1)
1497 SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
1498 SSVALS(p,22,-1); /* max uses */
1499 SSVAL(p,24,1); /* current uses */
1500 SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
1501 len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
1502 memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
1505 if (uLevel > 2)
1507 memset(p+40,0,SHPWLEN+2);
1508 SSVAL(p,50,0);
1509 SIVAL(p,52,0);
1510 SSVAL(p,56,0);
1511 SSVAL(p,58,0);
1512 SIVAL(p,60,0);
1513 SSVAL(p,64,0);
1514 SSVAL(p,66,0);
1517 if (stringbuf)
1519 (*buf) = p + struct_len;
1520 (*buflen) -= struct_len;
1521 (*stringbuf) = p2;
1522 (*stringspace) = l2;
1524 else
1526 (*buf) = p2;
1527 (*buflen) -= len;
1529 return len;
1532 static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
1533 int mdrcnt,int mprcnt,
1534 char **rdata,char **rparam,
1535 int *rdata_len,int *rparam_len)
1537 char *str1 = param+2;
1538 char *str2 = skip_string(str1,1);
1539 char *netname = skip_string(str2,1);
1540 char *p = skip_string(netname,1);
1541 int uLevel = SVAL(p,0);
1542 int snum = find_service(netname);
1544 if (snum < 0) return False;
1546 /* check it's a supported varient */
1547 if (!prefix_ok(str1,"zWrLh")) return False;
1548 if (!check_share_info(uLevel,str2)) return False;
1550 *rdata = REALLOC(*rdata,mdrcnt);
1551 p = *rdata;
1552 *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
1553 if (*rdata_len < 0) return False;
1555 *rparam_len = 6;
1556 *rparam = REALLOC(*rparam,*rparam_len);
1557 SSVAL(*rparam,0,NERR_Success);
1558 SSVAL(*rparam,2,0); /* converter word */
1559 SSVAL(*rparam,4,*rdata_len);
1561 return(True);
1564 /****************************************************************************
1565 view list of shares available
1566 ****************************************************************************/
1567 static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
1568 int mdrcnt,int mprcnt,
1569 char **rdata,char **rparam,
1570 int *rdata_len,int *rparam_len)
1572 char *str1 = param+2;
1573 char *str2 = skip_string(str1,1);
1574 char *p = skip_string(str2,1);
1575 int uLevel = SVAL(p,0);
1576 int buf_len = SVAL(p,2);
1577 char *p2;
1578 int count=lp_numservices();
1579 int total=0,counted=0;
1580 BOOL missed = False;
1581 int i;
1582 int data_len, fixed_len, string_len;
1583 int f_len = 0, s_len = 0;
1585 if (!prefix_ok(str1,"WrLeh")) return False;
1586 if (!check_share_info(uLevel,str2)) return False;
1588 data_len = fixed_len = string_len = 0;
1589 for (i=0;i<count;i++)
1590 if (lp_browseable(i) && lp_snum_ok(i))
1592 total++;
1593 data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
1594 if (data_len <= buf_len)
1596 counted++;
1597 fixed_len += f_len;
1598 string_len += s_len;
1600 else
1601 missed = True;
1603 *rdata_len = fixed_len + string_len;
1604 *rdata = REALLOC(*rdata,*rdata_len);
1605 memset(*rdata,0,*rdata_len);
1607 p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
1608 p = *rdata;
1609 f_len = fixed_len;
1610 s_len = string_len;
1611 for (i = 0; i < count;i++)
1612 if (lp_browseable(i) && lp_snum_ok(i))
1613 if (fill_share_info(conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
1614 break;
1616 *rparam_len = 8;
1617 *rparam = REALLOC(*rparam,*rparam_len);
1618 SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
1619 SSVAL(*rparam,2,0);
1620 SSVAL(*rparam,4,counted);
1621 SSVAL(*rparam,6,total);
1623 DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
1624 counted,total,uLevel,
1625 buf_len,*rdata_len,mdrcnt));
1626 return(True);
1631 /****************************************************************************
1632 get the time of day info
1633 ****************************************************************************/
1634 static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
1635 int mdrcnt,int mprcnt,
1636 char **rdata,char **rparam,
1637 int *rdata_len,int *rparam_len)
1639 char *p;
1640 *rparam_len = 4;
1641 *rparam = REALLOC(*rparam,*rparam_len);
1643 *rdata_len = 21;
1644 *rdata = REALLOC(*rdata,*rdata_len);
1646 SSVAL(*rparam,0,NERR_Success);
1647 SSVAL(*rparam,2,0); /* converter word */
1649 p = *rdata;
1652 struct tm *t;
1653 time_t unixdate = time(NULL);
1655 put_dos_date3(p,0,unixdate); /* this is the time that is looked at
1656 by NT in a "net time" operation,
1657 it seems to ignore the one below */
1659 /* the client expects to get localtime, not GMT, in this bit
1660 (I think, this needs testing) */
1661 t = LocalTime(&unixdate);
1663 SIVAL(p,4,0); /* msecs ? */
1664 CVAL(p,8) = t->tm_hour;
1665 CVAL(p,9) = t->tm_min;
1666 CVAL(p,10) = t->tm_sec;
1667 CVAL(p,11) = 0; /* hundredths of seconds */
1668 SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
1669 SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
1670 CVAL(p,16) = t->tm_mday;
1671 CVAL(p,17) = t->tm_mon + 1;
1672 SSVAL(p,18,1900+t->tm_year);
1673 CVAL(p,20) = t->tm_wday;
1677 return(True);
1680 /****************************************************************************
1681 Set the user password.
1682 *****************************************************************************/
1684 static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1685 int mdrcnt,int mprcnt,
1686 char **rdata,char **rparam,
1687 int *rdata_len,int *rparam_len)
1689 char *p = skip_string(param+2,2);
1690 fstring user;
1691 fstring pass1,pass2;
1693 fstrcpy(user,p);
1695 p = skip_string(p,1);
1697 memset(pass1,'\0',sizeof(pass1));
1698 memset(pass2,'\0',sizeof(pass2));
1699 memcpy(pass1,p,16);
1700 memcpy(pass2,p+16,16);
1702 *rparam_len = 4;
1703 *rparam = REALLOC(*rparam,*rparam_len);
1705 *rdata_len = 0;
1707 SSVAL(*rparam,0,NERR_badpass);
1708 SSVAL(*rparam,2,0); /* converter word */
1710 DEBUG(3,("Set password for <%s>\n",user));
1713 * Pass the user through the NT -> unix user mapping
1714 * function.
1717 (void)map_username(user);
1720 * Do any UNIX username case mangling.
1722 (void)Get_Pwnam( user, True);
1725 * Attempt to verify the old password against smbpasswd entries
1726 * Win98 clients send old and new password in plaintext for this call.
1730 fstring saved_pass2;
1731 struct smb_passwd *smbpw = NULL;
1734 * Save the new password as change_oem_password overwrites it
1735 * with zeros.
1738 fstrcpy(saved_pass2, pass2);
1740 if (check_plaintext_password(user,pass1,strlen(pass1),&smbpw) &&
1741 change_oem_password(smbpw,pass2,False))
1743 SSVAL(*rparam,0,NERR_Success);
1746 * If unix password sync was requested, attempt to change
1747 * the /etc/passwd database also. Return failure if this cannot
1748 * be done.
1751 if(lp_unix_password_sync() && !chgpasswd(user,pass1,saved_pass2,False))
1752 SSVAL(*rparam,0,NERR_badpass);
1757 * If the above failed, attempt the plaintext password change.
1758 * This tests against the /etc/passwd database only.
1761 if(SVAL(*rparam,0) != NERR_Success)
1763 if (password_ok(user, pass1,strlen(pass1),NULL) &&
1764 chgpasswd(user,pass1,pass2,False))
1766 SSVAL(*rparam,0,NERR_Success);
1771 * If the plaintext change failed, attempt
1772 * the old encrypted method. NT will generate this
1773 * after trying the samr method. Note that this
1774 * method is done as a last resort as this
1775 * password change method loses the NT password hash
1776 * and cannot change the UNIX password as no plaintext
1777 * is received.
1780 if(SVAL(*rparam,0) != NERR_Success)
1782 struct smb_passwd *sampw = NULL;
1784 if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &sampw) &&
1785 change_lanman_password(sampw,(unsigned char *)pass1,(unsigned char *)pass2))
1787 SSVAL(*rparam,0,NERR_Success);
1791 memset((char *)pass1,'\0',sizeof(fstring));
1792 memset((char *)pass2,'\0',sizeof(fstring));
1794 return(True);
1797 /****************************************************************************
1798 Set the user password (SamOEM version - gets plaintext).
1799 ****************************************************************************/
1801 static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
1802 int mdrcnt,int mprcnt,
1803 char **rdata,char **rparam,
1804 int *rdata_len,int *rparam_len)
1806 fstring user;
1807 char *p = param + 2;
1808 *rparam_len = 2;
1809 *rparam = REALLOC(*rparam,*rparam_len);
1811 *rdata_len = 0;
1813 SSVAL(*rparam,0,NERR_badpass);
1816 * Check the parameter definition is correct.
1818 if(!strequal(param + 2, "zsT")) {
1819 DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
1820 return False;
1822 p = skip_string(p, 1);
1824 if(!strequal(p, "B516B16")) {
1825 DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
1826 return False;
1828 p = skip_string(p,1);
1830 fstrcpy(user,p);
1831 p = skip_string(p,1);
1833 DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
1836 * Pass the user through the NT -> unix user mapping
1837 * function.
1840 (void)map_username(user);
1843 * Do any UNIX username case mangling.
1845 (void)Get_Pwnam( user, True);
1847 if (pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL))
1849 SSVAL(*rparam,0,NERR_Success);
1852 return(True);
1855 /****************************************************************************
1856 delete a print job
1857 Form: <W> <>
1858 ****************************************************************************/
1859 static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
1860 int mdrcnt,int mprcnt,
1861 char **rdata,char **rparam,
1862 int *rdata_len,int *rparam_len)
1864 int function = SVAL(param,0);
1865 char *str1 = param+2;
1866 char *str2 = skip_string(str1,1);
1867 char *p = skip_string(str2,1);
1868 int jobid, errcode;
1869 extern struct current_user current_user;
1871 jobid = SVAL(p,0);
1873 /* check it's a supported varient */
1874 if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
1875 return(False);
1877 *rparam_len = 4;
1878 *rparam = REALLOC(*rparam,*rparam_len);
1879 *rdata_len = 0;
1881 if (!print_job_exists(jobid)) {
1882 errcode = NERR_JobNotFound;
1883 goto out;
1886 errcode = NERR_notsupported;
1888 switch (function) {
1889 case 81: /* delete */
1890 if (print_job_delete(&current_user, jobid))
1891 errcode = NERR_Success;
1892 break;
1893 case 82: /* pause */
1894 if (print_job_pause(&current_user, jobid))
1895 errcode = NERR_Success;
1896 break;
1897 case 83: /* resume */
1898 if (print_job_resume(&current_user, jobid))
1899 errcode = NERR_Success;
1900 break;
1903 out:
1904 SSVAL(*rparam,0,errcode);
1905 SSVAL(*rparam,2,0); /* converter word */
1907 return(True);
1910 /****************************************************************************
1911 Purge a print queue - or pause or resume it.
1912 ****************************************************************************/
1913 static BOOL api_WPrintQueuePurge(connection_struct *conn,uint16 vuid, char *param,char *data,
1914 int mdrcnt,int mprcnt,
1915 char **rdata,char **rparam,
1916 int *rdata_len,int *rparam_len)
1918 int function = SVAL(param,0);
1919 char *str1 = param+2;
1920 char *str2 = skip_string(str1,1);
1921 char *QueueName = skip_string(str2,1);
1922 int errcode = NERR_notsupported;
1923 int snum;
1925 /* check it's a supported varient */
1926 if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
1927 return(False);
1929 *rparam_len = 4;
1930 *rparam = REALLOC(*rparam,*rparam_len);
1931 *rdata_len = 0;
1933 snum = print_queue_snum(QueueName);
1935 if (snum == -1) {
1936 errcode = NERR_JobNotFound;
1937 goto out;
1940 switch (function) {
1941 case 74: /* Pause queue */
1942 if (print_queue_pause(NULL, snum)) errcode = NERR_Success;
1943 break;
1944 case 75: /* Resume queue */
1945 if (print_queue_resume(NULL, snum)) errcode = NERR_Success;
1946 break;
1947 case 103: /* Purge */
1948 if (print_queue_purge(NULL, snum)) errcode = NERR_Success;
1949 break;
1952 out:
1953 SSVAL(*rparam,0,errcode);
1954 SSVAL(*rparam,2,0); /* converter word */
1956 return(True);
1960 /****************************************************************************
1961 set the property of a print job (undocumented?)
1962 ? function = 0xb -> set name of print job
1963 ? function = 0x6 -> move print job up/down
1964 Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
1965 or <WWsTP> <WB21BB16B10zWWzDDz>
1966 ****************************************************************************/
1967 static int check_printjob_info(struct pack_desc* desc,
1968 int uLevel, char* id)
1970 desc->subformat = NULL;
1971 switch( uLevel ) {
1972 case 0: desc->format = "W"; break;
1973 case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
1974 case 2: desc->format = "WWzWWDDzz"; break;
1975 case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
1976 default: return False;
1978 if (strcmp(desc->format,id) != 0) return False;
1979 return True;
1982 static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
1983 int mdrcnt,int mprcnt,
1984 char **rdata,char **rparam,
1985 int *rdata_len,int *rparam_len)
1987 struct pack_desc desc;
1988 char *str1 = param+2;
1989 char *str2 = skip_string(str1,1);
1990 char *p = skip_string(str2,1);
1991 int jobid;
1992 int uLevel = SVAL(p,2);
1993 int function = SVAL(p,4);
1994 int place, errcode;
1996 jobid = SVAL(p,0);
1997 *rparam_len = 4;
1998 *rparam = REALLOC(*rparam,*rparam_len);
2000 *rdata_len = 0;
2002 /* check it's a supported varient */
2003 if ((strcmp(str1,"WWsTP")) ||
2004 (!check_printjob_info(&desc,uLevel,str2)))
2005 return(False);
2007 if (!print_job_exists(jobid)) {
2008 errcode=NERR_JobNotFound;
2009 goto out;
2012 errcode = NERR_notsupported;
2014 switch (function) {
2015 case 0x6:
2016 /* change job place in the queue,
2017 data gives the new place */
2018 place = SVAL(data,0);
2019 if (print_job_set_place(jobid, place)) {
2020 errcode=NERR_Success;
2022 break;
2024 case 0xb:
2025 /* change print job name, data gives the name */
2026 if (print_job_set_name(jobid, data)) {
2027 errcode=NERR_Success;
2029 break;
2031 default:
2032 return False;
2035 out:
2036 SSVALS(*rparam,0,errcode);
2037 SSVAL(*rparam,2,0); /* converter word */
2039 return(True);
2043 /****************************************************************************
2044 get info about the server
2045 ****************************************************************************/
2046 static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2047 int mdrcnt,int mprcnt,
2048 char **rdata,char **rparam,
2049 int *rdata_len,int *rparam_len)
2051 char *str1 = param+2;
2052 char *str2 = skip_string(str1,1);
2053 char *p = skip_string(str2,1);
2054 int uLevel = SVAL(p,0);
2055 char *p2;
2056 int struct_len;
2058 DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
2060 /* check it's a supported varient */
2061 if (!prefix_ok(str1,"WrLh")) return False;
2062 switch( uLevel ) {
2063 case 0:
2064 if (strcmp(str2,"B16") != 0) return False;
2065 struct_len = 16;
2066 break;
2067 case 1:
2068 if (strcmp(str2,"B16BBDz") != 0) return False;
2069 struct_len = 26;
2070 break;
2071 case 2:
2072 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
2073 != 0) return False;
2074 struct_len = 134;
2075 break;
2076 case 3:
2077 if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
2078 != 0) return False;
2079 struct_len = 144;
2080 break;
2081 case 20:
2082 if (strcmp(str2,"DN") != 0) return False;
2083 struct_len = 6;
2084 break;
2085 case 50:
2086 if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
2087 struct_len = 42;
2088 break;
2089 default: return False;
2092 *rdata_len = mdrcnt;
2093 *rdata = REALLOC(*rdata,*rdata_len);
2095 p = *rdata;
2096 p2 = p + struct_len;
2097 if (uLevel != 20) {
2098 StrnCpy(p,local_machine,16);
2099 strupper(p);
2101 p += 16;
2102 if (uLevel > 0)
2104 struct srv_info_struct *servers=NULL;
2105 int i,count;
2106 pstring comment;
2107 uint32 servertype= lp_default_server_announce();
2109 pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
2111 if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
2112 for (i=0;i<count;i++)
2113 if (strequal(servers[i].name,local_machine))
2115 servertype = servers[i].type;
2116 pstrcpy(comment,servers[i].comment);
2119 if (servers) free(servers);
2121 SCVAL(p,0,lp_major_announce_version());
2122 SCVAL(p,1,lp_minor_announce_version());
2123 SIVAL(p,2,servertype);
2125 if (mdrcnt == struct_len) {
2126 SIVAL(p,6,0);
2127 } else {
2128 SIVAL(p,6,PTR_DIFF(p2,*rdata));
2129 standard_sub_conn(conn,comment);
2130 StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
2131 p2 = skip_string(p2,1);
2134 if (uLevel > 1)
2136 return False; /* not yet implemented */
2139 *rdata_len = PTR_DIFF(p2,*rdata);
2141 *rparam_len = 6;
2142 *rparam = REALLOC(*rparam,*rparam_len);
2143 SSVAL(*rparam,0,NERR_Success);
2144 SSVAL(*rparam,2,0); /* converter word */
2145 SSVAL(*rparam,4,*rdata_len);
2147 return(True);
2151 /****************************************************************************
2152 get info about the server
2153 ****************************************************************************/
2154 static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2155 int mdrcnt,int mprcnt,
2156 char **rdata,char **rparam,
2157 int *rdata_len,int *rparam_len)
2159 char *str1 = param+2;
2160 char *str2 = skip_string(str1,1);
2161 char *p = skip_string(str2,1);
2162 char *p2;
2163 extern pstring sesssetup_user;
2164 int level = SVAL(p,0);
2166 DEBUG(4,("NetWkstaGetInfo level %d\n",level));
2168 *rparam_len = 6;
2169 *rparam = REALLOC(*rparam,*rparam_len);
2171 /* check it's a supported varient */
2172 if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
2173 return(False);
2175 *rdata_len = mdrcnt + 1024;
2176 *rdata = REALLOC(*rdata,*rdata_len);
2178 SSVAL(*rparam,0,NERR_Success);
2179 SSVAL(*rparam,2,0); /* converter word */
2181 p = *rdata;
2182 p2 = p + 22;
2185 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
2186 pstrcpy(p2,local_machine);
2187 strupper(p2);
2188 p2 = skip_string(p2,1);
2189 p += 4;
2191 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2192 pstrcpy(p2,sesssetup_user);
2193 p2 = skip_string(p2,1);
2194 p += 4;
2196 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
2197 pstrcpy(p2,global_myworkgroup);
2198 strupper(p2);
2199 p2 = skip_string(p2,1);
2200 p += 4;
2202 SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
2203 SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
2204 p += 2;
2206 SIVAL(p,0,PTR_DIFF(p2,*rdata));
2207 pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
2208 p2 = skip_string(p2,1);
2209 p += 4;
2211 SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
2212 pstrcpy(p2,"");
2213 p2 = skip_string(p2,1);
2214 p += 4;
2216 *rdata_len = PTR_DIFF(p2,*rdata);
2218 SSVAL(*rparam,4,*rdata_len);
2220 return(True);
2223 /****************************************************************************
2224 get info about a user
2226 struct user_info_11 {
2227 char usri11_name[21]; 0-20
2228 char usri11_pad; 21
2229 char *usri11_comment; 22-25
2230 char *usri11_usr_comment; 26-29
2231 unsigned short usri11_priv; 30-31
2232 unsigned long usri11_auth_flags; 32-35
2233 long usri11_password_age; 36-39
2234 char *usri11_homedir; 40-43
2235 char *usri11_parms; 44-47
2236 long usri11_last_logon; 48-51
2237 long usri11_last_logoff; 52-55
2238 unsigned short usri11_bad_pw_count; 56-57
2239 unsigned short usri11_num_logons; 58-59
2240 char *usri11_logon_server; 60-63
2241 unsigned short usri11_country_code; 64-65
2242 char *usri11_workstations; 66-69
2243 unsigned long usri11_max_storage; 70-73
2244 unsigned short usri11_units_per_week; 74-75
2245 unsigned char *usri11_logon_hours; 76-79
2246 unsigned short usri11_code_page; 80-81
2249 where:
2251 usri11_name specifies the user name for which information is retireved
2253 usri11_pad aligns the next data structure element to a word boundary
2255 usri11_comment is a null terminated ASCII comment
2257 usri11_user_comment is a null terminated ASCII comment about the user
2259 usri11_priv specifies the level of the privilege assigned to the user.
2260 The possible values are:
2262 Name Value Description
2263 USER_PRIV_GUEST 0 Guest privilege
2264 USER_PRIV_USER 1 User privilege
2265 USER_PRV_ADMIN 2 Administrator privilege
2267 usri11_auth_flags specifies the account operator privileges. The
2268 possible values are:
2270 Name Value Description
2271 AF_OP_PRINT 0 Print operator
2274 Leach, Naik [Page 28]
2278 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2281 AF_OP_COMM 1 Communications operator
2282 AF_OP_SERVER 2 Server operator
2283 AF_OP_ACCOUNTS 3 Accounts operator
2286 usri11_password_age specifies how many seconds have elapsed since the
2287 password was last changed.
2289 usri11_home_dir points to a null terminated ASCII string that contains
2290 the path name of the user's home directory.
2292 usri11_parms points to a null terminated ASCII string that is set
2293 aside for use by applications.
2295 usri11_last_logon specifies the time when the user last logged on.
2296 This value is stored as the number of seconds elapsed since
2297 00:00:00, January 1, 1970.
2299 usri11_last_logoff specifies the time when the user last logged off.
2300 This value is stored as the number of seconds elapsed since
2301 00:00:00, January 1, 1970. A value of 0 means the last logoff
2302 time is unknown.
2304 usri11_bad_pw_count specifies the number of incorrect passwords
2305 entered since the last successful logon.
2307 usri11_log1_num_logons specifies the number of times this user has
2308 logged on. A value of -1 means the number of logons is unknown.
2310 usri11_logon_server points to a null terminated ASCII string that
2311 contains the name of the server to which logon requests are sent.
2312 A null string indicates logon requests should be sent to the
2313 domain controller.
2315 usri11_country_code specifies the country code for the user's language
2316 of choice.
2318 usri11_workstations points to a null terminated ASCII string that
2319 contains the names of workstations the user may log on from.
2320 There may be up to 8 workstations, with the names separated by
2321 commas. A null strings indicates there are no restrictions.
2323 usri11_max_storage specifies the maximum amount of disk space the user
2324 can occupy. A value of 0xffffffff indicates there are no
2325 restrictions.
2327 usri11_units_per_week specifies the equal number of time units into
2328 which a week is divided. This value must be equal to 168.
2330 usri11_logon_hours points to a 21 byte (168 bits) string that
2331 specifies the time during which the user can log on. Each bit
2332 represents one unique hour in a week. The first bit (bit 0, word
2333 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
2337 Leach, Naik [Page 29]
2341 INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
2344 Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
2345 are no restrictions.
2347 usri11_code_page specifies the code page for the user's language of
2348 choice
2350 All of the pointers in this data structure need to be treated
2351 specially. The pointer is a 32 bit pointer. The higher 16 bits need
2352 to be ignored. The converter word returned in the parameters section
2353 needs to be subtracted from the lower 16 bits to calculate an offset
2354 into the return buffer where this ASCII string resides.
2356 There is no auxiliary data in the response.
2358 ****************************************************************************/
2360 #define usri11_name 0
2361 #define usri11_pad 21
2362 #define usri11_comment 22
2363 #define usri11_usr_comment 26
2364 #define usri11_full_name 30
2365 #define usri11_priv 34
2366 #define usri11_auth_flags 36
2367 #define usri11_password_age 40
2368 #define usri11_homedir 44
2369 #define usri11_parms 48
2370 #define usri11_last_logon 52
2371 #define usri11_last_logoff 56
2372 #define usri11_bad_pw_count 60
2373 #define usri11_num_logons 62
2374 #define usri11_logon_server 64
2375 #define usri11_country_code 68
2376 #define usri11_workstations 70
2377 #define usri11_max_storage 74
2378 #define usri11_units_per_week 78
2379 #define usri11_logon_hours 80
2380 #define usri11_code_page 84
2381 #define usri11_end 86
2383 #define USER_PRIV_GUEST 0
2384 #define USER_PRIV_USER 1
2385 #define USER_PRIV_ADMIN 2
2387 #define AF_OP_PRINT 0
2388 #define AF_OP_COMM 1
2389 #define AF_OP_SERVER 2
2390 #define AF_OP_ACCOUNTS 3
2393 static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2394 int mdrcnt,int mprcnt,
2395 char **rdata,char **rparam,
2396 int *rdata_len,int *rparam_len)
2398 char *str1 = param+2;
2399 char *str2 = skip_string(str1,1);
2400 char *UserName = skip_string(str2,1);
2401 char *p = skip_string(UserName,1);
2402 int uLevel = SVAL(p,0);
2403 char *p2;
2405 /* get NIS home of a previously validated user - simeon */
2406 /* With share level security vuid will always be zero.
2407 Don't depend on vuser being non-null !!. JRA */
2408 user_struct *vuser = get_valid_user_struct(vuid);
2409 if(vuser != NULL)
2410 DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid,
2411 vuser->user.unix_name));
2413 *rparam_len = 6;
2414 *rparam = REALLOC(*rparam,*rparam_len);
2416 DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
2418 /* check it's a supported variant */
2419 if (strcmp(str1,"zWrLh") != 0) return False;
2420 switch( uLevel )
2422 case 0: p2 = "B21"; break;
2423 case 1: p2 = "B21BB16DWzzWz"; break;
2424 case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
2425 case 10: p2 = "B21Bzzz"; break;
2426 case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
2427 default: return False;
2430 if (strcmp(p2,str2) != 0) return False;
2432 *rdata_len = mdrcnt + 1024;
2433 *rdata = REALLOC(*rdata,*rdata_len);
2435 SSVAL(*rparam,0,NERR_Success);
2436 SSVAL(*rparam,2,0); /* converter word */
2438 p = *rdata;
2439 p2 = p + usri11_end;
2441 memset(p,0,21);
2442 fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
2444 if (uLevel > 0)
2446 SCVAL(p,usri11_pad,0); /* padding - 1 byte */
2447 *p2 = 0;
2449 if (uLevel >= 10)
2451 SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
2452 pstrcpy(p2,"Comment");
2453 p2 = skip_string(p2,1);
2455 SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
2456 pstrcpy(p2,"UserComment");
2457 p2 = skip_string(p2,1);
2459 /* EEK! the cifsrap.txt doesn't have this in!!!! */
2460 SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
2461 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2462 p2 = skip_string(p2,1);
2465 if (uLevel == 11) /* modelled after NTAS 3.51 reply */
2467 SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2468 SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
2469 SIVALS(p,usri11_password_age,-1); /* password age */
2470 SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
2471 pstrcpy(p2, lp_logon_home());
2472 p2 = skip_string(p2,1);
2473 SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
2474 pstrcpy(p2,"");
2475 p2 = skip_string(p2,1);
2476 SIVAL(p,usri11_last_logon,0); /* last logon */
2477 SIVAL(p,usri11_last_logoff,0); /* last logoff */
2478 SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */
2479 SSVALS(p,usri11_num_logons,-1); /* num logons */
2480 SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
2481 pstrcpy(p2,"\\\\*");
2482 p2 = skip_string(p2,1);
2483 SSVAL(p,usri11_country_code,0); /* country code */
2485 SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
2486 pstrcpy(p2,"");
2487 p2 = skip_string(p2,1);
2489 SIVALS(p,usri11_max_storage,-1); /* max storage */
2490 SSVAL(p,usri11_units_per_week,168); /* units per week */
2491 SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
2493 /* a simple way to get logon hours at all times. */
2494 memset(p2,0xff,21);
2495 SCVAL(p2,21,0); /* fix zero termination */
2496 p2 = skip_string(p2,1);
2498 SSVAL(p,usri11_code_page,0); /* code page */
2500 if (uLevel == 1 || uLevel == 2)
2502 memset(p+22,' ',16); /* password */
2503 SIVALS(p,38,-1); /* password age */
2504 SSVAL(p,42,
2505 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2506 SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
2507 pstrcpy(p2,lp_logon_home());
2508 p2 = skip_string(p2,1);
2509 SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
2510 *p2++ = 0;
2511 SSVAL(p,52,0); /* flags */
2512 SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
2513 pstrcpy(p2,lp_logon_script());
2514 standard_sub_conn( conn, p2 );
2515 p2 = skip_string(p2,1);
2516 if (uLevel == 2)
2518 SIVAL(p,60,0); /* auth_flags */
2519 SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
2520 pstrcpy(p2,((vuser != NULL) ? vuser->user.full_name : UserName));
2521 p2 = skip_string(p2,1);
2522 SIVAL(p,68,0); /* urs_comment */
2523 SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
2524 pstrcpy(p2,"");
2525 p2 = skip_string(p2,1);
2526 SIVAL(p,76,0); /* workstations */
2527 SIVAL(p,80,0); /* last_logon */
2528 SIVAL(p,84,0); /* last_logoff */
2529 SIVALS(p,88,-1); /* acct_expires */
2530 SIVALS(p,92,-1); /* max_storage */
2531 SSVAL(p,96,168); /* units_per_week */
2532 SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
2533 memset(p2,-1,21);
2534 p2 += 21;
2535 SSVALS(p,102,-1); /* bad_pw_count */
2536 SSVALS(p,104,-1); /* num_logons */
2537 SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
2538 pstrcpy(p2,"\\\\%L");
2539 standard_sub_conn(conn, p2);
2540 p2 = skip_string(p2,1);
2541 SSVAL(p,110,49); /* country_code */
2542 SSVAL(p,112,860); /* code page */
2546 *rdata_len = PTR_DIFF(p2,*rdata);
2548 SSVAL(*rparam,4,*rdata_len); /* is this right?? */
2550 return(True);
2553 /*******************************************************************
2554 get groups that a user is a member of
2555 ******************************************************************/
2556 static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
2557 int mdrcnt,int mprcnt,
2558 char **rdata,char **rparam,
2559 int *rdata_len,int *rparam_len)
2561 char *str1 = param+2;
2562 char *str2 = skip_string(str1,1);
2563 char *UserName = skip_string(str2,1);
2564 char *p = skip_string(UserName,1);
2565 int uLevel = SVAL(p,0);
2566 char *p2;
2567 int count=0;
2569 *rparam_len = 8;
2570 *rparam = REALLOC(*rparam,*rparam_len);
2572 /* check it's a supported varient */
2573 if (strcmp(str1,"zWrLeh") != 0) return False;
2574 switch( uLevel ) {
2575 case 0: p2 = "B21"; break;
2576 default: return False;
2578 if (strcmp(p2,str2) != 0) return False;
2580 *rdata_len = mdrcnt + 1024;
2581 *rdata = REALLOC(*rdata,*rdata_len);
2583 SSVAL(*rparam,0,NERR_Success);
2584 SSVAL(*rparam,2,0); /* converter word */
2586 p = *rdata;
2588 /* XXXX we need a real SAM database some day */
2589 pstrcpy(p,"Users"); p += 21; count++;
2590 pstrcpy(p,"Domain Users"); p += 21; count++;
2591 pstrcpy(p,"Guests"); p += 21; count++;
2592 pstrcpy(p,"Domain Guests"); p += 21; count++;
2594 *rdata_len = PTR_DIFF(p,*rdata);
2596 SSVAL(*rparam,4,count); /* is this right?? */
2597 SSVAL(*rparam,6,count); /* is this right?? */
2599 return(True);
2603 static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
2604 int mdrcnt,int mprcnt,
2605 char **rdata,char **rparam,
2606 int *rdata_len,int *rparam_len)
2608 char *str1 = param+2;
2609 char *str2 = skip_string(str1,1);
2610 char *p = skip_string(str2,1);
2611 int uLevel;
2612 struct pack_desc desc;
2613 char* name;
2615 uLevel = SVAL(p,0);
2616 name = p + 2;
2618 memset((char *)&desc,'\0',sizeof(desc));
2620 DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
2622 /* check it's a supported varient */
2623 if (strcmp(str1,"OOWb54WrLh") != 0) return False;
2624 if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
2625 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2626 desc.base = *rdata;
2627 desc.buflen = mdrcnt;
2628 desc.subformat = NULL;
2629 desc.format = str2;
2631 if (init_package(&desc,1,0))
2633 PACKI(&desc,"W",0); /* code */
2634 PACKS(&desc,"B21",name); /* eff. name */
2635 PACKS(&desc,"B",""); /* pad */
2636 PACKI(&desc,"W",
2637 conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
2638 PACKI(&desc,"D",0); /* auth flags XXX */
2639 PACKI(&desc,"W",0); /* num logons */
2640 PACKI(&desc,"W",0); /* bad pw count */
2641 PACKI(&desc,"D",0); /* last logon */
2642 PACKI(&desc,"D",-1); /* last logoff */
2643 PACKI(&desc,"D",-1); /* logoff time */
2644 PACKI(&desc,"D",-1); /* kickoff time */
2645 PACKI(&desc,"D",0); /* password age */
2646 PACKI(&desc,"D",0); /* password can change */
2647 PACKI(&desc,"D",-1); /* password must change */
2649 fstring mypath;
2650 fstrcpy(mypath,"\\\\");
2651 fstrcat(mypath,local_machine);
2652 strupper(mypath);
2653 PACKS(&desc,"z",mypath); /* computer */
2655 PACKS(&desc,"z",global_myworkgroup);/* domain */
2657 /* JHT - By calling lp_logon_script() and standard_sub() we have */
2658 /* made sure all macros are fully substituted and available */
2660 pstring logon_script;
2661 pstrcpy(logon_script,lp_logon_script());
2662 standard_sub_conn( conn, logon_script );
2663 PACKS(&desc,"z", logon_script); /* script path */
2665 /* End of JHT mods */
2667 PACKI(&desc,"D",0x00000000); /* reserved */
2670 *rdata_len = desc.usedlen;
2671 *rparam_len = 6;
2672 *rparam = REALLOC(*rparam,*rparam_len);
2673 SSVALS(*rparam,0,desc.errcode);
2674 SSVAL(*rparam,2,0);
2675 SSVAL(*rparam,4,desc.neededlen);
2677 DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
2678 return(True);
2682 /****************************************************************************
2683 api_WAccessGetUserPerms
2684 ****************************************************************************/
2685 static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
2686 int mdrcnt,int mprcnt,
2687 char **rdata,char **rparam,
2688 int *rdata_len,int *rparam_len)
2690 char *str1 = param+2;
2691 char *str2 = skip_string(str1,1);
2692 char *user = skip_string(str2,1);
2693 char *resource = skip_string(user,1);
2695 DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
2697 /* check it's a supported varient */
2698 if (strcmp(str1,"zzh") != 0) return False;
2699 if (strcmp(str2,"") != 0) return False;
2701 *rparam_len = 6;
2702 *rparam = REALLOC(*rparam,*rparam_len);
2703 SSVALS(*rparam,0,0); /* errorcode */
2704 SSVAL(*rparam,2,0); /* converter word */
2705 SSVAL(*rparam,4,0x7f); /* permission flags */
2707 return(True);
2710 /****************************************************************************
2711 api_WPrintJobEnumerate
2712 ****************************************************************************/
2713 static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2714 int mdrcnt,int mprcnt,
2715 char **rdata,char **rparam,
2716 int *rdata_len,int *rparam_len)
2718 char *str1 = param+2;
2719 char *str2 = skip_string(str1,1);
2720 char *p = skip_string(str2,1);
2721 int uLevel;
2722 int count;
2723 int i;
2724 int snum;
2725 int job;
2726 struct pack_desc desc;
2727 print_queue_struct *queue=NULL;
2728 print_status_struct status;
2730 uLevel = SVAL(p,2);
2732 memset((char *)&desc,'\0',sizeof(desc));
2733 memset((char *)&status,'\0',sizeof(status));
2735 DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
2737 /* check it's a supported varient */
2738 if (strcmp(str1,"WWrLh") != 0) return False;
2739 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2741 job = SVAL(p,0);
2742 snum = print_job_snum(job);
2744 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2746 count = print_queue_status(snum,&queue,&status);
2747 for (i = 0; i < count; i++) {
2748 if (queue[i].job == job) break;
2750 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2751 desc.base = *rdata;
2752 desc.buflen = mdrcnt;
2754 if (init_package(&desc,1,0)) {
2755 if (i < count) {
2756 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2757 *rdata_len = desc.usedlen;
2759 else {
2760 desc.errcode = NERR_JobNotFound;
2761 *rdata_len = 0;
2765 *rparam_len = 6;
2766 *rparam = REALLOC(*rparam,*rparam_len);
2767 SSVALS(*rparam,0,desc.errcode);
2768 SSVAL(*rparam,2,0);
2769 SSVAL(*rparam,4,desc.neededlen);
2771 if (queue) free(queue);
2773 DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
2774 return(True);
2777 static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
2778 int mdrcnt,int mprcnt,
2779 char **rdata,char **rparam,
2780 int *rdata_len,int *rparam_len)
2782 char *str1 = param+2;
2783 char *str2 = skip_string(str1,1);
2784 char *p = skip_string(str2,1);
2785 char* name = p;
2786 int uLevel;
2787 int count;
2788 int i, succnt=0;
2789 int snum;
2790 struct pack_desc desc;
2791 print_queue_struct *queue=NULL;
2792 print_status_struct status;
2794 memset((char *)&desc,'\0',sizeof(desc));
2795 memset((char *)&status,'\0',sizeof(status));
2797 p = skip_string(p,1);
2798 uLevel = SVAL(p,0);
2800 DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
2802 /* check it's a supported varient */
2803 if (strcmp(str1,"zWrLeh") != 0) return False;
2804 if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
2805 if (!check_printjob_info(&desc,uLevel,str2)) return False;
2807 snum = lp_servicenumber(name);
2808 if (snum < 0 && pcap_printername_ok(name,NULL)) {
2809 int pnum = lp_servicenumber(PRINTERS_NAME);
2810 if (pnum >= 0) {
2811 lp_add_printer(name,pnum);
2812 snum = lp_servicenumber(name);
2816 if (snum < 0 || !VALID_SNUM(snum)) return(False);
2818 count = print_queue_status(snum,&queue,&status);
2819 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2820 desc.base = *rdata;
2821 desc.buflen = mdrcnt;
2823 if (init_package(&desc,count,0)) {
2824 succnt = 0;
2825 for (i = 0; i < count; i++) {
2826 fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
2827 if (desc.errcode == NERR_Success) succnt = i+1;
2831 *rdata_len = desc.usedlen;
2833 *rparam_len = 8;
2834 *rparam = REALLOC(*rparam,*rparam_len);
2835 SSVALS(*rparam,0,desc.errcode);
2836 SSVAL(*rparam,2,0);
2837 SSVAL(*rparam,4,succnt);
2838 SSVAL(*rparam,6,count);
2840 if (queue) free(queue);
2842 DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
2843 return(True);
2846 static int check_printdest_info(struct pack_desc* desc,
2847 int uLevel, char* id)
2849 desc->subformat = NULL;
2850 switch( uLevel ) {
2851 case 0: desc->format = "B9"; break;
2852 case 1: desc->format = "B9B21WWzW"; break;
2853 case 2: desc->format = "z"; break;
2854 case 3: desc->format = "zzzWWzzzWW"; break;
2855 default: return False;
2857 if (strcmp(desc->format,id) != 0) return False;
2858 return True;
2861 static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
2862 struct pack_desc* desc)
2864 char buf[100];
2865 strncpy(buf,SERVICE(snum),sizeof(buf)-1);
2866 buf[sizeof(buf)-1] = 0;
2867 strupper(buf);
2868 if (uLevel <= 1) {
2869 PACKS(desc,"B9",buf); /* szName */
2870 if (uLevel == 1) {
2871 PACKS(desc,"B21",""); /* szUserName */
2872 PACKI(desc,"W",0); /* uJobId */
2873 PACKI(desc,"W",0); /* fsStatus */
2874 PACKS(desc,"z",""); /* pszStatus */
2875 PACKI(desc,"W",0); /* time */
2878 if (uLevel == 2 || uLevel == 3) {
2879 PACKS(desc,"z",buf); /* pszPrinterName */
2880 if (uLevel == 3) {
2881 PACKS(desc,"z",""); /* pszUserName */
2882 PACKS(desc,"z",""); /* pszLogAddr */
2883 PACKI(desc,"W",0); /* uJobId */
2884 PACKI(desc,"W",0); /* fsStatus */
2885 PACKS(desc,"z",""); /* pszStatus */
2886 PACKS(desc,"z",""); /* pszComment */
2887 PACKS(desc,"z","NULL"); /* pszDrivers */
2888 PACKI(desc,"W",0); /* time */
2889 PACKI(desc,"W",0); /* pad1 */
2894 static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
2895 int mdrcnt,int mprcnt,
2896 char **rdata,char **rparam,
2897 int *rdata_len,int *rparam_len)
2899 char *str1 = param+2;
2900 char *str2 = skip_string(str1,1);
2901 char *p = skip_string(str2,1);
2902 char* PrinterName = p;
2903 int uLevel;
2904 struct pack_desc desc;
2905 int snum;
2907 memset((char *)&desc,'\0',sizeof(desc));
2909 p = skip_string(p,1);
2910 uLevel = SVAL(p,0);
2912 DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
2914 /* check it's a supported varient */
2915 if (strcmp(str1,"zWrLh") != 0) return False;
2916 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2918 snum = lp_servicenumber(PrinterName);
2919 if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
2920 int pnum = lp_servicenumber(PRINTERS_NAME);
2921 if (pnum >= 0) {
2922 lp_add_printer(PrinterName,pnum);
2923 snum = lp_servicenumber(PrinterName);
2927 if (snum < 0) {
2928 *rdata_len = 0;
2929 desc.errcode = NERR_DestNotFound;
2930 desc.neededlen = 0;
2932 else {
2933 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2934 desc.base = *rdata;
2935 desc.buflen = mdrcnt;
2936 if (init_package(&desc,1,0)) {
2937 fill_printdest_info(conn,snum,uLevel,&desc);
2939 *rdata_len = desc.usedlen;
2942 *rparam_len = 6;
2943 *rparam = REALLOC(*rparam,*rparam_len);
2944 SSVALS(*rparam,0,desc.errcode);
2945 SSVAL(*rparam,2,0);
2946 SSVAL(*rparam,4,desc.neededlen);
2948 DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
2949 return(True);
2952 static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
2953 int mdrcnt,int mprcnt,
2954 char **rdata,char **rparam,
2955 int *rdata_len,int *rparam_len)
2957 char *str1 = param+2;
2958 char *str2 = skip_string(str1,1);
2959 char *p = skip_string(str2,1);
2960 int uLevel;
2961 int queuecnt;
2962 int i, n, succnt=0;
2963 struct pack_desc desc;
2964 int services = lp_numservices();
2966 memset((char *)&desc,'\0',sizeof(desc));
2968 uLevel = SVAL(p,0);
2970 DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
2972 /* check it's a supported varient */
2973 if (strcmp(str1,"WrLeh") != 0) return False;
2974 if (!check_printdest_info(&desc,uLevel,str2)) return False;
2976 queuecnt = 0;
2977 for (i = 0; i < services; i++)
2978 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
2979 queuecnt++;
2981 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
2982 desc.base = *rdata;
2983 desc.buflen = mdrcnt;
2984 if (init_package(&desc,queuecnt,0)) {
2985 succnt = 0;
2986 n = 0;
2987 for (i = 0; i < services; i++) {
2988 if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
2989 fill_printdest_info(conn,i,uLevel,&desc);
2990 n++;
2991 if (desc.errcode == NERR_Success) succnt = n;
2996 *rdata_len = desc.usedlen;
2998 *rparam_len = 8;
2999 *rparam = REALLOC(*rparam,*rparam_len);
3000 SSVALS(*rparam,0,desc.errcode);
3001 SSVAL(*rparam,2,0);
3002 SSVAL(*rparam,4,succnt);
3003 SSVAL(*rparam,6,queuecnt);
3005 DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
3006 return(True);
3009 static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3010 int mdrcnt,int mprcnt,
3011 char **rdata,char **rparam,
3012 int *rdata_len,int *rparam_len)
3014 char *str1 = param+2;
3015 char *str2 = skip_string(str1,1);
3016 char *p = skip_string(str2,1);
3017 int uLevel;
3018 int succnt;
3019 struct pack_desc desc;
3021 memset((char *)&desc,'\0',sizeof(desc));
3023 uLevel = SVAL(p,0);
3025 DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
3027 /* check it's a supported varient */
3028 if (strcmp(str1,"WrLeh") != 0) return False;
3029 if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
3031 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3032 desc.base = *rdata;
3033 desc.buflen = mdrcnt;
3034 if (init_package(&desc,1,0)) {
3035 PACKS(&desc,"B41","NULL");
3038 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3040 *rdata_len = desc.usedlen;
3042 *rparam_len = 8;
3043 *rparam = REALLOC(*rparam,*rparam_len);
3044 SSVALS(*rparam,0,desc.errcode);
3045 SSVAL(*rparam,2,0);
3046 SSVAL(*rparam,4,succnt);
3047 SSVAL(*rparam,6,1);
3049 DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
3050 return(True);
3053 static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3054 int mdrcnt,int mprcnt,
3055 char **rdata,char **rparam,
3056 int *rdata_len,int *rparam_len)
3058 char *str1 = param+2;
3059 char *str2 = skip_string(str1,1);
3060 char *p = skip_string(str2,1);
3061 int uLevel;
3062 int succnt;
3063 struct pack_desc desc;
3065 memset((char *)&desc,'\0',sizeof(desc));
3067 uLevel = SVAL(p,0);
3069 DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
3071 /* check it's a supported varient */
3072 if (strcmp(str1,"WrLeh") != 0) return False;
3073 if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
3075 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3076 desc.base = *rdata;
3077 desc.buflen = mdrcnt;
3078 desc.format = str2;
3079 if (init_package(&desc,1,0)) {
3080 PACKS(&desc,"B13","lpd");
3083 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3085 *rdata_len = desc.usedlen;
3087 *rparam_len = 8;
3088 *rparam = REALLOC(*rparam,*rparam_len);
3089 SSVALS(*rparam,0,desc.errcode);
3090 SSVAL(*rparam,2,0);
3091 SSVAL(*rparam,4,succnt);
3092 SSVAL(*rparam,6,1);
3094 DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
3095 return(True);
3098 static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
3099 int mdrcnt,int mprcnt,
3100 char **rdata,char **rparam,
3101 int *rdata_len,int *rparam_len)
3103 char *str1 = param+2;
3104 char *str2 = skip_string(str1,1);
3105 char *p = skip_string(str2,1);
3106 int uLevel;
3107 int succnt;
3108 struct pack_desc desc;
3110 memset((char *)&desc,'\0',sizeof(desc));
3112 uLevel = SVAL(p,0);
3114 DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
3116 /* check it's a supported varient */
3117 if (strcmp(str1,"WrLeh") != 0) return False;
3118 if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
3120 if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
3121 memset((char *)&desc,'\0',sizeof(desc));
3122 desc.base = *rdata;
3123 desc.buflen = mdrcnt;
3124 desc.format = str2;
3125 if (init_package(&desc,1,0)) {
3126 PACKS(&desc,"B13","lp0");
3129 succnt = (desc.errcode == NERR_Success ? 1 : 0);
3131 *rdata_len = desc.usedlen;
3133 *rparam_len = 8;
3134 *rparam = REALLOC(*rparam,*rparam_len);
3135 SSVALS(*rparam,0,desc.errcode);
3136 SSVAL(*rparam,2,0);
3137 SSVAL(*rparam,4,succnt);
3138 SSVAL(*rparam,6,1);
3140 DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
3141 return(True);
3144 /****************************************************************************
3145 The buffer was too small
3146 ****************************************************************************/
3148 static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
3149 int mdrcnt,int mprcnt,
3150 char **rdata,char **rparam,
3151 int *rdata_len,int *rparam_len)
3153 *rparam_len = MIN(*rparam_len,mprcnt);
3154 *rparam = REALLOC(*rparam,*rparam_len);
3156 *rdata_len = 0;
3158 SSVAL(*rparam,0,NERR_BufTooSmall);
3160 DEBUG(3,("Supplied buffer too small in API command\n"));
3162 return(True);
3166 /****************************************************************************
3167 The request is not supported
3168 ****************************************************************************/
3170 static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
3171 int mdrcnt,int mprcnt,
3172 char **rdata,char **rparam,
3173 int *rdata_len,int *rparam_len)
3175 *rparam_len = 4;
3176 *rparam = REALLOC(*rparam,*rparam_len);
3178 *rdata_len = 0;
3180 SSVAL(*rparam,0,NERR_notsupported);
3181 SSVAL(*rparam,2,0); /* converter word */
3183 DEBUG(3,("Unsupported API command\n"));
3185 return(True);
3191 struct
3193 char *name;
3194 int id;
3195 BOOL (*fn)(connection_struct *,uint16,char *,char *,
3196 int,int,char **,char **,int *,int *);
3197 int flags;
3198 } api_commands[] = {
3199 {"RNetShareEnum", 0, api_RNetShareEnum,0},
3200 {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
3201 {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
3202 {"RNetGroupGetUsers", 52, api_RNetGroupGetUsers,0},
3203 {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
3204 {"NetUserGetGroups", 59, api_NetUserGetGroups,0},
3205 {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
3206 {"DosPrintQEnum", 69, api_DosPrintQEnum,0},
3207 {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
3208 {"WPrintQueuePause", 74, api_WPrintQueuePurge,0},
3209 {"WPrintQueueResume", 75, api_WPrintQueuePurge,0},
3210 {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
3211 {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
3212 {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
3213 {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
3214 {"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
3215 {"WPrintDestEnum", 84, api_WPrintDestEnum,0},
3216 {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
3217 {"NetRemoteTOD", 91, api_NetRemoteTOD,0},
3218 {"WPrintQueuePurge", 103, api_WPrintQueuePurge,0},
3219 {"NetServerEnum", 104, api_RNetServerEnum,0},
3220 {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
3221 {"SetUserPassword", 115, api_SetUserPassword,0},
3222 {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
3223 {"PrintJobInfo", 147, api_PrintJobInfo,0},
3224 {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
3225 {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
3226 {"WPrintPortEnum", 207, api_WPrintPortEnum,0},
3227 {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
3228 {NULL, -1, api_Unsupported,0}};
3231 /****************************************************************************
3232 Handle remote api calls
3233 ****************************************************************************/
3235 int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
3236 int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
3238 int api_command;
3239 char *rdata = NULL;
3240 char *rparam = NULL;
3241 int rdata_len = 0;
3242 int rparam_len = 0;
3243 BOOL reply=False;
3244 int i;
3246 if (!params) {
3247 DEBUG(0,("ERROR: NULL params in api_reply()\n"));
3248 return 0;
3251 api_command = SVAL(params,0);
3253 DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
3254 api_command,
3255 params+2,
3256 skip_string(params+2,1),
3257 tdscnt,tpscnt,mdrcnt,mprcnt));
3259 for (i=0;api_commands[i].name;i++) {
3260 if (api_commands[i].id == api_command && api_commands[i].fn) {
3261 DEBUG(3,("Doing %s\n",api_commands[i].name));
3262 break;
3266 rdata = (char *)malloc(1024);
3267 if (rdata)
3268 memset(rdata,'\0',1024);
3270 rparam = (char *)malloc(1024);
3271 if (rparam)
3272 memset(rparam,'\0',1024);
3274 if(!rdata || !rparam) {
3275 DEBUG(0,("api_reply: malloc fail !\n"));
3276 return -1;
3279 reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
3280 &rdata,&rparam,&rdata_len,&rparam_len);
3283 if (rdata_len > mdrcnt ||
3284 rparam_len > mprcnt) {
3285 reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
3286 &rdata,&rparam,&rdata_len,&rparam_len);
3289 /* if we get False back then it's actually unsupported */
3290 if (!reply)
3291 api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
3292 &rdata,&rparam,&rdata_len,&rparam_len);
3294 send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
3296 if (rdata )
3297 free(rdata);
3298 if (rparam)
3299 free(rparam);
3301 return -1;
3305 #undef OLD_NTDOMAIN