1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-31 17:18:04 +03:00
samba-mirror/source3/smbd/ipc.c

2853 lines
74 KiB
C
Raw Normal View History

/*
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;
receive_smb(Client,inbuf, 0);
show_msg(inbuf);
/* Ensure this is still a trans packet (sanity check) */
if(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));
}
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);
}