mirror of
https://github.com/samba-team/samba.git
synced 2025-01-07 17:18:11 +03:00
a521fe8a27
also added paranoid code in the main process() loop of smbd to detect
when smbd is looping uselessly. This should stop the "smbd is chewing
lots of cpu" reports
(This used to be commit 8e9dce34d5
)
2852 lines
74 KiB
C
2852 lines
74 KiB
C
/*
|
|
Unix SMB/Netbios implementation.
|
|
Version 1.9.
|
|
Inter-process communication and named pipe handling
|
|
Copyright (C) Andrew Tridgell 1992-1995
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
/*
|
|
This file handles the named pipe and mailslot calls
|
|
in the SMBtrans protocol
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
#ifdef CHECK_TYPES
|
|
#undef CHECK_TYPES
|
|
#endif
|
|
#define CHECK_TYPES 0
|
|
|
|
extern int DEBUGLEVEL;
|
|
extern int maxxmit;
|
|
extern files_struct Files[];
|
|
extern connection_struct Connections[];
|
|
|
|
extern fstring local_machine;
|
|
|
|
#define NERR_Success 0
|
|
#define NERR_badpass 86
|
|
#define NERR_notsupported 50
|
|
|
|
#define NERR_BASE (2100)
|
|
#define NERR_BufTooSmall (NERR_BASE+23)
|
|
#define NERR_JobNotFound (NERR_BASE+51)
|
|
#define NERR_DestNotFound (NERR_BASE+52)
|
|
#define ERROR_INVALID_LEVEL 124
|
|
#define ERROR_MORE_DATA 234
|
|
|
|
#define REALLOC(ptr,size) Realloc(ptr,MAX((size),4*1024))
|
|
|
|
#define ACCESS_READ 0x01
|
|
#define ACCESS_WRITE 0x02
|
|
#define ACCESS_CREATE 0x04
|
|
|
|
#define SHPWLEN 8 /* share password length */
|
|
#define NNLEN 12 /* 8.3 net name length */
|
|
#define SNLEN 15 /* service name length */
|
|
#define QNLEN 12 /* queue name maximum length */
|
|
|
|
extern int Client;
|
|
|
|
static int CopyExpanded(int cnum, int snum, char** dst, char* src, int* n)
|
|
{
|
|
pstring buf;
|
|
int l;
|
|
|
|
if (!src || !dst || !n || !(*dst)) return(0);
|
|
|
|
StrnCpy(buf,src,sizeof(buf)/2);
|
|
string_sub(buf,"%S",lp_servicename(snum));
|
|
standard_sub(cnum,buf);
|
|
StrnCpy(*dst,buf,*n);
|
|
l = strlen(*dst) + 1;
|
|
(*dst) += l;
|
|
(*n) -= l;
|
|
return l;
|
|
}
|
|
|
|
static int CopyAndAdvance(char** dst, char* src, int* n)
|
|
{
|
|
int l;
|
|
if (!src || !dst || !n || !(*dst)) return(0);
|
|
StrnCpy(*dst,src,*n);
|
|
l = strlen(*dst) + 1;
|
|
(*dst) += l;
|
|
(*n) -= l;
|
|
return l;
|
|
}
|
|
|
|
static int StrlenExpanded(int cnum, int snum, char* s)
|
|
{
|
|
pstring buf;
|
|
if (!s) return(0);
|
|
StrnCpy(buf,s,sizeof(buf)/2);
|
|
string_sub(buf,"%S",lp_servicename(snum));
|
|
standard_sub(cnum,buf);
|
|
return strlen(buf) + 1;
|
|
}
|
|
|
|
static char* Expand(int cnum, int snum, char* s)
|
|
{
|
|
static pstring buf;
|
|
if (!s) return(NULL);
|
|
StrnCpy(buf,s,sizeof(buf)/2);
|
|
string_sub(buf,"%S",lp_servicename(snum));
|
|
standard_sub(cnum,buf);
|
|
return &buf[0];
|
|
}
|
|
|
|
/*******************************************************************
|
|
check a API string for validity when we only need to check the prefix
|
|
******************************************************************/
|
|
static BOOL prefix_ok(char *str,char *prefix)
|
|
{
|
|
return(strncmp(str,prefix,strlen(prefix)) == 0);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
send a trans reply
|
|
****************************************************************************/
|
|
static void send_trans_reply(char *outbuf,char *data,char *param,uint16 *setup,
|
|
int ldata,int lparam,int lsetup)
|
|
{
|
|
int i;
|
|
int this_ldata,this_lparam;
|
|
int tot_data=0,tot_param=0;
|
|
int align;
|
|
|
|
this_lparam = MIN(lparam,maxxmit - (500+lsetup*SIZEOFWORD)); /* hack */
|
|
this_ldata = MIN(ldata,maxxmit - (500+lsetup*SIZEOFWORD+this_lparam));
|
|
|
|
align = (this_lparam%4);
|
|
|
|
set_message(outbuf,10+lsetup,align+this_ldata+this_lparam,True);
|
|
if (this_lparam)
|
|
memcpy(smb_buf(outbuf),param,this_lparam);
|
|
if (this_ldata)
|
|
memcpy(smb_buf(outbuf)+this_lparam+align,data,this_ldata);
|
|
|
|
SSVAL(outbuf,smb_vwv0,lparam);
|
|
SSVAL(outbuf,smb_vwv1,ldata);
|
|
SSVAL(outbuf,smb_vwv3,this_lparam);
|
|
SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf),outbuf));
|
|
SSVAL(outbuf,smb_vwv5,0);
|
|
SSVAL(outbuf,smb_vwv6,this_ldata);
|
|
SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+this_lparam+align,outbuf));
|
|
SSVAL(outbuf,smb_vwv8,0);
|
|
SSVAL(outbuf,smb_vwv9,lsetup);
|
|
for (i=0;i<lsetup;i++)
|
|
SSVAL(outbuf,smb_vwv10+i*SIZEOFWORD,setup[i]);
|
|
|
|
show_msg(outbuf);
|
|
send_smb(Client,outbuf);
|
|
|
|
tot_data = this_ldata;
|
|
tot_param = this_lparam;
|
|
|
|
while (tot_data < ldata || tot_param < lparam)
|
|
{
|
|
this_lparam = MIN(lparam-tot_param,maxxmit - 500); /* hack */
|
|
this_ldata = MIN(ldata-tot_data,maxxmit - (500+this_lparam));
|
|
|
|
align = (this_lparam%4);
|
|
|
|
set_message(outbuf,10,this_ldata+this_lparam+align,False);
|
|
if (this_lparam)
|
|
memcpy(smb_buf(outbuf),param+tot_param,this_lparam);
|
|
if (this_ldata)
|
|
memcpy(smb_buf(outbuf)+this_lparam+align,data+tot_data,this_ldata);
|
|
|
|
SSVAL(outbuf,smb_vwv3,this_lparam);
|
|
SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf),outbuf));
|
|
SSVAL(outbuf,smb_vwv5,tot_param);
|
|
SSVAL(outbuf,smb_vwv6,this_ldata);
|
|
SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+this_lparam+align,outbuf));
|
|
SSVAL(outbuf,smb_vwv8,tot_data);
|
|
SSVAL(outbuf,smb_vwv9,0);
|
|
|
|
show_msg(outbuf);
|
|
send_smb(Client,outbuf);
|
|
|
|
tot_data += this_ldata;
|
|
tot_param += this_lparam;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
get a print queue
|
|
****************************************************************************/
|
|
|
|
struct pack_desc {
|
|
char* format; /* formatstring for structure */
|
|
char* subformat; /* subformat for structure */
|
|
char* base; /* baseaddress of buffer */
|
|
int buflen; /* remaining size for fixed part; on init: length of base */
|
|
int subcount; /* count of substructures */
|
|
char* structbuf; /* pointer into buffer for remaining fixed part */
|
|
int stringlen; /* remaining size for variable part */
|
|
char* stringbuf; /* pointer into buffer for remaining variable part */
|
|
int neededlen; /* total needed size */
|
|
int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
|
|
char* curpos; /* current position; pointer into format or subformat */
|
|
int errcode;
|
|
};
|
|
|
|
static int get_counter(char** p)
|
|
{
|
|
int i, n;
|
|
if (!p || !(*p)) return(1);
|
|
if (!isdigit(**p)) return 1;
|
|
for (n = 0;;) {
|
|
i = **p;
|
|
if (isdigit(i))
|
|
n = 10 * n + (i - '0');
|
|
else
|
|
return n;
|
|
(*p)++;
|
|
}
|
|
}
|
|
|
|
static int getlen(char* p)
|
|
{
|
|
int n = 0;
|
|
if (!p) return(0);
|
|
while (*p) {
|
|
switch( *p++ ) {
|
|
case 'W': /* word (2 byte) */
|
|
n += 2;
|
|
break;
|
|
case 'N': /* count of substructures (word) at end */
|
|
n += 2;
|
|
break;
|
|
case 'D': /* double word (4 byte) */
|
|
case 'z': /* offset to zero terminated string (4 byte) */
|
|
case 'l': /* offset to user data (4 byte) */
|
|
n += 4;
|
|
break;
|
|
case 'b': /* offset to data (with counter) (4 byte) */
|
|
n += 4;
|
|
get_counter(&p);
|
|
break;
|
|
case 'B': /* byte (with optional counter) */
|
|
n += get_counter(&p);
|
|
break;
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static BOOL init_package(struct pack_desc* p, int count, int subcount)
|
|
{
|
|
int n = p->buflen;
|
|
int i;
|
|
|
|
if (!p->format || !p->base) return(False);
|
|
|
|
i = count * getlen(p->format);
|
|
if (p->subformat) i += subcount * getlen(p->subformat);
|
|
p->structbuf = p->base;
|
|
p->neededlen = 0;
|
|
p->usedlen = 0;
|
|
p->subcount = 0;
|
|
p->curpos = p->format;
|
|
if (i > n) {
|
|
i = n = 0;
|
|
p->errcode = NERR_BufTooSmall;
|
|
}
|
|
|
|
p->errcode = NERR_Success;
|
|
p->buflen = i;
|
|
n -= i;
|
|
p->stringbuf = p->base + i;
|
|
p->stringlen = n;
|
|
return(p->errcode == NERR_Success);
|
|
}
|
|
|
|
#ifdef __STDC__
|
|
static int package(struct pack_desc* p, ...)
|
|
{
|
|
#else
|
|
static int package(va_alist)
|
|
va_dcl
|
|
{
|
|
struct pack_desc* p;
|
|
#endif
|
|
va_list args;
|
|
int needed=0, stringneeded;
|
|
char* str=NULL;
|
|
int is_string=0, stringused;
|
|
int32 temp;
|
|
|
|
#ifdef __STDC__
|
|
va_start(args,p);
|
|
#else
|
|
va_start(args);
|
|
p = va_arg(args,struct pack_desc *);
|
|
#endif
|
|
|
|
if (!*p->curpos) {
|
|
if (!p->subcount)
|
|
p->curpos = p->format;
|
|
else {
|
|
p->curpos = p->subformat;
|
|
p->subcount--;
|
|
}
|
|
}
|
|
#if CHECK_TYPES
|
|
str = va_arg(args,char*);
|
|
if (strncmp(str,p->curpos,strlen(str)) != 0) {
|
|
DEBUG(2,("type error in package: %s instead of %*s\n",str,
|
|
strlen(str),p->curpos));
|
|
va_end(args);
|
|
#if AJT
|
|
ajt_panic();
|
|
#endif
|
|
return 0;
|
|
}
|
|
#endif
|
|
stringneeded = -1;
|
|
|
|
if (!p->curpos) return(0);
|
|
|
|
switch( *p->curpos++ ) {
|
|
case 'W': /* word (2 byte) */
|
|
needed = 2;
|
|
temp = va_arg(args,int);
|
|
if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
|
|
break;
|
|
case 'N': /* count of substructures (word) at end */
|
|
needed = 2;
|
|
p->subcount = va_arg(args,int);
|
|
if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
|
|
break;
|
|
case 'D': /* double word (4 byte) */
|
|
needed = 4;
|
|
temp = va_arg(args,int);
|
|
if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
|
|
break;
|
|
case 'B': /* byte (with optional counter) */
|
|
needed = get_counter(&p->curpos);
|
|
{
|
|
char *s = va_arg(args,char*);
|
|
if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed);
|
|
}
|
|
break;
|
|
case 'z': /* offset to zero terminated string (4 byte) */
|
|
str = va_arg(args,char*);
|
|
stringneeded = (str ? strlen(str)+1 : 0);
|
|
is_string = 1;
|
|
break;
|
|
case 'l': /* offset to user data (4 byte) */
|
|
str = va_arg(args,char*);
|
|
stringneeded = va_arg(args,int);
|
|
is_string = 0;
|
|
break;
|
|
case 'b': /* offset to data (with counter) (4 byte) */
|
|
str = va_arg(args,char*);
|
|
stringneeded = get_counter(&p->curpos);
|
|
is_string = 0;
|
|
break;
|
|
}
|
|
va_end(args);
|
|
if (stringneeded >= 0) {
|
|
needed = 4;
|
|
if (p->buflen >= needed) {
|
|
stringused = stringneeded;
|
|
if (stringused > p->stringlen) {
|
|
stringused = (is_string ? p->stringlen : 0);
|
|
if (p->errcode == NERR_Success) p->errcode = ERROR_MORE_DATA;
|
|
}
|
|
if (!stringused)
|
|
SIVAL(p->structbuf,0,0);
|
|
else {
|
|
SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
|
|
memcpy(p->stringbuf,str?str:"",stringused);
|
|
if (is_string) p->stringbuf[stringused-1] = '\0';
|
|
p->stringbuf += stringused;
|
|
p->stringlen -= stringused;
|
|
p->usedlen += stringused;
|
|
}
|
|
}
|
|
p->neededlen += stringneeded;
|
|
}
|
|
p->neededlen += needed;
|
|
if (p->buflen >= needed) {
|
|
p->structbuf += needed;
|
|
p->buflen -= needed;
|
|
p->usedlen += needed;
|
|
}
|
|
else {
|
|
if (p->errcode == NERR_Success) p->errcode = NERR_BufTooSmall;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#if CHECK_TYPES
|
|
#define PACK(desc,t,v) package(desc,t,v,0,0,0,0)
|
|
#define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0)
|
|
#else
|
|
#define PACK(desc,t,v) package(desc,v)
|
|
#define PACKl(desc,t,v,l) package(desc,v,l)
|
|
#endif
|
|
|
|
static void PACKI(struct pack_desc* desc,char *t,int v)
|
|
{
|
|
PACK(desc,t,v);
|
|
}
|
|
|
|
static void PACKS(struct pack_desc* desc,char *t,char *v)
|
|
{
|
|
PACK(desc,t,v);
|
|
}
|
|
|
|
static void PackDriverData(struct pack_desc* desc)
|
|
{
|
|
char drivdata[4+4+32];
|
|
SIVAL(drivdata,0,sizeof drivdata); /* cb */
|
|
SIVAL(drivdata,4,1000); /* lVersion */
|
|
memset(drivdata+8,0,32); /* szDeviceName */
|
|
strcpy(drivdata+8,"NULL");
|
|
PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
|
|
}
|
|
|
|
static int check_printq_info(struct pack_desc* desc,
|
|
int uLevel, const char* id1, const char* id2)
|
|
{
|
|
desc->subformat = NULL;
|
|
switch( uLevel ) {
|
|
case 0:
|
|
desc->format = "B13";
|
|
break;
|
|
case 1:
|
|
desc->format = "B13BWWWzzzzzWW";
|
|
break;
|
|
case 2:
|
|
desc->format = "B13BWWWzzzzzWN";
|
|
desc->subformat = "WB21BB16B10zWWzDDz";
|
|
break;
|
|
case 3:
|
|
desc->format = "zWWWWzzzzWWzzl";
|
|
break;
|
|
case 4:
|
|
desc->format = "zWWWWzzzzWNzzl";
|
|
desc->subformat = "WWzWWDDzz";
|
|
break;
|
|
case 5:
|
|
desc->format = "z";
|
|
break;
|
|
default: return False;
|
|
}
|
|
if (strcmp(desc->format,id1) != 0) return False;
|
|
if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
|
|
return True;
|
|
}
|
|
|
|
static void fill_printjob_info(int cnum, int snum, int uLevel,
|
|
struct pack_desc* desc,
|
|
print_queue_struct* queue, int n)
|
|
{
|
|
time_t t = queue->time;
|
|
|
|
/* the client expects localtime */
|
|
t -= TimeDiff(t);
|
|
|
|
PACKI(desc,"W",((snum%0xFF)<<8) | (queue->job%0xFF)); /* uJobId */
|
|
if (uLevel == 1) {
|
|
PACKS(desc,"B21",queue->user); /* szUserName */
|
|
PACKS(desc,"B",""); /* pad */
|
|
PACKS(desc,"B16",""); /* szNotifyName */
|
|
PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
|
|
PACKS(desc,"z",""); /* pszParms */
|
|
PACKI(desc,"W",n+1); /* uPosition */
|
|
PACKI(desc,"W",queue->status); /* fsStatus */
|
|
PACKS(desc,"z",""); /* pszStatus */
|
|
PACKI(desc,"D",t); /* ulSubmitted */
|
|
PACKI(desc,"D",queue->size); /* ulSize */
|
|
PACKS(desc,"z",queue->file); /* pszComment */
|
|
}
|
|
if (uLevel == 2 || uLevel == 3) {
|
|
PACKI(desc,"W",queue->priority); /* uPriority */
|
|
PACKS(desc,"z",queue->user); /* pszUserName */
|
|
PACKI(desc,"W",n+1); /* uPosition */
|
|
PACKI(desc,"W",queue->status); /* fsStatus */
|
|
PACKI(desc,"D",t); /* ulSubmitted */
|
|
PACKI(desc,"D",queue->size); /* ulSize */
|
|
PACKS(desc,"z","Samba"); /* pszComment */
|
|
PACKS(desc,"z",queue->file); /* pszDocument */
|
|
if (uLevel == 3) {
|
|
PACKS(desc,"z",""); /* pszNotifyName */
|
|
PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
|
|
PACKS(desc,"z",""); /* pszParms */
|
|
PACKS(desc,"z",""); /* pszStatus */
|
|
PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
|
|
PACKS(desc,"z","lpd"); /* pszQProcName */
|
|
PACKS(desc,"z",""); /* pszQProcParms */
|
|
PACKS(desc,"z","NULL"); /* pszDriverName */
|
|
PackDriverData(desc); /* pDriverData */
|
|
PACKS(desc,"z",""); /* pszPrinterName */
|
|
}
|
|
}
|
|
}
|
|
|
|
static void fill_printq_info(int cnum, int snum, int uLevel,
|
|
struct pack_desc* desc,
|
|
int count, print_queue_struct* queue,
|
|
print_status_struct* status)
|
|
{
|
|
if (uLevel < 3) {
|
|
PACKS(desc,"B13",SERVICE(snum));
|
|
} else {
|
|
PACKS(desc,"z",Expand(cnum,snum,SERVICE(snum)));
|
|
}
|
|
if (uLevel == 1 || uLevel == 2) {
|
|
PACKS(desc,"B",""); /* alignment */
|
|
PACKI(desc,"W",5); /* priority */
|
|
PACKI(desc,"W",0); /* start time */
|
|
PACKI(desc,"W",0); /* until time */
|
|
PACKS(desc,"z",""); /* pSepFile */
|
|
PACKS(desc,"z","lpd"); /* pPrProc */
|
|
PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
|
|
PACKS(desc,"z",""); /* pParms */
|
|
if (snum < 0) {
|
|
PACKS(desc,"z","UNKNOWN PRINTER");
|
|
PACKI(desc,"W",LPSTAT_ERROR);
|
|
}
|
|
else if (!status || !status->message[0]) {
|
|
PACKS(desc,"z",Expand(cnum,snum,lp_comment(snum)));
|
|
PACKI(desc,"W",LPSTAT_OK); /* status */
|
|
} else {
|
|
PACKS(desc,"z",status->message);
|
|
PACKI(desc,"W",status->status); /* status */
|
|
}
|
|
PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
|
|
}
|
|
if (uLevel == 3 || uLevel == 4) {
|
|
PACKI(desc,"W",5); /* uPriority */
|
|
PACKI(desc,"W",0); /* uStarttime */
|
|
PACKI(desc,"W",0); /* uUntiltime */
|
|
PACKI(desc,"W",5); /* pad1 */
|
|
PACKS(desc,"z",""); /* pszSepFile */
|
|
PACKS(desc,"z","lpd"); /* pszPrProc */
|
|
PACKS(desc,"z",""); /* pszParms */
|
|
if (!status || !status->message[0]) {
|
|
PACKS(desc,"z",Expand(cnum,snum,lp_comment(snum))); /* pszComment */
|
|
PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
|
|
} else {
|
|
PACKS(desc,"z",status->message); /* pszComment */
|
|
PACKI(desc,"W",status->status); /* fsStatus */
|
|
}
|
|
PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
|
|
PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
|
|
PACKS(desc,"z","NULL"); /* pszDriverName */
|
|
PackDriverData(desc); /* pDriverData */
|
|
}
|
|
if (uLevel == 2 || uLevel == 4) {
|
|
int i;
|
|
for (i=0;i<count;i++)
|
|
fill_printjob_info(cnum,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
|
|
}
|
|
|
|
DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",SERVICE(snum),count));
|
|
}
|
|
|
|
static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
char *QueueName = p;
|
|
int uLevel,cbBuf;
|
|
int count=0;
|
|
int snum;
|
|
char* str3;
|
|
struct pack_desc desc;
|
|
print_queue_struct *queue=NULL;
|
|
print_status_struct status;
|
|
|
|
bzero(&status,sizeof(status));
|
|
bzero(&desc,sizeof(desc));
|
|
|
|
p = skip_string(p,1);
|
|
uLevel = SVAL(p,0);
|
|
cbBuf = SVAL(p,2);
|
|
str3 = p + 4;
|
|
|
|
if ((p = strchr(QueueName,'%'))) *p = 0;
|
|
|
|
DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
|
|
|
|
/* check it's a supported varient */
|
|
if (!prefix_ok(str1,"zWrLh")) return False;
|
|
if (!check_printq_info(&desc,uLevel,str2,str3)) return False;
|
|
|
|
snum = lp_servicenumber(QueueName);
|
|
if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
|
|
int pnum = lp_servicenumber(PRINTERS_NAME);
|
|
if (pnum >= 0) {
|
|
lp_add_printer(QueueName,pnum);
|
|
snum = lp_servicenumber(QueueName);
|
|
}
|
|
}
|
|
|
|
if (snum < 0 || !VALID_SNUM(snum)) return(False);
|
|
|
|
count = get_printqueue(snum,cnum,&queue,&status);
|
|
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
|
|
desc.base = *rdata;
|
|
desc.buflen = mdrcnt;
|
|
if (init_package(&desc,1,count)) {
|
|
desc.subcount = count;
|
|
fill_printq_info(cnum,snum,uLevel,&desc,count,queue,&status);
|
|
}
|
|
|
|
*rdata_len = desc.usedlen;
|
|
|
|
*rparam_len = 6;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVALS(*rparam,0,desc.errcode);
|
|
SSVAL(*rparam,2,0);
|
|
SSVAL(*rparam,4,desc.neededlen);
|
|
|
|
DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
|
|
|
|
if (queue) free(queue);
|
|
|
|
return(True);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
view list of all print jobs on all queues
|
|
****************************************************************************/
|
|
static BOOL api_DosPrintQEnum(int cnum, int uid, char* param, char* data,
|
|
int mdrcnt, int mprcnt,
|
|
char **rdata, char** rparam,
|
|
int *rdata_len, int *rparam_len)
|
|
{
|
|
char *param_format = param+2;
|
|
char *output_format1 = skip_string(param_format,1);
|
|
char *p = skip_string(output_format1,1);
|
|
int uLevel = SVAL(p,0);
|
|
char *output_format2 = p + 4;
|
|
int services = lp_numservices();
|
|
int i, n;
|
|
struct pack_desc desc;
|
|
print_queue_struct **queue = NULL;
|
|
print_status_struct *status = NULL;
|
|
int* subcntarr = NULL;
|
|
int queuecnt, subcnt=0, succnt=0;
|
|
|
|
bzero(&desc,sizeof(desc));
|
|
|
|
DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
|
|
|
|
if (prefix_ok(param_format,"WrLeh")) return False;
|
|
if (!check_printq_info(&desc,uLevel,output_format1,output_format2))
|
|
return False;
|
|
queuecnt = 0;
|
|
for (i = 0; i < services; i++)
|
|
if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
|
|
queuecnt++;
|
|
if (uLevel > 0) {
|
|
queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*));
|
|
memset(queue,0,queuecnt*sizeof(print_queue_struct*));
|
|
status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct));
|
|
memset(status,0,queuecnt*sizeof(print_status_struct));
|
|
subcntarr = (int*)malloc(queuecnt*sizeof(int));
|
|
subcnt = 0;
|
|
n = 0;
|
|
for (i = 0; i < services; i++)
|
|
if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
|
|
subcntarr[n] = get_printqueue(i,cnum,&queue[n],&status[n]);
|
|
subcnt += subcntarr[n];
|
|
n++;
|
|
}
|
|
}
|
|
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
|
|
desc.base = *rdata;
|
|
desc.buflen = mdrcnt;
|
|
|
|
if (init_package(&desc,queuecnt,subcnt)) {
|
|
n = 0;
|
|
succnt = 0;
|
|
for (i = 0; i < services; i++)
|
|
if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
|
|
fill_printq_info(cnum,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
|
|
n++;
|
|
if (desc.errcode == NERR_Success) succnt = n;
|
|
}
|
|
}
|
|
|
|
if (subcntarr) free(subcntarr);
|
|
|
|
*rdata_len = desc.usedlen;
|
|
*rparam_len = 8;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVALS(*rparam,0,desc.errcode);
|
|
SSVAL(*rparam,2,0);
|
|
SSVAL(*rparam,4,succnt);
|
|
SSVAL(*rparam,6,queuecnt);
|
|
|
|
for (i = 0; i < queuecnt; i++) {
|
|
if (queue && queue[i]) free(queue[i]);
|
|
}
|
|
|
|
if (queue) free(queue);
|
|
if (status) free(status);
|
|
|
|
return True;
|
|
}
|
|
|
|
/****************************************************************************
|
|
get info level for a server list query
|
|
****************************************************************************/
|
|
static BOOL check_server_info(int uLevel, char* id)
|
|
{
|
|
switch( uLevel ) {
|
|
case 0:
|
|
if (strcmp(id,"B16") != 0) return False;
|
|
break;
|
|
case 1:
|
|
if (strcmp(id,"B16BBDz") != 0) return False;
|
|
break;
|
|
default:
|
|
return False;
|
|
}
|
|
return True;
|
|
}
|
|
|
|
/* used for server information: client, nameserv and ipc */
|
|
struct srv_info_struct
|
|
{
|
|
fstring name;
|
|
uint32 type;
|
|
fstring comment;
|
|
fstring domain; /* used ONLY in ipc.c NOT namework.c */
|
|
BOOL server_added; /* used ONLY in ipc.c NOT namework.c */
|
|
};
|
|
|
|
/*******************************************************************
|
|
filter out unwanted server info
|
|
******************************************************************/
|
|
static BOOL filter_server_info(struct srv_info_struct *server,
|
|
BOOL domains,
|
|
char *domain, uint32 request)
|
|
{
|
|
if (*domain == 0)
|
|
{
|
|
if (strequal(lp_workgroup(), server->domain)) {
|
|
return True;
|
|
}
|
|
else if (domains)
|
|
{
|
|
DEBUG(4,("primary domain:reject %8x %s %s\n",request,server->name,server->domain));
|
|
return False;
|
|
}
|
|
else if ((request & SV_TYPE_DOMAIN_ENUM) &&
|
|
(server->type & SV_TYPE_DOMAIN_ENUM))
|
|
{
|
|
DEBUG(4,("rej:DOM %8x: %s %s\n",server->type,server->name,server->domain));
|
|
return False;
|
|
}
|
|
|
|
return True;
|
|
}
|
|
else
|
|
{
|
|
if (strequal(domain, server->domain))
|
|
{
|
|
/*
|
|
if (request == SV_TYPE_LOCAL_LIST_ONLY &&
|
|
!(server->type & SV_TYPE_LOCAL_LIST_ONLY))
|
|
{
|
|
DEBUG(4,("rej:LOC %8x: ok %s %s\n",request,server->name,server->domain));
|
|
return False;
|
|
}
|
|
*/
|
|
if ((request == (SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM)) &&
|
|
!(server->type&SV_TYPE_DOMAIN_ENUM))
|
|
{
|
|
DEBUG(4,("rej:LOCDOM %8x: ok %s %s\n",request,server->name,server->domain));
|
|
return False;
|
|
}
|
|
|
|
return True;
|
|
}
|
|
else if (!domains)
|
|
{
|
|
DEBUG(4,("domain:%s %s %s\n",domain,server->name,server->domain));
|
|
return False;
|
|
}
|
|
return True;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
get server info lists from the files saved by nmbd. Return the
|
|
number of entries
|
|
******************************************************************/
|
|
static int get_server_info(uint32 servertype,
|
|
struct srv_info_struct **servers, BOOL domains,
|
|
char *domain)
|
|
{
|
|
FILE *f;
|
|
pstring fname;
|
|
int count=0;
|
|
int alloced=0;
|
|
pstring line;
|
|
|
|
strcpy(fname,lp_lockdir());
|
|
trim_string(fname,NULL,"/");
|
|
strcat(fname,"/");
|
|
strcat(fname,SERVER_LIST);
|
|
|
|
f = fopen(fname,"r");
|
|
|
|
if (!f) {
|
|
DEBUG(4,("Can't open %s - %s\n",fname,strerror(errno)));
|
|
return(0);
|
|
}
|
|
|
|
/* request for everything is code for request all servers */
|
|
if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM;
|
|
|
|
DEBUG(4,("Servertype search: %8x domains:%s\n",servertype,BOOLSTR(domains)));
|
|
|
|
while (!feof(f))
|
|
{
|
|
fstring stype;
|
|
struct srv_info_struct *s;
|
|
char *ptr = line;
|
|
BOOL ok = True;
|
|
*ptr = 0;
|
|
|
|
fgets(line,sizeof(line)-1,f);
|
|
if (!*line) continue;
|
|
|
|
if (count == alloced) {
|
|
alloced += 10;
|
|
(*servers) = (struct srv_info_struct *)
|
|
Realloc(*servers,sizeof(**servers)*alloced);
|
|
if (!(*servers)) return(0);
|
|
bzero((char *)((*servers)+count),sizeof(**servers)*(alloced-count));
|
|
}
|
|
s = &(*servers)[count];
|
|
|
|
if (!next_token(&ptr,s->name , NULL)) continue;
|
|
if (!next_token(&ptr,stype , NULL)) continue;
|
|
if (!next_token(&ptr,s->comment, NULL)) continue;
|
|
if (!next_token(&ptr,s->domain , NULL)) {
|
|
/* this allows us to cope with an old nmbd */
|
|
strcpy(s->domain,my_workgroup());
|
|
}
|
|
|
|
if (sscanf(stype,"%X",&s->type) != 1) {
|
|
DEBUG(4,("r:host file "));
|
|
ok = False;
|
|
}
|
|
|
|
/* doesn't match up: don't want it */
|
|
if (!(servertype & s->type)) {
|
|
DEBUG(4,("r:serv type "));
|
|
ok = False;
|
|
}
|
|
|
|
if ((servertype == ~SV_TYPE_DOMAIN_ENUM) &&
|
|
(s->type & SV_TYPE_DOMAIN_ENUM))
|
|
{
|
|
DEBUG(4,("s:all x dom "));
|
|
ok = False;
|
|
}
|
|
|
|
if (domains && !(domain && *domain && strequal(domain, s->domain)))
|
|
{
|
|
if (!(s->type & SV_TYPE_DOMAIN_ENUM))
|
|
{
|
|
DEBUG(4,("r:dom enum "));
|
|
ok = False;
|
|
}
|
|
}
|
|
|
|
if (ok)
|
|
{
|
|
DEBUG(4,("**SV** %20s %8x %25s %15s\n",
|
|
s->name, s->type, s->comment, s->domain));
|
|
|
|
s->type |= SV_TYPE_LOCAL_LIST_ONLY;
|
|
s->server_added = True;
|
|
count++;
|
|
}
|
|
else
|
|
{
|
|
DEBUG(4,("%20s %8x %25s %15s\n",
|
|
s->name, s->type, s->comment, s->domain));
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
return(count);
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
fill in a server info structure
|
|
******************************************************************/
|
|
static int fill_srv_info(struct srv_info_struct *service,
|
|
int uLevel, char **buf, int *buflen,
|
|
char **stringbuf, int *stringspace, char *baseaddr)
|
|
{
|
|
int struct_len;
|
|
char* p;
|
|
char* p2;
|
|
int l2;
|
|
int len;
|
|
|
|
switch (uLevel) {
|
|
case 0: struct_len = 16; break;
|
|
case 1: struct_len = 26; break;
|
|
default: return -1;
|
|
}
|
|
|
|
if (!buf)
|
|
{
|
|
len = 0;
|
|
switch (uLevel)
|
|
{
|
|
case 1:
|
|
len = strlen(service->comment)+1;
|
|
break;
|
|
}
|
|
|
|
if (buflen) *buflen = struct_len;
|
|
if (stringspace) *stringspace = len;
|
|
return struct_len + len;
|
|
}
|
|
|
|
len = struct_len;
|
|
p = *buf;
|
|
if (*buflen < struct_len) return -1;
|
|
if (stringbuf)
|
|
{
|
|
p2 = *stringbuf;
|
|
l2 = *stringspace;
|
|
}
|
|
else
|
|
{
|
|
p2 = p + struct_len;
|
|
l2 = *buflen - struct_len;
|
|
}
|
|
if (!baseaddr) baseaddr = p;
|
|
|
|
switch (uLevel)
|
|
{
|
|
case 0:
|
|
StrnCpy(p,service->name,15);
|
|
break;
|
|
|
|
case 1:
|
|
StrnCpy(p,service->name,15);
|
|
SIVAL(p,18,service->type);
|
|
SIVAL(p,22,PTR_DIFF(p2,baseaddr));
|
|
len += CopyAndAdvance(&p2,service->comment,&l2);
|
|
break;
|
|
}
|
|
|
|
if (stringbuf)
|
|
{
|
|
*buf = p + struct_len;
|
|
*buflen -= struct_len;
|
|
*stringbuf = p2;
|
|
*stringspace = l2;
|
|
}
|
|
else
|
|
{
|
|
*buf = p2;
|
|
*buflen -= len;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
|
|
static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
|
|
{
|
|
return(strcmp(s1->name,s2->name));
|
|
}
|
|
|
|
/****************************************************************************
|
|
view list of servers available (or possibly domains). The info is
|
|
extracted from lists saved by nmbd on the local host
|
|
****************************************************************************/
|
|
static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
|
|
int mdrcnt, int mprcnt, char **rdata,
|
|
char **rparam, int *rdata_len, int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
int uLevel = SVAL(p,0);
|
|
int buf_len = SVAL(p,2);
|
|
uint32 servertype = IVAL(p,4);
|
|
char *p2;
|
|
int data_len, fixed_len, string_len;
|
|
int f_len, s_len;
|
|
struct srv_info_struct *servers=NULL;
|
|
int counted=0,total=0;
|
|
int i;
|
|
fstring domain;
|
|
BOOL domains;
|
|
BOOL domain_request;
|
|
BOOL local_request = servertype & SV_TYPE_LOCAL_LIST_ONLY;
|
|
|
|
/*if (servertype == SV_TYPE_ALL) servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);*/
|
|
if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM;
|
|
|
|
domain_request = servertype & SV_TYPE_DOMAIN_ENUM;
|
|
|
|
domain[0] = 0;
|
|
p += 8;
|
|
|
|
if (!prefix_ok(str1,"WrLehD")) return False;
|
|
if (!check_server_info(uLevel,str2)) return False;
|
|
|
|
DEBUG(4, ("server request level: %s %8x ", str2, servertype));
|
|
DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
|
|
DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
|
|
|
|
if (strcmp(str1, "WrLehDO") == 0)
|
|
{
|
|
domains = False;
|
|
}
|
|
else if (strcmp(str1, "WrLehDz") == 0)
|
|
{
|
|
domains = True;
|
|
StrnCpy(domain, p, sizeof(fstring)-1);
|
|
}
|
|
|
|
if (lp_browse_list())
|
|
{
|
|
total = get_server_info(servertype,&servers,domains,domain);
|
|
}
|
|
|
|
data_len = fixed_len = string_len = 0;
|
|
|
|
qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
|
|
|
|
{
|
|
char *lastname=NULL;
|
|
|
|
for (i=0;i<total;i++)
|
|
{
|
|
struct srv_info_struct *s = &servers[i];
|
|
if (filter_server_info(s,domains,domain,
|
|
local_request|domain_request))
|
|
{
|
|
if (lastname && strequal(lastname,s->name)) continue;
|
|
lastname = s->name;
|
|
data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
|
|
DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
|
|
s->name, s->type, s->comment, s->domain));
|
|
|
|
if (data_len <= buf_len)
|
|
{
|
|
counted++;
|
|
fixed_len += f_len;
|
|
string_len += s_len;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*rdata_len = fixed_len + string_len;
|
|
*rdata = REALLOC(*rdata,*rdata_len);
|
|
bzero(*rdata,*rdata_len);
|
|
|
|
p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
|
|
p = *rdata;
|
|
f_len = fixed_len;
|
|
s_len = string_len;
|
|
|
|
{
|
|
char *lastname=NULL;
|
|
int count2 = counted;
|
|
for (i = 0; i < total && count2;i++)
|
|
{
|
|
struct srv_info_struct *s = &servers[i];
|
|
if (filter_server_info(s,domains,domain,local_request|domain_request))
|
|
{
|
|
if (lastname && strequal(lastname,s->name)) continue;
|
|
lastname = s->name;
|
|
fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
|
|
DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
|
|
s->name, s->type, s->comment, s->domain));
|
|
count2--;
|
|
}
|
|
}
|
|
}
|
|
|
|
*rparam_len = 8;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVAL(*rparam,0,NERR_Success);
|
|
SSVAL(*rparam,2,0);
|
|
SSVAL(*rparam,4,counted);
|
|
SSVAL(*rparam,6,total);
|
|
|
|
if (servers) free(servers);
|
|
|
|
DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
|
|
domain,uLevel,counted,total));
|
|
|
|
return(True);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
get info about a share
|
|
****************************************************************************/
|
|
static BOOL check_share_info(int uLevel, char* id)
|
|
{
|
|
switch( uLevel ) {
|
|
case 0:
|
|
if (strcmp(id,"B13") != 0) return False;
|
|
break;
|
|
case 1:
|
|
if (strcmp(id,"B13BWz") != 0) return False;
|
|
break;
|
|
case 2:
|
|
if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
|
|
break;
|
|
case 91:
|
|
if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
|
|
break;
|
|
default: return False;
|
|
}
|
|
return True;
|
|
}
|
|
|
|
static int fill_share_info(int cnum, int snum, int uLevel,
|
|
char** buf, int* buflen,
|
|
char** stringbuf, int* stringspace, char* baseaddr)
|
|
{
|
|
int struct_len;
|
|
char* p;
|
|
char* p2;
|
|
int l2;
|
|
int len;
|
|
|
|
switch( uLevel ) {
|
|
case 0: struct_len = 13; break;
|
|
case 1: struct_len = 20; break;
|
|
case 2: struct_len = 40; break;
|
|
case 91: struct_len = 68; break;
|
|
default: return -1;
|
|
}
|
|
|
|
|
|
if (!buf)
|
|
{
|
|
len = 0;
|
|
if (uLevel > 0) len += StrlenExpanded(cnum,snum,lp_comment(snum));
|
|
if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
|
|
if (buflen) *buflen = struct_len;
|
|
if (stringspace) *stringspace = len;
|
|
return struct_len + len;
|
|
}
|
|
|
|
len = struct_len;
|
|
p = *buf;
|
|
if ((*buflen) < struct_len) return -1;
|
|
if (stringbuf)
|
|
{
|
|
p2 = *stringbuf;
|
|
l2 = *stringspace;
|
|
}
|
|
else
|
|
{
|
|
p2 = p + struct_len;
|
|
l2 = (*buflen) - struct_len;
|
|
}
|
|
if (!baseaddr) baseaddr = p;
|
|
|
|
StrnCpy(p,lp_servicename(snum),13);
|
|
|
|
if (uLevel > 0)
|
|
{
|
|
int type;
|
|
CVAL(p,13) = 0;
|
|
type = STYPE_DISKTREE;
|
|
if (lp_print_ok(snum)) type = STYPE_PRINTQ;
|
|
if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
|
|
SSVAL(p,14,type); /* device type */
|
|
SIVAL(p,16,PTR_DIFF(p2,baseaddr));
|
|
len += CopyExpanded(cnum,snum,&p2,lp_comment(snum),&l2);
|
|
}
|
|
|
|
if (uLevel > 1)
|
|
{
|
|
SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
|
|
SSVALS(p,22,-1); /* max uses */
|
|
SSVAL(p,24,1); /* current uses */
|
|
SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
|
|
len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
|
|
memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
|
|
}
|
|
|
|
if (uLevel > 2)
|
|
{
|
|
memset(p+40,0,SHPWLEN+2);
|
|
SSVAL(p,50,0);
|
|
SIVAL(p,52,0);
|
|
SSVAL(p,56,0);
|
|
SSVAL(p,58,0);
|
|
SIVAL(p,60,0);
|
|
SSVAL(p,64,0);
|
|
SSVAL(p,66,0);
|
|
}
|
|
|
|
if (stringbuf)
|
|
{
|
|
(*buf) = p + struct_len;
|
|
(*buflen) -= struct_len;
|
|
(*stringbuf) = p2;
|
|
(*stringspace) = l2;
|
|
}
|
|
else
|
|
{
|
|
(*buf) = p2;
|
|
(*buflen) -= len;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
static BOOL api_RNetShareGetInfo(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *netname = skip_string(str2,1);
|
|
char *p = skip_string(netname,1);
|
|
int uLevel = SVAL(p,0);
|
|
int snum = find_service(netname);
|
|
|
|
if (snum < 0) return False;
|
|
|
|
/* check it's a supported varient */
|
|
if (!prefix_ok(str1,"zWrLh")) return False;
|
|
if (!check_share_info(uLevel,str2)) return False;
|
|
|
|
*rdata = REALLOC(*rdata,mdrcnt);
|
|
p = *rdata;
|
|
*rdata_len = fill_share_info(cnum,snum,uLevel,&p,&mdrcnt,0,0,0);
|
|
if (*rdata_len < 0) return False;
|
|
|
|
*rparam_len = 6;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVAL(*rparam,0,NERR_Success);
|
|
SSVAL(*rparam,2,0); /* converter word */
|
|
SSVAL(*rparam,4,*rdata_len);
|
|
|
|
return(True);
|
|
}
|
|
|
|
/****************************************************************************
|
|
view list of shares available
|
|
****************************************************************************/
|
|
static BOOL api_RNetShareEnum(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
int uLevel = SVAL(p,0);
|
|
int buf_len = SVAL(p,2);
|
|
char *p2;
|
|
int count=lp_numservices();
|
|
int total=0,counted=0;
|
|
int i;
|
|
int data_len, fixed_len, string_len;
|
|
int f_len, s_len;
|
|
|
|
if (!prefix_ok(str1,"WrLeh")) return False;
|
|
if (!check_share_info(uLevel,str2)) return False;
|
|
|
|
data_len = fixed_len = string_len = 0;
|
|
for (i=0;i<count;i++)
|
|
if (lp_browseable(i) && lp_snum_ok(i))
|
|
{
|
|
total++;
|
|
data_len += fill_share_info(cnum,i,uLevel,0,&f_len,0,&s_len,0);
|
|
if (data_len <= buf_len)
|
|
{
|
|
counted++;
|
|
fixed_len += f_len;
|
|
string_len += s_len;
|
|
}
|
|
}
|
|
*rdata_len = fixed_len + string_len;
|
|
*rdata = REALLOC(*rdata,*rdata_len);
|
|
memset(*rdata,0,*rdata_len);
|
|
|
|
p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
|
|
p = *rdata;
|
|
f_len = fixed_len;
|
|
s_len = string_len;
|
|
for (i = 0; i < count;i++)
|
|
if (lp_browseable(i) && lp_snum_ok(i))
|
|
if (fill_share_info(cnum,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
|
|
break;
|
|
|
|
*rparam_len = 8;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVAL(*rparam,0,NERR_Success);
|
|
SSVAL(*rparam,2,0);
|
|
SSVAL(*rparam,4,counted);
|
|
SSVAL(*rparam,6,total);
|
|
|
|
DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
|
|
counted,total,uLevel,
|
|
buf_len,*rdata_len,mdrcnt));
|
|
return(True);
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
get the time of day info
|
|
****************************************************************************/
|
|
static BOOL api_NetRemoteTOD(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *p;
|
|
*rparam_len = 4;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
|
|
*rdata_len = 21;
|
|
*rdata = REALLOC(*rdata,*rdata_len);
|
|
|
|
SSVAL(*rparam,0,NERR_Success);
|
|
SSVAL(*rparam,2,0); /* converter word */
|
|
|
|
p = *rdata;
|
|
|
|
{
|
|
struct tm *t;
|
|
time_t unixdate = time(NULL);
|
|
|
|
put_dos_date3(p,0,unixdate); /* this is the time that is looked at
|
|
by NT in a "net time" operation,
|
|
it seems to ignore the one below */
|
|
|
|
/* the client expects to get localtime, not GMT, in this bit
|
|
(I think, this needs testing) */
|
|
t = LocalTime(&unixdate);
|
|
|
|
SIVAL(p,4,0); /* msecs ? */
|
|
CVAL(p,8) = t->tm_hour;
|
|
CVAL(p,9) = t->tm_min;
|
|
CVAL(p,10) = t->tm_sec;
|
|
CVAL(p,11) = 0; /* hundredths of seconds */
|
|
SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
|
|
SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
|
|
CVAL(p,16) = t->tm_mday;
|
|
CVAL(p,17) = t->tm_mon + 1;
|
|
SSVAL(p,18,1900+t->tm_year);
|
|
CVAL(p,20) = t->tm_wday;
|
|
}
|
|
|
|
|
|
return(True);
|
|
}
|
|
|
|
/****************************************************************************
|
|
set the user password
|
|
****************************************************************************/
|
|
static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *p = skip_string(param+2,2);
|
|
fstring user;
|
|
fstring pass1,pass2;
|
|
|
|
strcpy(user,p);
|
|
|
|
p = skip_string(p,1);
|
|
|
|
StrnCpy(pass1,p,16);
|
|
StrnCpy(pass2,p+16,16);
|
|
|
|
*rparam_len = 4;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
|
|
*rdata_len = 0;
|
|
|
|
SSVAL(*rparam,0,NERR_Success);
|
|
SSVAL(*rparam,2,0); /* converter word */
|
|
|
|
DEBUG(3,("Set password for <%s>\n",user));
|
|
|
|
if (!password_ok(user,pass1,strlen(pass1),NULL,False) ||
|
|
!chgpasswd(user,pass1,pass2))
|
|
SSVAL(*rparam,0,NERR_badpass);
|
|
|
|
bzero(pass1,sizeof(fstring));
|
|
bzero(pass2,sizeof(fstring));
|
|
|
|
return(True);
|
|
}
|
|
|
|
/****************************************************************************
|
|
delete a print job
|
|
Form: <W> <>
|
|
****************************************************************************/
|
|
static BOOL api_RDosPrintJobDel(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
int function = SVAL(param,0);
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
int jobid = (SVAL(p,0)&0xFF); /* the snum and jobid are encoded
|
|
by the print queue api */
|
|
int snum = (SVAL(p,0)>>8);
|
|
int i, count;
|
|
|
|
|
|
/* check it's a supported varient */
|
|
if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
|
|
return(False);
|
|
|
|
*rparam_len = 4;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
|
|
*rdata_len = 0;
|
|
|
|
SSVAL(*rparam,0,NERR_Success);
|
|
|
|
if (snum >= 0 && VALID_SNUM(snum))
|
|
{
|
|
print_queue_struct *queue=NULL;
|
|
lpq_reset(snum);
|
|
count = get_printqueue(snum,cnum,&queue,NULL);
|
|
|
|
for (i=0;i<count;i++)
|
|
if ((queue[i].job%0xFF) == jobid)
|
|
{
|
|
switch (function) {
|
|
case 81: /* delete */
|
|
DEBUG(3,("Deleting queue entry %d\n",queue[i].job));
|
|
del_printqueue(cnum,snum,queue[i].job);
|
|
break;
|
|
case 82: /* pause */
|
|
case 83: /* resume */
|
|
DEBUG(3,("%s queue entry %d\n",
|
|
(function==82?"pausing":"resuming"),queue[i].job));
|
|
status_printjob(cnum,snum,queue[i].job,
|
|
(function==82?LPQ_PAUSED:LPQ_QUEUED));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (i==count)
|
|
SSVAL(*rparam,0,NERR_JobNotFound);
|
|
|
|
if (queue) free(queue);
|
|
}
|
|
|
|
SSVAL(*rparam,2,0); /* converter word */
|
|
|
|
return(True);
|
|
}
|
|
|
|
static BOOL api_WPrintQueuePurge(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *QueueName = skip_string(str2,1);
|
|
int snum;
|
|
|
|
/* check it's a supported varient */
|
|
if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
|
|
return(False);
|
|
|
|
*rparam_len = 4;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
|
|
*rdata_len = 0;
|
|
|
|
SSVAL(*rparam,0,NERR_Success);
|
|
SSVAL(*rparam,2,0); /* converter word */
|
|
|
|
snum = lp_servicenumber(QueueName);
|
|
if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
|
|
int pnum = lp_servicenumber(PRINTERS_NAME);
|
|
if (pnum >= 0) {
|
|
lp_add_printer(QueueName,pnum);
|
|
snum = lp_servicenumber(QueueName);
|
|
}
|
|
}
|
|
|
|
if (snum >= 0 && VALID_SNUM(snum)) {
|
|
print_queue_struct *queue=NULL;
|
|
int i, count;
|
|
lpq_reset(snum);
|
|
|
|
count = get_printqueue(snum,cnum,&queue,NULL);
|
|
for (i = 0; i < count; i++)
|
|
del_printqueue(cnum,snum,queue[i].job);
|
|
|
|
if (queue) free(queue);
|
|
}
|
|
|
|
DEBUG(3,("Print queue purge, queue=%s\n",QueueName));
|
|
|
|
return(True);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
set the property of a print job (undocumented?)
|
|
? function = 0xb -> set name of print job
|
|
? function = 0x6 -> move print job up/down
|
|
Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
|
|
or <WWsTP> <WB21BB16B10zWWzDDz>
|
|
****************************************************************************/
|
|
static int check_printjob_info(struct pack_desc* desc,
|
|
int uLevel, char* id)
|
|
{
|
|
desc->subformat = NULL;
|
|
switch( uLevel ) {
|
|
case 0: desc->format = "W"; break;
|
|
case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
|
|
case 2: desc->format = "WWzWWDDzz"; break;
|
|
case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
|
|
default: return False;
|
|
}
|
|
if (strcmp(desc->format,id) != 0) return False;
|
|
return True;
|
|
}
|
|
|
|
static BOOL api_PrintJobInfo(int cnum,int uid,char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
struct pack_desc desc;
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
int jobid = (SVAL(p,0)&0xFF); /* the snum and jobid are encoded
|
|
by the print queue api */
|
|
int snum = (SVAL(p,0)>>8);
|
|
int uLevel = SVAL(p,2);
|
|
int function = SVAL(p,4); /* what is this ?? */
|
|
int i;
|
|
char *s = data;
|
|
|
|
*rparam_len = 4;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
|
|
*rdata_len = 0;
|
|
|
|
/* check it's a supported varient */
|
|
if ((strcmp(str1,"WWsTP")) || (!check_printjob_info(&desc,uLevel,str2)))
|
|
return(False);
|
|
|
|
switch (function) {
|
|
case 0x6: /* change job place in the queue, data gives the new place */
|
|
if (snum >= 0 && VALID_SNUM(snum))
|
|
{
|
|
print_queue_struct *queue=NULL;
|
|
int count;
|
|
|
|
lpq_reset(snum);
|
|
count = get_printqueue(snum,cnum,&queue,NULL);
|
|
for (i=0;i<count;i++) /* find job */
|
|
if ((queue[i].job%0xFF) == jobid) break;
|
|
|
|
if (i==count) {
|
|
desc.errcode=NERR_JobNotFound;
|
|
if (queue) free(queue);
|
|
}
|
|
else {
|
|
desc.errcode=NERR_Success;
|
|
i++;
|
|
#if 0
|
|
{
|
|
int place= SVAL(data,0);
|
|
/* we currently have no way of doing this. Can any unix do it? */
|
|
if (i < place) /* move down */;
|
|
else if (i > place ) /* move up */;
|
|
}
|
|
#endif
|
|
desc.errcode=NERR_notsupported; /* not yet supported */
|
|
if (queue) free(queue);
|
|
}
|
|
}
|
|
else desc.errcode=NERR_JobNotFound;
|
|
break;
|
|
case 0xb: /* change print job name, data gives the name */
|
|
/* jobid, snum should be zero */
|
|
if (isalpha(*s))
|
|
{
|
|
pstring name;
|
|
int l = 0;
|
|
while (l<64 && *s)
|
|
{
|
|
if (issafe(*s)) name[l++] = *s;
|
|
s++;
|
|
}
|
|
name[l] = 0;
|
|
|
|
DEBUG(3,("Setting print name to %s\n",name));
|
|
|
|
for (i=0;i<MAX_OPEN_FILES;i++)
|
|
if (Files[i].open && Files[i].print_file)
|
|
{
|
|
pstring wd;
|
|
GetWd(wd);
|
|
unbecome_user();
|
|
|
|
if (!become_user(Files[i].cnum,uid) ||
|
|
!become_service(Files[i].cnum,True))
|
|
break;
|
|
|
|
if (sys_rename(Files[i].name,name) == 0)
|
|
string_set(&Files[i].name,name);
|
|
break;
|
|
}
|
|
}
|
|
desc.errcode=NERR_Success;
|
|
|
|
break;
|
|
default: /* not implemented */
|
|
return False;
|
|
}
|
|
|
|
SSVALS(*rparam,0,desc.errcode);
|
|
SSVAL(*rparam,2,0); /* converter word */
|
|
|
|
return(True);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
get info about the server
|
|
****************************************************************************/
|
|
static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
int uLevel = SVAL(p,0);
|
|
char *p2;
|
|
int struct_len;
|
|
|
|
DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
|
|
|
|
/* check it's a supported varient */
|
|
if (!prefix_ok(str1,"WrLh")) return False;
|
|
switch( uLevel ) {
|
|
case 0:
|
|
if (strcmp(str2,"B16") != 0) return False;
|
|
struct_len = 16;
|
|
break;
|
|
case 1:
|
|
if (strcmp(str2,"B16BBDz") != 0) return False;
|
|
struct_len = 26;
|
|
break;
|
|
case 2:
|
|
if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
|
|
!= 0) return False;
|
|
struct_len = 134;
|
|
break;
|
|
case 3:
|
|
if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
|
|
!= 0) return False;
|
|
struct_len = 144;
|
|
break;
|
|
case 20:
|
|
if (strcmp(str2,"DN") != 0) return False;
|
|
struct_len = 6;
|
|
break;
|
|
case 50:
|
|
if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
|
|
struct_len = 42;
|
|
break;
|
|
default: return False;
|
|
}
|
|
|
|
*rdata_len = mdrcnt;
|
|
*rdata = REALLOC(*rdata,*rdata_len);
|
|
|
|
p = *rdata;
|
|
p2 = p + struct_len;
|
|
if (uLevel != 20) {
|
|
StrnCpy(p,local_machine,16);
|
|
strupper(p);
|
|
}
|
|
p += 16;
|
|
if (uLevel > 0)
|
|
{
|
|
struct srv_info_struct *servers=NULL;
|
|
int i,count;
|
|
pstring comment;
|
|
uint32 servertype=SV_TYPE_SERVER_UNIX|SV_TYPE_WORKSTATION|
|
|
SV_TYPE_SERVER|SV_TYPE_TIME_SOURCE;
|
|
|
|
strcpy(comment,lp_serverstring());
|
|
|
|
if ((count=get_server_info(SV_TYPE_ALL,&servers,False,NULL))>0) {
|
|
for (i=0;i<count;i++)
|
|
if (strequal(servers[i].name,local_machine)) {
|
|
servertype = servers[i].type;
|
|
strcpy(comment,servers[i].comment);
|
|
}
|
|
}
|
|
if (servers) free(servers);
|
|
|
|
SCVAL(p,0,2); /* version_major */
|
|
SCVAL(p,1,0); /* version_minor */
|
|
SIVAL(p,2,servertype);
|
|
if (mdrcnt == struct_len) {
|
|
SIVAL(p,6,0);
|
|
} else {
|
|
SIVAL(p,6,PTR_DIFF(p2,*rdata));
|
|
standard_sub(cnum,comment);
|
|
StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
|
|
p2 = skip_string(p2,1);
|
|
}
|
|
}
|
|
if (uLevel > 1)
|
|
{
|
|
return False; /* not yet implemented */
|
|
}
|
|
|
|
*rdata_len = PTR_DIFF(p2,*rdata);
|
|
|
|
*rparam_len = 6;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVAL(*rparam,0,NERR_Success);
|
|
SSVAL(*rparam,2,0); /* converter word */
|
|
SSVAL(*rparam,4,*rdata_len);
|
|
|
|
return(True);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
get info about the server
|
|
****************************************************************************/
|
|
static BOOL api_NetWkstaGetInfo(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
char *p2;
|
|
extern pstring sesssetup_user;
|
|
int level = SVAL(p,0);
|
|
|
|
DEBUG(4,("NetWkstaGetInfo level %d\n",level));
|
|
|
|
*rparam_len = 6;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
|
|
/* check it's a supported varient */
|
|
if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
|
|
return(False);
|
|
|
|
*rdata_len = mdrcnt + 1024;
|
|
*rdata = REALLOC(*rdata,*rdata_len);
|
|
|
|
SSVAL(*rparam,0,NERR_Success);
|
|
SSVAL(*rparam,2,0); /* converter word */
|
|
|
|
p = *rdata;
|
|
p2 = p + 22;
|
|
|
|
SIVAL(p,0,PTR_DIFF(p2,*rdata));
|
|
strcpy(p2,local_machine);
|
|
p2 = skip_string(p2,1);
|
|
p += 4;
|
|
|
|
SIVAL(p,0,PTR_DIFF(p2,*rdata));
|
|
strcpy(p2,sesssetup_user);
|
|
p2 = skip_string(p2,1);
|
|
p += 4;
|
|
|
|
SIVAL(p,0,PTR_DIFF(p2,*rdata));
|
|
strcpy(p2,my_workgroup());
|
|
p2 = skip_string(p2,1);
|
|
p += 4;
|
|
|
|
SCVAL(p,0,2); /* major version?? */
|
|
SCVAL(p,1,1); /* minor version?? */
|
|
p += 2;
|
|
|
|
SIVAL(p,0,PTR_DIFF(p2,*rdata));
|
|
strcpy(p2,my_workgroup()); /* login domain?? */
|
|
p2 = skip_string(p2,1);
|
|
p += 4;
|
|
|
|
SIVAL(p,0,PTR_DIFF(p2,*rdata));
|
|
strcpy(p2,"");
|
|
p2 = skip_string(p2,1);
|
|
p += 4;
|
|
|
|
*rdata_len = PTR_DIFF(p2,*rdata);
|
|
|
|
SSVAL(*rparam,4,*rdata_len);
|
|
|
|
return(True);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
get info about a user
|
|
****************************************************************************/
|
|
|
|
#define USER_PRIV_GUEST 0
|
|
#define USER_PRIV_USER 1
|
|
#define USER_PRIV_ADMIN 2
|
|
|
|
static BOOL api_RNetUserGetInfo(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *UserName = skip_string(str2,1);
|
|
char *p = skip_string(UserName,1);
|
|
int uLevel = SVAL(p,0);
|
|
char *p2;
|
|
|
|
*rparam_len = 6;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
|
|
/* check it's a supported varient */
|
|
if (strcmp(str1,"zWrLh") != 0) return False;
|
|
switch( uLevel ) {
|
|
case 0: p2 = "B21"; break;
|
|
case 1: p2 = "B21BB16DWzzWz"; break;
|
|
case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
|
|
case 10: p2 = "B21Bzzz"; break;
|
|
case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
|
|
default: return False;
|
|
}
|
|
if (strcmp(p2,str2) != 0) return False;
|
|
|
|
*rdata_len = mdrcnt + 1024;
|
|
*rdata = REALLOC(*rdata,*rdata_len);
|
|
|
|
SSVAL(*rparam,0,NERR_Success);
|
|
SSVAL(*rparam,2,0); /* converter word */
|
|
|
|
p = *rdata;
|
|
p2 = p + 86;
|
|
|
|
memset(p,0,21);
|
|
strcpy(p,UserName);
|
|
if (uLevel > 0) {
|
|
SCVAL(p,21,0);
|
|
*p2 = 0;
|
|
if (uLevel >= 10) {
|
|
SIVAL(p,22,PTR_DIFF(p2,p)); /* comment */
|
|
strcpy(p2,"<Comment>");
|
|
p2 = skip_string(p2,1);
|
|
SIVAL(p,26,PTR_DIFF(p2,p)); /* user_comment */
|
|
strcpy(p2,"<UserComment>");
|
|
p2 = skip_string(p2,1);
|
|
SIVAL(p,30,PTR_DIFF(p2,p)); /* full name */
|
|
strcpy(p2,"<FullName>");
|
|
p2 = skip_string(p2,1);
|
|
}
|
|
if (uLevel == 11) { /* modelled after NTAS 3.51 reply */
|
|
SSVAL(p,34,USER_PRIV_USER); /* user privilege */
|
|
SIVAL(p,36,0); /* auth flags */
|
|
SIVALS(p,40,-1); /* password age */
|
|
SIVAL(p,44,PTR_DIFF(p2,p)); /* home dir */
|
|
strcpy(p2,"\\\\%L\\HOMES");
|
|
standard_sub_basic(p2);
|
|
p2 = skip_string(p2,1);
|
|
SIVAL(p,48,PTR_DIFF(p2,p)); /* parms */
|
|
strcpy(p2,"");
|
|
p2 = skip_string(p2,1);
|
|
SIVAL(p,52,0); /* last logon */
|
|
SIVAL(p,56,0); /* last logoff */
|
|
SSVALS(p,60,-1); /* bad pw counts */
|
|
SSVALS(p,62,-1); /* num logons */
|
|
SIVAL(p,64,PTR_DIFF(p2,p)); /* logon server */
|
|
strcpy(p2,"\\\\*");
|
|
p2 = skip_string(p2,1);
|
|
SSVAL(p,68,0); /* country code */
|
|
|
|
SIVAL(p,70,PTR_DIFF(p2,p)); /* workstations */
|
|
strcpy(p2,"");
|
|
p2 = skip_string(p2,1);
|
|
|
|
SIVALS(p,74,-1); /* max storage */
|
|
SSVAL(p,78,168); /* units per week */
|
|
SIVAL(p,80,PTR_DIFF(p2,p)); /* logon hours */
|
|
memset(p2,-1,21);
|
|
SCVAL(p2,21,0); /* fix zero termination */
|
|
p2 = skip_string(p2,1);
|
|
|
|
SSVAL(p,84,0); /* code page */
|
|
}
|
|
if (uLevel == 1 || uLevel == 2) {
|
|
memset(p+22,' ',16); /* password */
|
|
SIVALS(p,38,-1); /* password age */
|
|
SSVAL(p,42,USER_PRIV_ADMIN); /* user privilege */
|
|
SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
|
|
strcpy(p2,"\\\\%L\\HOMES");
|
|
standard_sub_basic(p2);
|
|
p2 = skip_string(p2,1);
|
|
SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
|
|
*p2++ = 0;
|
|
SSVAL(p,52,0); /* flags */
|
|
SIVAL(p,54,0); /* script_path */
|
|
if (uLevel == 2) {
|
|
SIVAL(p,60,0); /* auth_flags */
|
|
SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
|
|
strcpy(p2,"<Full Name>");
|
|
p2 = skip_string(p2,1);
|
|
SIVAL(p,68,0); /* urs_comment */
|
|
SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
|
|
strcpy(p2,"");
|
|
p2 = skip_string(p2,1);
|
|
SIVAL(p,76,0); /* workstations */
|
|
SIVAL(p,80,0); /* last_logon */
|
|
SIVAL(p,84,0); /* last_logoff */
|
|
SIVALS(p,88,-1); /* acct_expires */
|
|
SIVALS(p,92,-1); /* max_storage */
|
|
SSVAL(p,96,168); /* units_per_week */
|
|
SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
|
|
memset(p2,-1,21);
|
|
p2 += 21;
|
|
SSVALS(p,102,-1); /* bad_pw_count */
|
|
SSVALS(p,104,-1); /* num_logons */
|
|
SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
|
|
strcpy(p2,"\\\\%L");
|
|
standard_sub_basic(p2);
|
|
p2 = skip_string(p2,1);
|
|
SSVAL(p,110,49); /* country_code */
|
|
SSVAL(p,112,860); /* code page */
|
|
}
|
|
}
|
|
}
|
|
|
|
*rdata_len = PTR_DIFF(p2,*rdata);
|
|
|
|
SSVAL(*rparam,4,*rdata_len); /* is this right?? */
|
|
|
|
return(True);
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
get groups that a user is a member of
|
|
******************************************************************/
|
|
static BOOL api_NetUserGetGroups(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *UserName = skip_string(str2,1);
|
|
char *p = skip_string(UserName,1);
|
|
int uLevel = SVAL(p,0);
|
|
char *p2;
|
|
int count=0;
|
|
|
|
*rparam_len = 8;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
|
|
/* check it's a supported varient */
|
|
if (strcmp(str1,"zWrLeh") != 0) return False;
|
|
switch( uLevel ) {
|
|
case 0: p2 = "B21"; break;
|
|
default: return False;
|
|
}
|
|
if (strcmp(p2,str2) != 0) return False;
|
|
|
|
*rdata_len = mdrcnt + 1024;
|
|
*rdata = REALLOC(*rdata,*rdata_len);
|
|
|
|
SSVAL(*rparam,0,NERR_Success);
|
|
SSVAL(*rparam,2,0); /* converter word */
|
|
|
|
p = *rdata;
|
|
|
|
/* XXXX we need a real SAM database some day */
|
|
strcpy(p,"Users"); p += 21; count++;
|
|
strcpy(p,"Domain Users"); p += 21; count++;
|
|
strcpy(p,"Guests"); p += 21; count++;
|
|
strcpy(p,"Domain Guests"); p += 21; count++;
|
|
|
|
*rdata_len = PTR_DIFF(p,*rdata);
|
|
|
|
SSVAL(*rparam,4,count); /* is this right?? */
|
|
SSVAL(*rparam,6,count); /* is this right?? */
|
|
|
|
return(True);
|
|
}
|
|
|
|
|
|
static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
int uLevel;
|
|
struct pack_desc desc;
|
|
char* name;
|
|
|
|
uLevel = SVAL(p,0);
|
|
name = p + 2;
|
|
|
|
bzero(&desc,sizeof(desc));
|
|
|
|
DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
|
|
|
|
/* check it's a supported varient */
|
|
if (strcmp(str1,"OOWb54WrLh") != 0) return False;
|
|
if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
|
|
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
|
|
desc.base = *rdata;
|
|
desc.buflen = mdrcnt;
|
|
desc.subformat = NULL;
|
|
desc.format = str2;
|
|
|
|
|
|
|
|
if (init_package(&desc,1,0)) {
|
|
PACKI(&desc,"W",0); /* code */
|
|
PACKS(&desc,"B21",name); /* eff. name */
|
|
PACKS(&desc,"B",""); /* pad */
|
|
PACKI(&desc,"W",
|
|
Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
|
|
PACKI(&desc,"D",0); /* auth flags XXX */
|
|
PACKI(&desc,"W",0); /* num logons */
|
|
PACKI(&desc,"W",0); /* bad pw count */
|
|
PACKI(&desc,"D",-1); /* last logon */
|
|
PACKI(&desc,"D",-1); /* last logoff */
|
|
PACKI(&desc,"D",-1); /* logoff time */
|
|
PACKI(&desc,"D",-1); /* kickoff time */
|
|
PACKI(&desc,"D",0); /* password age */
|
|
PACKI(&desc,"D",0); /* password can change */
|
|
PACKI(&desc,"D",-1); /* password must change */
|
|
{
|
|
fstring mypath;
|
|
strcpy(mypath,"\\\\");
|
|
strcat(mypath,local_machine);
|
|
strupper(mypath);
|
|
PACKS(&desc,"z",mypath); /* computer */
|
|
}
|
|
PACKS(&desc,"z",my_workgroup());/* domain */
|
|
PACKS(&desc,"z",lp_logon_script()); /* script path */
|
|
PACKI(&desc,"D",0); /* reserved */
|
|
}
|
|
|
|
*rdata_len = desc.usedlen;
|
|
*rparam_len = 6;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVALS(*rparam,0,desc.errcode);
|
|
SSVAL(*rparam,2,0);
|
|
SSVAL(*rparam,4,desc.neededlen);
|
|
|
|
DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
|
|
return(True);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
api_WAccessGetUserPerms
|
|
****************************************************************************/
|
|
static BOOL api_WAccessGetUserPerms(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *user = skip_string(str2,1);
|
|
char *resource = skip_string(user,1);
|
|
|
|
DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
|
|
|
|
/* check it's a supported varient */
|
|
if (strcmp(str1,"zzh") != 0) return False;
|
|
if (strcmp(str2,"") != 0) return False;
|
|
|
|
*rparam_len = 6;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVALS(*rparam,0,0); /* errorcode */
|
|
SSVAL(*rparam,2,0); /* converter word */
|
|
SSVAL(*rparam,4,0x7f); /* permission flags */
|
|
|
|
return(True);
|
|
}
|
|
|
|
/****************************************************************************
|
|
api_WPrintJobEnumerate
|
|
****************************************************************************/
|
|
static BOOL api_WPrintJobGetInfo(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
int uJobId = SVAL(p,0);
|
|
int uLevel,cbBuf;
|
|
int count;
|
|
int i;
|
|
int snum;
|
|
int job;
|
|
struct pack_desc desc;
|
|
print_queue_struct *queue=NULL;
|
|
print_status_struct status;
|
|
|
|
uLevel = SVAL(p,2);
|
|
cbBuf = SVAL(p,4);
|
|
|
|
bzero(&desc,sizeof(desc));
|
|
bzero(&status,sizeof(status));
|
|
|
|
DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,uJobId));
|
|
|
|
/* check it's a supported varient */
|
|
if (strcmp(str1,"WWrLh") != 0) return False;
|
|
if (!check_printjob_info(&desc,uLevel,str2)) return False;
|
|
|
|
snum = (unsigned int)uJobId >> 8; /*## valid serice number??*/
|
|
job = uJobId & 0xFF;
|
|
|
|
if (snum < 0 || !VALID_SNUM(snum)) return(False);
|
|
|
|
count = get_printqueue(snum,cnum,&queue,&status);
|
|
for (i = 0; i < count; i++) {
|
|
if ((queue[i].job % 0xFF) == job) break;
|
|
}
|
|
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
|
|
desc.base = *rdata;
|
|
desc.buflen = mdrcnt;
|
|
|
|
if (init_package(&desc,1,0)) {
|
|
if (i < count) {
|
|
fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i);
|
|
*rdata_len = desc.usedlen;
|
|
}
|
|
else {
|
|
desc.errcode = NERR_JobNotFound;
|
|
*rdata_len = 0;
|
|
}
|
|
}
|
|
|
|
*rparam_len = 6;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVALS(*rparam,0,desc.errcode);
|
|
SSVAL(*rparam,2,0);
|
|
SSVAL(*rparam,4,desc.neededlen);
|
|
|
|
if (queue) free(queue);
|
|
|
|
DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
|
|
return(True);
|
|
}
|
|
|
|
static BOOL api_WPrintJobEnumerate(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
char* name = p;
|
|
int uLevel,cbBuf;
|
|
int count;
|
|
int i, succnt=0;
|
|
int snum;
|
|
struct pack_desc desc;
|
|
print_queue_struct *queue=NULL;
|
|
print_status_struct status;
|
|
|
|
bzero(&desc,sizeof(desc));
|
|
bzero(&status,sizeof(status));
|
|
|
|
p = skip_string(p,1);
|
|
uLevel = SVAL(p,0);
|
|
cbBuf = SVAL(p,2);
|
|
|
|
DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
|
|
|
|
/* check it's a supported varient */
|
|
if (strcmp(str1,"zWrLeh") != 0) return False;
|
|
if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
|
|
if (!check_printjob_info(&desc,uLevel,str2)) return False;
|
|
|
|
snum = lp_servicenumber(name);
|
|
if (snum < 0 && pcap_printername_ok(name,NULL)) {
|
|
int pnum = lp_servicenumber(PRINTERS_NAME);
|
|
if (pnum >= 0) {
|
|
lp_add_printer(name,pnum);
|
|
snum = lp_servicenumber(name);
|
|
}
|
|
}
|
|
|
|
if (snum < 0 || !VALID_SNUM(snum)) return(False);
|
|
|
|
count = get_printqueue(snum,cnum,&queue,&status);
|
|
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
|
|
desc.base = *rdata;
|
|
desc.buflen = mdrcnt;
|
|
|
|
if (init_package(&desc,count,0)) {
|
|
succnt = 0;
|
|
for (i = 0; i < count; i++) {
|
|
fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i);
|
|
if (desc.errcode == NERR_Success) succnt = i+1;
|
|
}
|
|
}
|
|
|
|
*rdata_len = desc.usedlen;
|
|
|
|
*rparam_len = 8;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVALS(*rparam,0,desc.errcode);
|
|
SSVAL(*rparam,2,0);
|
|
SSVAL(*rparam,4,succnt);
|
|
SSVAL(*rparam,6,count);
|
|
|
|
if (queue) free(queue);
|
|
|
|
DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
|
|
return(True);
|
|
}
|
|
|
|
static int check_printdest_info(struct pack_desc* desc,
|
|
int uLevel, char* id)
|
|
{
|
|
desc->subformat = NULL;
|
|
switch( uLevel ) {
|
|
case 0: desc->format = "B9"; break;
|
|
case 1: desc->format = "B9B21WWzW"; break;
|
|
case 2: desc->format = "z"; break;
|
|
case 3: desc->format = "zzzWWzzzWW"; break;
|
|
default: return False;
|
|
}
|
|
if (strcmp(desc->format,id) != 0) return False;
|
|
return True;
|
|
}
|
|
|
|
static void fill_printdest_info(int cnum, int snum, int uLevel,
|
|
struct pack_desc* desc)
|
|
{
|
|
char buf[100];
|
|
strcpy(buf,SERVICE(snum));
|
|
strupper(buf);
|
|
if (uLevel <= 1) {
|
|
PACKS(desc,"B9",buf); /* szName */
|
|
if (uLevel == 1) {
|
|
PACKS(desc,"B21",""); /* szUserName */
|
|
PACKI(desc,"W",0); /* uJobId */
|
|
PACKI(desc,"W",0); /* fsStatus */
|
|
PACKS(desc,"z",""); /* pszStatus */
|
|
PACKI(desc,"W",0); /* time */
|
|
}
|
|
}
|
|
if (uLevel == 2 || uLevel == 3) {
|
|
PACKS(desc,"z",buf); /* pszPrinterName */
|
|
if (uLevel == 3) {
|
|
PACKS(desc,"z",""); /* pszUserName */
|
|
PACKS(desc,"z",""); /* pszLogAddr */
|
|
PACKI(desc,"W",0); /* uJobId */
|
|
PACKI(desc,"W",0); /* fsStatus */
|
|
PACKS(desc,"z",""); /* pszStatus */
|
|
PACKS(desc,"z",""); /* pszComment */
|
|
PACKS(desc,"z","NULL"); /* pszDrivers */
|
|
PACKI(desc,"W",0); /* time */
|
|
PACKI(desc,"W",0); /* pad1 */
|
|
}
|
|
}
|
|
}
|
|
|
|
static BOOL api_WPrintDestGetInfo(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
char* PrinterName = p;
|
|
int uLevel,cbBuf;
|
|
struct pack_desc desc;
|
|
int snum;
|
|
|
|
bzero(&desc,sizeof(desc));
|
|
|
|
p = skip_string(p,1);
|
|
uLevel = SVAL(p,0);
|
|
cbBuf = SVAL(p,2);
|
|
|
|
DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
|
|
|
|
/* check it's a supported varient */
|
|
if (strcmp(str1,"zWrLh") != 0) return False;
|
|
if (!check_printdest_info(&desc,uLevel,str2)) return False;
|
|
|
|
snum = lp_servicenumber(PrinterName);
|
|
if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
|
|
int pnum = lp_servicenumber(PRINTERS_NAME);
|
|
if (pnum >= 0) {
|
|
lp_add_printer(PrinterName,pnum);
|
|
snum = lp_servicenumber(PrinterName);
|
|
}
|
|
}
|
|
|
|
if (snum < 0) {
|
|
*rdata_len = 0;
|
|
desc.errcode = NERR_DestNotFound;
|
|
desc.neededlen = 0;
|
|
}
|
|
else {
|
|
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
|
|
desc.base = *rdata;
|
|
desc.buflen = mdrcnt;
|
|
if (init_package(&desc,1,0)) {
|
|
fill_printdest_info(cnum,snum,uLevel,&desc);
|
|
}
|
|
*rdata_len = desc.usedlen;
|
|
}
|
|
|
|
*rparam_len = 6;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVALS(*rparam,0,desc.errcode);
|
|
SSVAL(*rparam,2,0);
|
|
SSVAL(*rparam,4,desc.neededlen);
|
|
|
|
DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
|
|
return(True);
|
|
}
|
|
|
|
static BOOL api_WPrintDestEnum(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
int uLevel,cbBuf;
|
|
int queuecnt;
|
|
int i, n, succnt=0;
|
|
struct pack_desc desc;
|
|
int services = lp_numservices();
|
|
|
|
bzero(&desc,sizeof(desc));
|
|
|
|
uLevel = SVAL(p,0);
|
|
cbBuf = SVAL(p,2);
|
|
|
|
DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
|
|
|
|
/* check it's a supported varient */
|
|
if (strcmp(str1,"WrLeh") != 0) return False;
|
|
if (!check_printdest_info(&desc,uLevel,str2)) return False;
|
|
|
|
queuecnt = 0;
|
|
for (i = 0; i < services; i++)
|
|
if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
|
|
queuecnt++;
|
|
|
|
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
|
|
desc.base = *rdata;
|
|
desc.buflen = mdrcnt;
|
|
if (init_package(&desc,queuecnt,0)) {
|
|
succnt = 0;
|
|
n = 0;
|
|
for (i = 0; i < services; i++) {
|
|
if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
|
|
fill_printdest_info(cnum,i,uLevel,&desc);
|
|
n++;
|
|
if (desc.errcode == NERR_Success) succnt = n;
|
|
}
|
|
}
|
|
}
|
|
|
|
*rdata_len = desc.usedlen;
|
|
|
|
*rparam_len = 8;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVALS(*rparam,0,desc.errcode);
|
|
SSVAL(*rparam,2,0);
|
|
SSVAL(*rparam,4,succnt);
|
|
SSVAL(*rparam,6,queuecnt);
|
|
|
|
DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
|
|
return(True);
|
|
}
|
|
|
|
static BOOL api_WPrintDriverEnum(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
int uLevel,cbBuf;
|
|
int succnt;
|
|
struct pack_desc desc;
|
|
|
|
bzero(&desc,sizeof(desc));
|
|
|
|
uLevel = SVAL(p,0);
|
|
cbBuf = SVAL(p,2);
|
|
|
|
DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
|
|
|
|
/* check it's a supported varient */
|
|
if (strcmp(str1,"WrLeh") != 0) return False;
|
|
if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
|
|
|
|
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
|
|
desc.base = *rdata;
|
|
desc.buflen = mdrcnt;
|
|
if (init_package(&desc,1,0)) {
|
|
PACKS(&desc,"B41","NULL");
|
|
}
|
|
|
|
succnt = (desc.errcode == NERR_Success ? 1 : 0);
|
|
|
|
*rdata_len = desc.usedlen;
|
|
|
|
*rparam_len = 8;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVALS(*rparam,0,desc.errcode);
|
|
SSVAL(*rparam,2,0);
|
|
SSVAL(*rparam,4,succnt);
|
|
SSVAL(*rparam,6,1);
|
|
|
|
DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
|
|
return(True);
|
|
}
|
|
|
|
static BOOL api_WPrintQProcEnum(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
int uLevel,cbBuf;
|
|
int succnt;
|
|
struct pack_desc desc;
|
|
|
|
bzero(&desc,sizeof(desc));
|
|
|
|
uLevel = SVAL(p,0);
|
|
cbBuf = SVAL(p,2);
|
|
|
|
DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
|
|
|
|
/* check it's a supported varient */
|
|
if (strcmp(str1,"WrLeh") != 0) return False;
|
|
if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
|
|
|
|
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
|
|
desc.base = *rdata;
|
|
desc.buflen = mdrcnt;
|
|
desc.format = str2;
|
|
if (init_package(&desc,1,0)) {
|
|
PACKS(&desc,"B13","lpd");
|
|
}
|
|
|
|
succnt = (desc.errcode == NERR_Success ? 1 : 0);
|
|
|
|
*rdata_len = desc.usedlen;
|
|
|
|
*rparam_len = 8;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVALS(*rparam,0,desc.errcode);
|
|
SSVAL(*rparam,2,0);
|
|
SSVAL(*rparam,4,succnt);
|
|
SSVAL(*rparam,6,1);
|
|
|
|
DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
|
|
return(True);
|
|
}
|
|
|
|
static BOOL api_WPrintPortEnum(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
char *str1 = param+2;
|
|
char *str2 = skip_string(str1,1);
|
|
char *p = skip_string(str2,1);
|
|
int uLevel,cbBuf;
|
|
int succnt;
|
|
struct pack_desc desc;
|
|
|
|
bzero(&desc,sizeof(desc));
|
|
|
|
uLevel = SVAL(p,0);
|
|
cbBuf = SVAL(p,2);
|
|
|
|
DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
|
|
|
|
/* check it's a supported varient */
|
|
if (strcmp(str1,"WrLeh") != 0) return False;
|
|
if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
|
|
|
|
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
|
|
bzero(&desc,sizeof(desc));
|
|
desc.base = *rdata;
|
|
desc.buflen = mdrcnt;
|
|
desc.format = str2;
|
|
if (init_package(&desc,1,0)) {
|
|
PACKS(&desc,"B13","lp0");
|
|
}
|
|
|
|
succnt = (desc.errcode == NERR_Success ? 1 : 0);
|
|
|
|
*rdata_len = desc.usedlen;
|
|
|
|
*rparam_len = 8;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
SSVALS(*rparam,0,desc.errcode);
|
|
SSVAL(*rparam,2,0);
|
|
SSVAL(*rparam,4,succnt);
|
|
SSVAL(*rparam,6,1);
|
|
|
|
DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
|
|
return(True);
|
|
}
|
|
|
|
/****************************************************************************
|
|
the buffer was too small
|
|
****************************************************************************/
|
|
static BOOL api_TooSmall(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
*rparam_len = MIN(*rparam_len,mprcnt);
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
|
|
*rdata_len = 0;
|
|
|
|
SSVAL(*rparam,0,NERR_BufTooSmall);
|
|
|
|
DEBUG(3,("Supplied buffer too small in API command\n"));
|
|
|
|
return(True);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
the request is not supported
|
|
****************************************************************************/
|
|
static BOOL api_Unsupported(int cnum,int uid, char *param,char *data,
|
|
int mdrcnt,int mprcnt,
|
|
char **rdata,char **rparam,
|
|
int *rdata_len,int *rparam_len)
|
|
{
|
|
*rparam_len = 4;
|
|
*rparam = REALLOC(*rparam,*rparam_len);
|
|
|
|
*rdata_len = 0;
|
|
|
|
SSVAL(*rparam,0,NERR_notsupported);
|
|
SSVAL(*rparam,2,0); /* converter word */
|
|
|
|
DEBUG(3,("Unsupported API command\n"));
|
|
|
|
return(True);
|
|
}
|
|
|
|
|
|
|
|
|
|
struct
|
|
{
|
|
char *name;
|
|
int id;
|
|
BOOL (*fn)();
|
|
int flags;
|
|
} api_commands[] = {
|
|
{"RNetShareEnum", 0, api_RNetShareEnum,0},
|
|
{"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
|
|
{"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
|
|
{"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
|
|
{"NetUserGetGroups", 59, api_NetUserGetGroups,0},
|
|
{"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
|
|
{"DosPrintQEnum", 69, api_DosPrintQEnum,0},
|
|
{"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
|
|
{"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
|
|
{"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
|
|
{"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
|
|
{"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
|
|
{"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
|
|
{"WPrintDestEnum", 84, api_WPrintDestEnum,0},
|
|
{"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
|
|
{"NetRemoteTOD", 91, api_NetRemoteTOD,0},
|
|
{"WPrintQueuePurge", 103, api_WPrintQueuePurge,0},
|
|
{"NetServerEnum", 104, api_RNetServerEnum,0},
|
|
{"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
|
|
{"SetUserPassword", 115, api_SetUserPassword,0},
|
|
{"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
|
|
{"PrintJobInfo", 147, api_PrintJobInfo,0},
|
|
{"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
|
|
{"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
|
|
{"WPrintPortEnum", 207, api_WPrintPortEnum,0},
|
|
{NULL, -1, api_Unsupported,0}};
|
|
|
|
|
|
/****************************************************************************
|
|
handle remote api calls
|
|
****************************************************************************/
|
|
static int api_reply(int cnum,int uid,char *outbuf,char *data,char *params,
|
|
int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
|
|
{
|
|
int api_command = SVAL(params,0);
|
|
char *rdata = NULL;
|
|
char *rparam = NULL;
|
|
int rdata_len = 0;
|
|
int rparam_len = 0;
|
|
BOOL reply=False;
|
|
int i;
|
|
|
|
DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
|
|
api_command,params+2,skip_string(params+2,1),
|
|
tdscnt,tpscnt,mdrcnt,mprcnt));
|
|
|
|
for (i=0;api_commands[i].name;i++)
|
|
if (api_commands[i].id == api_command && api_commands[i].fn)
|
|
{
|
|
DEBUG(3,("Doing %s\n",api_commands[i].name));
|
|
break;
|
|
}
|
|
|
|
rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024);
|
|
rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
|
|
|
|
reply = api_commands[i].fn(cnum,uid,params,data,mdrcnt,mprcnt,
|
|
&rdata,&rparam,&rdata_len,&rparam_len);
|
|
|
|
|
|
if (rdata_len > mdrcnt ||
|
|
rparam_len > mprcnt)
|
|
{
|
|
reply = api_TooSmall(cnum,uid,params,data,mdrcnt,mprcnt,
|
|
&rdata,&rparam,&rdata_len,&rparam_len);
|
|
}
|
|
|
|
|
|
/* if we get False back then it's actually unsupported */
|
|
if (!reply)
|
|
api_Unsupported(cnum,uid,params,data,mdrcnt,mprcnt,
|
|
&rdata,&rparam,&rdata_len,&rparam_len);
|
|
|
|
|
|
|
|
/* now send the reply */
|
|
send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
|
|
|
|
if (rdata)
|
|
free(rdata);
|
|
if (rparam)
|
|
free(rparam);
|
|
|
|
return(-1);
|
|
}
|
|
|
|
/****************************************************************************
|
|
handle named pipe commands
|
|
****************************************************************************/
|
|
static int named_pipe(int cnum,int uid, char *outbuf,char *name,
|
|
uint16 *setup,char *data,char *params,
|
|
int suwcnt,int tdscnt,int tpscnt,
|
|
int msrcnt,int mdrcnt,int mprcnt)
|
|
{
|
|
|
|
if (strequal(name,"LANMAN"))
|
|
return(api_reply(cnum,uid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt));
|
|
|
|
DEBUG(3,("named pipe command on <%s> 0x%X setup1=%d\n",
|
|
name,(int)setup[0],(int)setup[1]));
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
reply to a SMBtrans
|
|
****************************************************************************/
|
|
int reply_trans(char *inbuf,char *outbuf)
|
|
{
|
|
fstring name;
|
|
|
|
char *data=NULL,*params=NULL;
|
|
uint16 *setup=NULL;
|
|
|
|
int outsize = 0;
|
|
int cnum = SVAL(inbuf,smb_tid);
|
|
int uid = SVAL(inbuf,smb_uid);
|
|
|
|
int tpscnt = SVAL(inbuf,smb_vwv0);
|
|
int tdscnt = SVAL(inbuf,smb_vwv1);
|
|
int mprcnt = SVAL(inbuf,smb_vwv2);
|
|
int mdrcnt = SVAL(inbuf,smb_vwv3);
|
|
int msrcnt = CVAL(inbuf,smb_vwv4);
|
|
BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
|
|
BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
|
|
int pscnt = SVAL(inbuf,smb_vwv9);
|
|
int psoff = SVAL(inbuf,smb_vwv10);
|
|
int dscnt = SVAL(inbuf,smb_vwv11);
|
|
int dsoff = SVAL(inbuf,smb_vwv12);
|
|
int suwcnt = CVAL(inbuf,smb_vwv13);
|
|
|
|
StrnCpy(name,smb_buf(inbuf),sizeof(name)-1);
|
|
|
|
if (tdscnt)
|
|
{
|
|
data = (char *)malloc(tdscnt);
|
|
memcpy(data,smb_base(inbuf)+dsoff,dscnt);
|
|
}
|
|
if (tpscnt)
|
|
{
|
|
params = (char *)malloc(tpscnt);
|
|
memcpy(params,smb_base(inbuf)+psoff,pscnt);
|
|
}
|
|
|
|
if (suwcnt)
|
|
{
|
|
int i;
|
|
setup = (uint16 *)malloc(suwcnt*sizeof(setup[0]));
|
|
for (i=0;i<suwcnt;i++)
|
|
setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
|
|
}
|
|
|
|
|
|
if (pscnt < tpscnt || dscnt < tdscnt)
|
|
{
|
|
/* We need to send an interim response then receive the rest
|
|
of the parameter/data bytes */
|
|
outsize = set_message(outbuf,0,0,True);
|
|
show_msg(outbuf);
|
|
send_smb(Client,outbuf);
|
|
}
|
|
|
|
/* receive the rest of the trans packet */
|
|
while (pscnt < tpscnt || dscnt < tdscnt)
|
|
{
|
|
int pcnt,poff,dcnt,doff,pdisp,ddisp;
|
|
|
|
if (!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT*1000) ||
|
|
CVAL(inbuf, smb_com) != SMBtrans)
|
|
{
|
|
DEBUG(2,("Invalid secondary trans2 packet\n"));
|
|
if (params) free(params);
|
|
if (data) free(data);
|
|
if (setup) free(setup);
|
|
return(ERROR(ERRSRV,ERRerror));
|
|
}
|
|
|
|
show_msg(inbuf);
|
|
|
|
tpscnt = SVAL(inbuf,smb_vwv0);
|
|
tdscnt = SVAL(inbuf,smb_vwv1);
|
|
|
|
pcnt = SVAL(inbuf,smb_vwv2);
|
|
poff = SVAL(inbuf,smb_vwv3);
|
|
pdisp = SVAL(inbuf,smb_vwv4);
|
|
|
|
dcnt = SVAL(inbuf,smb_vwv5);
|
|
doff = SVAL(inbuf,smb_vwv6);
|
|
ddisp = SVAL(inbuf,smb_vwv7);
|
|
|
|
pscnt += pcnt;
|
|
dscnt += dcnt;
|
|
|
|
if (pcnt)
|
|
memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
|
|
if (dcnt)
|
|
memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);
|
|
}
|
|
|
|
|
|
DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",name,tdscnt,tpscnt,suwcnt));
|
|
|
|
|
|
if (strncmp(name,"\\PIPE\\",strlen("\\PIPE\\")) == 0)
|
|
outsize = named_pipe(cnum,uid,outbuf,name+strlen("\\PIPE\\"),setup,data,params,
|
|
suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
|
|
|
|
|
|
if (data) free(data);
|
|
if (params) free(params);
|
|
if (setup) free(setup);
|
|
|
|
if (close_on_completion)
|
|
close_cnum(cnum,uid);
|
|
|
|
if (one_way)
|
|
return(-1);
|
|
|
|
if (outsize == 0)
|
|
return(ERROR(ERRSRV,ERRnosupport));
|
|
|
|
return(outsize);
|
|
}
|
|
|
|
|