diff options
Diffstat (limited to 'source3/smbd/ipc.c')
-rw-r--r-- | source3/smbd/ipc.c | 2779 |
1 files changed, 2779 insertions, 0 deletions
diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c new file mode 100644 index 0000000000..8852e57e8b --- /dev/null +++ b/source3/smbd/ipc.c @@ -0,0 +1,2779 @@ +/* + 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" +#include "loadparm.h" +#include "pcap.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 += GMT_TO_LOCAL*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",queue->time); /* 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",queue->time); /* 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, + char *domain) +{ + if (*domain) + return(strequal(domain, server->domain)); + + return (True); /* be indiscriminate: get all servers! */ +} + +/******************************************************************* + find server in the files saved by nmbd. Return True if we find it. + ******************************************************************/ +static BOOL find_server(struct srv_info_struct *servers, int num_servers, + char *domain, char *name) +{ + int count; + + if (!servers || num_servers == 0) return (False); + + for (count = 0; count < num_servers; count++) { + struct srv_info_struct *s; + + s = &servers[count]; + + if (strequal(name, s->name)) { + StrnCpy(domain, s->domain, sizeof(pstring)-1); + return (True); + } + } + return (False); +} + + +/******************************************************************* + 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) +{ + 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); + } + if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM; + + while (!feof(f)) + { + fstring stype; + struct srv_info_struct *s; + char *ptr = line; + *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]; + + s->server_added = True; + + 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 cop with an old nmbd */ + strcpy(s->domain,my_workgroup()); + } + + if (sscanf(stype,"%X",&s->type) != 1) continue; + + /* doesn't match up: don't want it */ + if (!(servertype & s->type)) continue; + + /* server entry is a domain, we haven't asked for domains: don't want it */ + if ((s->type&SV_TYPE_DOMAIN_ENUM) && !(servertype&SV_TYPE_DOMAIN_ENUM)) + continue; + + DEBUG(4,("Server %20s %8x %25s %15s\n", + s->name, stype, s->comment, s->domain)); + + count++; + } + + 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; +} + + +/**************************************************************************** + 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 domain_request = (servertype & SV_TYPE_DOMAIN_ENUM) && + !(servertype == SV_TYPE_ALL); + + 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\n", str2)); + + if (strcmp(str1, "WrLehDO") == 0) + { + /* asking for servers. we will have to work out which workgroup was + requested, as we maintain lists for multiple workgroups */ + } + else if (strcmp(str1, "WrLehDz") == 0) + { + /* asking for a specific workgroup */ + StrnCpy(domain, p, sizeof(fstring)-1); + } + + if (lp_browse_list()) + { + total = get_server_info(servertype,&servers); + } + + if (!domain[0] && !domain_request) { + extern fstring remote_machine; + /* must be a server request with an assumed domain. find a domain */ + + if (find_server(servers, total, domain, remote_machine)) { + DEBUG(4, ("No domain specified: using %s for %s\n", + domain, remote_machine)); + } else { + /* default to soemthing sensible */ + strcpy(domain,my_workgroup()); + } + } + + data_len = fixed_len = string_len = 0; + + for (i=0;i<total;i++) + if (filter_server_info(&servers[i],domain)) { + data_len += fill_srv_info(&servers[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); + bzero(*rdata,*rdata_len); + + p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */ + p = *rdata; + f_len = fixed_len; + s_len = string_len; + + { + int count2 = counted; + for (i = 0; i < total && count2;i++) { + if (filter_server_info(&servers[i],domain)) { + fill_srv_info(&servers[i],uLevel,&p,&f_len,&p2,&s_len,*rdata); + 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,GMT_TO_LOCAL); + + 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 (isalnum(*s) || strchr("-._",*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))>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); +} + + |