1996-05-04 11:50:46 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
Inter - process communication and named pipe handling
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
1997-07-09 15:04:45 +04:00
SMB Version handling
1998-01-22 16:27:43 +03:00
Copyright ( C ) John H Terpstra 1995 - 1998
1996-05-04 11:50:46 +04:00
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 0213 9 , USA .
*/
/*
This file handles the named pipe and mailslot calls
in the SMBtrans protocol
*/
# include "includes.h"
1998-03-12 00:11:04 +03:00
# include "nterr.h"
1996-05-04 11:50:46 +04:00
# ifdef CHECK_TYPES
# undef CHECK_TYPES
# endif
# define CHECK_TYPES 0
extern int DEBUGLEVEL ;
1997-02-28 23:39:36 +03:00
extern int max_send ;
1996-05-04 11:50:46 +04:00
extern fstring local_machine ;
1998-04-25 05:12:08 +04:00
extern fstring global_myworkgroup ;
1996-05-04 11:50:46 +04:00
# 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 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 ;
1997-11-19 02:30:49 +03:00
extern int smb_read_error ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
static BOOL api_Unsupported ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-08-15 19:11:34 +04:00
int mdrcnt , int mprcnt ,
char * * rdata , char * * rparam ,
int * rdata_len , int * rparam_len ) ;
1998-08-14 21:38:29 +04:00
static BOOL api_TooSmall ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-08-15 19:11:34 +04:00
int mdrcnt , int mprcnt ,
char * * rdata , char * * rparam ,
int * rdata_len , int * rparam_len ) ;
1998-08-14 21:38:29 +04:00
static int CopyExpanded ( connection_struct * conn ,
int snum , char * * dst , char * src , int * n )
1996-05-04 11:50:46 +04:00
{
1998-08-14 21:38:29 +04:00
pstring buf ;
int l ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
if ( ! src | | ! dst | | ! n | | ! ( * dst ) ) return ( 0 ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
StrnCpy ( buf , src , sizeof ( buf ) / 2 ) ;
string_sub ( buf , " %S " , lp_servicename ( snum ) ) ;
standard_sub ( conn , buf ) ;
StrnCpy ( * dst , buf , * n ) ;
l = strlen ( * dst ) + 1 ;
( * dst ) + = l ;
( * n ) - = l ;
return l ;
1996-05-04 11:50:46 +04:00
}
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 ;
}
1998-08-14 21:38:29 +04:00
static int StrlenExpanded ( connection_struct * conn , int snum , char * s )
1996-05-04 11:50:46 +04:00
{
1998-08-14 21:38:29 +04:00
pstring buf ;
if ( ! s ) return ( 0 ) ;
StrnCpy ( buf , s , sizeof ( buf ) / 2 ) ;
string_sub ( buf , " %S " , lp_servicename ( snum ) ) ;
standard_sub ( conn , buf ) ;
return strlen ( buf ) + 1 ;
1996-05-04 11:50:46 +04:00
}
1998-08-14 21:38:29 +04:00
static char * Expand ( connection_struct * conn , int snum , char * s )
1996-05-04 11:50:46 +04:00
{
1998-08-14 21:38:29 +04:00
static pstring buf ;
if ( ! s ) return ( NULL ) ;
StrnCpy ( buf , s , sizeof ( buf ) / 2 ) ;
string_sub ( buf , " %S " , lp_servicename ( snum ) ) ;
standard_sub ( conn , buf ) ;
return & buf [ 0 ] ;
1996-05-04 11:50:46 +04:00
}
/*******************************************************************
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 ) ;
}
1998-03-12 00:11:04 +03:00
/*******************************************************************
copies parameters and data , as needed , into the smb buffer
* both * the data and params sections should be aligned . this
is fudged in the rpc pipes by
at present , only the data section is . this may be a possible
cause of some of the ipc problems being experienced . lkcl26dec97
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void copy_trans_params_and_data ( char * outbuf , int align ,
struct mem_buf * rparam , struct mem_buf * rdata ,
int param_offset , int data_offset ,
int param_len , int data_len )
{
1998-09-03 09:37:15 +04:00
char * copy_into = smb_buf ( outbuf ) + 1 ;
1998-03-12 00:11:04 +03:00
DEBUG ( 5 , ( " copy_trans_params_and_data: params[%d..%d] data[%d..%d] \n " ,
param_offset , param_offset + param_len ,
data_offset , data_offset + data_len ) ) ;
if ( param_len ) mem_buf_copy ( copy_into , rparam , param_offset , param_len ) ;
copy_into + = param_len + align ;
if ( data_len ) mem_buf_copy ( copy_into , rdata , data_offset , data_len ) ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
send a trans reply
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-03-12 00:11:04 +03:00
static void send_trans_reply ( char * outbuf ,
struct mem_buf * rdata ,
struct mem_buf * rparam ,
uint16 * setup , int lsetup , int max_data_ret )
1996-05-04 11:50:46 +04:00
{
1998-03-12 00:11:04 +03:00
int i ;
int this_ldata , this_lparam ;
int tot_data = 0 , tot_param = 0 ;
int align ;
int ldata = rdata ? mem_buf_len ( rdata ) : 0 ;
int lparam = rparam ? mem_buf_len ( rparam ) : 0 ;
1996-05-04 11:50:46 +04:00
1998-03-12 00:11:04 +03:00
BOOL buffer_too_large = max_data_ret ? ldata > max_data_ret : False ;
if ( buffer_too_large )
{
DEBUG ( 5 , ( " send_trans_reply: buffer %d too large %d \n " , ldata , max_data_ret ) ) ;
ldata = max_data_ret ;
}
this_lparam = MIN ( lparam , max_send - ( 500 + lsetup * SIZEOFWORD ) ) ; /* hack */
this_ldata = MIN ( ldata , max_send - ( 500 + lsetup * SIZEOFWORD + this_lparam ) ) ;
1996-05-04 11:50:46 +04:00
1998-09-03 09:37:15 +04:00
align = ( ( this_lparam ) % 4 ) ;
1996-05-04 11:50:46 +04:00
1998-09-03 09:37:15 +04:00
set_message ( outbuf , 10 + lsetup , 1 + align + this_ldata + this_lparam , True ) ;
1998-03-12 00:11:04 +03:00
if ( buffer_too_large )
{
/* issue a buffer size warning. on a DCE/RPC pipe, expect an SMBreadX... */
SIVAL ( outbuf , smb_flg2 , FLAGS2_32_BIT_ERROR_CODES ) ;
SIVAL ( outbuf , smb_rcls , 0x80000000 | NT_STATUS_ACCESS_VIOLATION ) ;
}
copy_trans_params_and_data ( outbuf , align ,
rparam , rdata ,
tot_param , tot_data ,
this_lparam , this_ldata ) ;
SSVAL ( outbuf , smb_vwv0 , lparam ) ;
SSVAL ( outbuf , smb_vwv1 , ldata ) ;
SSVAL ( outbuf , smb_vwv3 , this_lparam ) ;
1998-09-03 09:37:15 +04:00
SSVAL ( outbuf , smb_vwv4 , smb_offset ( smb_buf ( outbuf ) + 1 , outbuf ) ) ;
1998-03-12 00:11:04 +03:00
SSVAL ( outbuf , smb_vwv5 , 0 ) ;
SSVAL ( outbuf , smb_vwv6 , this_ldata ) ;
1998-09-03 09:37:15 +04:00
SSVAL ( outbuf , smb_vwv7 , smb_offset ( smb_buf ( outbuf ) + 1 + this_lparam + align , outbuf ) ) ;
1998-03-12 00:11:04 +03:00
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 , max_send - 500 ) ; /* hack */
this_ldata = MIN ( ldata - tot_data , max_send - ( 500 + this_lparam ) ) ;
align = ( this_lparam % 4 ) ;
1998-09-03 09:37:15 +04:00
set_message ( outbuf , 10 , 1 + this_ldata + this_lparam + align , False ) ;
1998-03-12 00:11:04 +03:00
copy_trans_params_and_data ( outbuf , align ,
rparam , rdata ,
tot_param , tot_data ,
this_lparam , this_ldata ) ;
SSVAL ( outbuf , smb_vwv3 , this_lparam ) ;
1998-09-03 09:37:15 +04:00
SSVAL ( outbuf , smb_vwv4 , smb_offset ( smb_buf ( outbuf ) + 1 , outbuf ) ) ;
1998-03-12 00:11:04 +03:00
SSVAL ( outbuf , smb_vwv5 , tot_param ) ;
SSVAL ( outbuf , smb_vwv6 , this_ldata ) ;
1998-09-03 09:37:15 +04:00
SSVAL ( outbuf , smb_vwv7 , smb_offset ( smb_buf ( outbuf ) + 1 + this_lparam + align , outbuf ) ) ;
1998-03-12 00:11:04 +03:00
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 ;
}
1996-05-04 11:50:46 +04:00
}
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 ) ;
1998-08-15 05:19:26 +04:00
if ( ! isdigit ( ( int ) * * p ) ) return 1 ;
1996-05-04 11:50:46 +04:00
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 ) {
1998-04-16 00:00:41 +04:00
p - > neededlen = i ;
1996-05-04 11:50:46 +04:00
i = n = 0 ;
1998-06-04 22:49:13 +04:00
p - > errcode = ERRmoredata ;
1996-05-04 11:50:46 +04:00
}
1998-01-10 11:11:15 +03:00
else
p - > errcode = NERR_Success ;
1996-05-04 11:50:46 +04:00
p - > buflen = i ;
n - = i ;
p - > stringbuf = p - > base + i ;
p - > stringlen = n ;
return ( p - > errcode = = NERR_Success ) ;
}
1998-07-29 07:08:05 +04:00
# ifdef HAVE_STDARG_H
1996-05-04 11:50:46 +04:00
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 ;
1998-07-29 07:08:05 +04:00
# ifdef HAVE_STDARG_H
1996-05-04 11:50:46 +04:00
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 * ) ;
1998-08-25 01:49:10 +04:00
SMB_ASSERT ( strncmp ( str , p - > curpos , strlen ( str ) ) = = 0 ) ;
1996-05-04 11:50:46 +04:00
# 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 ) ;
1998-06-04 22:49:13 +04:00
if ( p - > errcode = = NERR_Success ) p - > errcode = ERRmoredata ;
1996-05-04 11:50:46 +04:00
}
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 {
1998-06-04 22:49:13 +04:00
if ( p - > errcode = = NERR_Success ) p - > errcode = ERRmoredata ;
1996-05-04 11:50:46 +04:00
}
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 ) ;
}
1996-08-13 12:57:55 +04:00
/****************************************************************************
get a print queue
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-05-04 11:50:46 +04:00
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 */
1998-05-12 04:55:32 +04:00
pstrcpy ( drivdata + 8 , " NULL " ) ;
1996-05-04 11:50:46 +04:00
PACKl ( desc , " l " , drivdata , sizeof drivdata ) ; /* pDriverData */
}
static int check_printq_info ( struct pack_desc * desc ,
1997-09-14 20:37:18 +04:00
int uLevel , char * id1 , char * id2 )
1996-05-04 11:50:46 +04:00
{
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 ;
1997-10-28 22:32:59 +03:00
case 52 :
desc - > format = " WzzzzzzzzN " ;
desc - > subformat = " z " ;
break ;
1996-05-04 11:50:46 +04:00
default : return False ;
}
if ( strcmp ( desc - > format , id1 ) ! = 0 ) return False ;
if ( desc - > subformat & & strcmp ( desc - > subformat , id2 ) ! = 0 ) return False ;
return True ;
}
1998-08-14 21:38:29 +04:00
static void fill_printjob_info ( connection_struct * conn , int snum , int uLevel ,
1996-05-04 11:50:46 +04:00
struct pack_desc * desc ,
print_queue_struct * queue , int n )
{
time_t t = queue - > time ;
/* the client expects localtime */
1996-05-31 19:13:29 +04:00
t - = TimeDiff ( t ) ;
1996-05-04 11:50:46 +04:00
1997-08-31 06:18:59 +04:00
PACKI ( desc , " W " , printjob_encode ( snum , queue - > job ) ) ; /* uJobId */
1996-05-04 11:50:46 +04:00
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 */
1996-05-31 19:13:29 +04:00
PACKI ( desc , " D " , t ) ; /* ulSubmitted */
1996-05-04 11:50:46 +04:00
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 */
1996-05-31 19:13:29 +04:00
PACKI ( desc , " D " , t ) ; /* ulSubmitted */
1996-05-04 11:50:46 +04:00
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 */
}
}
}
1998-08-14 21:38:29 +04:00
static void fill_printq_info ( connection_struct * conn , int snum , int uLevel ,
1996-05-04 11:50:46 +04:00
struct pack_desc * desc ,
int count , print_queue_struct * queue ,
print_status_struct * status )
{
1997-10-28 22:32:59 +03:00
switch ( uLevel ) {
case 1 :
case 2 :
PACKS ( desc , " B13 " , SERVICE ( snum ) ) ;
break ;
case 3 :
case 4 :
case 5 :
1998-08-14 21:38:29 +04:00
PACKS ( desc , " z " , Expand ( conn , snum , SERVICE ( snum ) ) ) ;
1997-10-28 22:32:59 +03:00
break ;
1996-05-04 11:50:46 +04:00
}
1997-10-28 22:32:59 +03:00
1996-05-04 11:50:46 +04:00
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 ] ) {
1998-08-14 21:38:29 +04:00
PACKS ( desc , " z " , Expand ( conn , snum , lp_comment ( snum ) ) ) ;
1996-05-04 11:50:46 +04:00
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 */
1996-08-13 12:57:55 +04:00
PACKS ( desc , " z " , " WinPrint " ) ; /* pszPrProc */
1996-05-04 11:50:46 +04:00
PACKS ( desc , " z " , " " ) ; /* pszParms */
if ( ! status | | ! status - > message [ 0 ] ) {
1998-08-14 21:38:29 +04:00
PACKS ( desc , " z " , Expand ( conn , snum , lp_comment ( snum ) ) ) ; /* pszComment */
1996-05-04 11:50:46 +04:00
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 */
1996-08-13 12:57:55 +04:00
PACKS ( desc , " z " , lp_printerdriver ( snum ) ) ; /* pszDriverName */
1996-05-04 11:50:46 +04:00
PackDriverData ( desc ) ; /* pDriverData */
}
if ( uLevel = = 2 | | uLevel = = 4 ) {
int i ;
for ( i = 0 ; i < count ; i + + )
1998-08-14 21:38:29 +04:00
fill_printjob_info ( conn , snum , uLevel = = 2 ? 1 : 2 , desc , & queue [ i ] , i ) ;
1996-05-04 11:50:46 +04:00
}
1997-10-28 22:32:59 +03:00
if ( uLevel = = 52 ) {
int i , ok = 0 ;
1998-01-02 16:33:20 +03:00
pstring tok , driver , datafile , langmon , helpfile , datatype ;
1997-10-28 22:32:59 +03:00
char * p , * q ;
FILE * f ;
pstring fname ;
1998-05-12 04:55:32 +04:00
pstrcpy ( fname , lp_driverfile ( ) ) ;
1997-10-28 22:32:59 +03:00
f = fopen ( fname , " r " ) ;
if ( ! f ) {
1998-01-02 16:33:20 +03:00
DEBUG ( 3 , ( " fill_printq_info: Can't open %s - %s \n " , fname , strerror ( errno ) ) ) ;
desc - > errcode = NERR_notsupported ;
return ;
1997-10-28 22:32:59 +03:00
}
1998-09-29 03:55:09 +04:00
if ( ( p = ( char * ) malloc ( 8192 * sizeof ( char ) ) ) = = NULL ) {
DEBUG ( 0 , ( " fill_printq_info: malloc fail ! \n " ) ) ;
desc - > errcode = NERR_notsupported ;
fclose ( f ) ;
return ;
}
1997-10-28 22:32:59 +03:00
bzero ( p , 8192 * sizeof ( char ) ) ;
q = p ;
/* lookup the long printer driver name in the file description */
while ( f & & ! feof ( f ) & & ! ok )
{
1998-01-02 16:33:20 +03:00
p = q ; /* reset string pointer */
1997-10-28 22:32:59 +03:00
fgets ( p , 8191 , f ) ;
p [ strlen ( p ) - 1 ] = ' \0 ' ;
1998-08-31 07:11:42 +04:00
if ( next_token ( & p , tok , " : " , sizeof ( tok ) ) & &
1998-05-05 23:24:32 +04:00
( strlen ( lp_printerdriver ( snum ) ) = = strlen ( tok ) ) & &
1998-01-02 16:33:20 +03:00
( ! strncmp ( tok , lp_printerdriver ( snum ) , strlen ( lp_printerdriver ( snum ) ) ) ) )
ok = 1 ;
1997-10-28 22:32:59 +03:00
}
fclose ( f ) ;
1998-01-02 16:33:20 +03:00
/* driver file name */
1998-08-31 07:11:42 +04:00
if ( ok & & ! next_token ( & p , driver , " : " , sizeof ( driver ) ) ) ok = 0 ;
1998-01-02 16:33:20 +03:00
/* data file name */
1998-08-31 07:11:42 +04:00
if ( ok & & ! next_token ( & p , datafile , " : " , sizeof ( datafile ) ) ) ok = 0 ;
1998-01-02 16:33:20 +03:00
/*
* for the next tokens - which may be empty - I have to check for empty
* tokens first because the next_token function will skip all empty
* token fields
*/
if ( ok ) {
/* help file */
if ( * p = = ' : ' ) {
* helpfile = ' \0 ' ;
p + + ;
1998-08-31 07:11:42 +04:00
} else if ( ! next_token ( & p , helpfile , " : " , sizeof ( helpfile ) ) ) ok = 0 ;
1998-01-02 16:33:20 +03:00
}
if ( ok ) {
/* language monitor */
if ( * p = = ' : ' ) {
* langmon = ' \0 ' ;
p + + ;
1998-08-31 07:11:42 +04:00
} else if ( ! next_token ( & p , langmon , " : " , sizeof ( langmon ) ) ) ok = 0 ;
1998-01-02 16:33:20 +03:00
}
/* default data type */
1998-08-31 07:11:42 +04:00
if ( ok & & ! next_token ( & p , datatype , " : " , sizeof ( datatype ) ) ) ok = 0 ;
1998-01-02 16:33:20 +03:00
if ( ok ) {
PACKI ( desc , " W " , 0x0400 ) ; /* don't know */
PACKS ( desc , " z " , lp_printerdriver ( snum ) ) ; /* long printer name */
1998-01-01 16:55:28 +03:00
PACKS ( desc , " z " , driver ) ; /* Driverfile Name */
PACKS ( desc , " z " , datafile ) ; /* Datafile name */
PACKS ( desc , " z " , langmon ) ; /* language monitor */
1998-01-02 16:33:20 +03:00
PACKS ( desc , " z " , lp_driverlocation ( snum ) ) ; /* share to retrieve files */
PACKS ( desc , " z " , datatype ) ; /* default data type */
PACKS ( desc , " z " , helpfile ) ; /* helpfile name */
PACKS ( desc , " z " , driver ) ; /* driver name */
1997-10-28 22:32:59 +03:00
DEBUG ( 3 , ( " Driver:%s: \n " , driver ) ) ;
1998-01-01 16:55:28 +03:00
DEBUG ( 3 , ( " Data File:%s: \n " , datafile ) ) ;
DEBUG ( 3 , ( " Language Monitor:%s: \n " , langmon ) ) ;
DEBUG ( 3 , ( " Data Type:%s: \n " , datatype ) ) ;
DEBUG ( 3 , ( " Help File:%s: \n " , helpfile ) ) ;
1998-01-02 16:33:20 +03:00
PACKI ( desc , " N " , count ) ; /* number of files to copy */
for ( i = 0 ; i < count ; i + + )
{
/* no need to check return value here - it was already tested in
* get_printerdrivernumber
*/
1998-08-31 07:11:42 +04:00
next_token ( & p , tok , " , " , sizeof ( tok ) ) ;
1998-01-02 16:33:20 +03:00
PACKS ( desc , " z " , tok ) ; /* driver files to copy */
DEBUG ( 3 , ( " file:%s: \n " , tok ) ) ;
}
DEBUG ( 3 , ( " fill_printq_info on <%s> gave %d entries \n " ,
SERVICE ( snum ) , count ) ) ;
} else {
DEBUG ( 3 , ( " fill_printq_info: Can't supply driver files \n " ) ) ;
desc - > errcode = NERR_notsupported ;
1997-10-28 22:32:59 +03:00
}
free ( q ) ;
}
1996-05-04 11:50:46 +04:00
}
1998-01-02 16:33:20 +03:00
/* This function returns the number of files for a given driver */
1998-09-05 09:07:05 +04:00
static int get_printerdrivernumber ( int snum )
1997-10-28 22:32:59 +03:00
{
int i = 0 , ok = 0 ;
pstring tok ;
char * p , * q ;
FILE * f ;
pstring fname ;
1998-05-12 04:55:32 +04:00
pstrcpy ( fname , lp_driverfile ( ) ) ;
1997-10-28 22:32:59 +03:00
DEBUG ( 4 , ( " In get_printerdrivernumber: %s \n " , fname ) ) ;
f = fopen ( fname , " r " ) ;
if ( ! f ) {
1998-01-02 16:33:20 +03:00
DEBUG ( 3 , ( " get_printerdrivernumber: Can't open %s - %s \n " , fname , strerror ( errno ) ) ) ;
1997-10-28 22:32:59 +03:00
return ( 0 ) ;
}
1998-09-29 03:55:09 +04:00
if ( ( p = ( char * ) malloc ( 8192 * sizeof ( char ) ) ) = = NULL ) {
DEBUG ( 3 , ( " get_printerdrivernumber: malloc fail ! \n " ) ) ;
fclose ( f ) ;
return 0 ;
}
1997-10-28 22:32:59 +03:00
q = p ; /* need it to free memory because p change ! */
/* lookup the long printer driver name in the file description */
while ( ! feof ( f ) & & ! ok )
{
1998-01-02 16:33:20 +03:00
p = q ; /* reset string pointer */
1997-10-28 22:32:59 +03:00
fgets ( p , 8191 , f ) ;
1998-08-31 07:11:42 +04:00
if ( next_token ( & p , tok , " : " , sizeof ( tok ) ) & &
1998-01-02 16:33:20 +03:00
( ! strncmp ( tok , lp_printerdriver ( snum ) , strlen ( lp_printerdriver ( snum ) ) ) ) )
ok = 1 ;
1997-10-28 22:32:59 +03:00
}
1998-01-02 16:33:20 +03:00
fclose ( f ) ;
1997-10-28 22:32:59 +03:00
if ( ok ) {
1998-01-02 16:33:20 +03:00
/* skip 5 fields */
i = 5 ;
while ( * p & & i ) {
if ( * p + + = = ' : ' ) i - - ;
}
if ( ! * p | | i )
return ( 0 ) ;
1997-10-28 22:32:59 +03:00
/* count the number of files */
1998-08-31 07:11:42 +04:00
while ( next_token ( & p , tok , " , " , sizeof ( tok ) ) )
1997-10-28 22:32:59 +03:00
i + + ;
}
free ( q ) ;
return ( i ) ;
}
1998-08-14 21:38:29 +04:00
static BOOL api_DosPrintQGetInfo ( connection_struct * conn ,
uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ;
1998-09-17 23:16:12 +04:00
int uLevel ;
1996-05-04 11:50:46 +04:00
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 ) ;
str3 = p + 4 ;
1996-08-13 12:57:55 +04:00
/* remove any trailing username */
1996-05-04 11:50:46 +04:00
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 ) ;
1998-08-16 10:20:18 +04:00
if ( uLevel = = 52 ) {
count = get_printerdrivernumber ( snum ) ;
DEBUG ( 3 , ( " api_DosPrintQGetInfo: Driver files count: %d \n " , count ) ) ;
1998-08-14 21:38:29 +04:00
} else {
1998-08-16 10:20:18 +04:00
count = get_printqueue ( snum , conn , & queue , & status ) ;
1997-10-28 22:32:59 +03:00
}
1996-05-04 11:50:46 +04:00
if ( mdrcnt > 0 ) * rdata = REALLOC ( * rdata , mdrcnt ) ;
desc . base = * rdata ;
desc . buflen = mdrcnt ;
if ( init_package ( & desc , 1 , count ) ) {
1998-08-16 10:20:18 +04:00
desc . subcount = count ;
fill_printq_info ( conn , snum , uLevel , & desc , count , queue , & status ) ;
1996-05-04 11:50:46 +04:00
}
* 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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_DosPrintQEnum ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ) ) ;
1996-08-14 19:01:09 +04:00
if ( ! prefix_ok ( param_format , " WrLeh " ) ) return False ;
1996-05-04 11:50:46 +04:00
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 ) {
1998-09-29 03:55:09 +04:00
if ( ( queue = ( print_queue_struct * * ) malloc ( queuecnt * sizeof ( print_queue_struct * ) ) ) = = NULL ) {
DEBUG ( 0 , ( " api_DosPrintQEnum: malloc fail ! \n " ) ) ;
return False ;
}
1996-05-04 11:50:46 +04:00
memset ( queue , 0 , queuecnt * sizeof ( print_queue_struct * ) ) ;
1998-09-29 03:55:09 +04:00
if ( ( status = ( print_status_struct * ) malloc ( queuecnt * sizeof ( print_status_struct ) ) ) = = NULL ) {
DEBUG ( 0 , ( " api_DosPrintQEnum: malloc fail ! \n " ) ) ;
return False ;
}
1996-05-04 11:50:46 +04:00
memset ( status , 0 , queuecnt * sizeof ( print_status_struct ) ) ;
1998-09-29 03:55:09 +04:00
if ( ( subcntarr = ( int * ) malloc ( queuecnt * sizeof ( int ) ) ) = = NULL ) {
DEBUG ( 0 , ( " api_DosPrintQEnum: malloc fail ! \n " ) ) ;
return False ;
}
1996-05-04 11:50:46 +04:00
subcnt = 0 ;
n = 0 ;
for ( i = 0 ; i < services ; i + + )
if ( lp_snum_ok ( i ) & & lp_print_ok ( i ) & & lp_browseable ( i ) ) {
1998-08-14 21:38:29 +04:00
subcntarr [ n ] = get_printqueue ( i , conn , & queue [ n ] , & status [ n ] ) ;
1996-05-04 11:50:46 +04:00
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 ) ) {
1998-08-14 21:38:29 +04:00
fill_printq_info ( conn , i , uLevel , & desc , subcntarr [ n ] , queue [ n ] , & status [ n ] ) ;
1996-05-04 11:50:46 +04:00
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 ;
}
struct srv_info_struct
{
fstring name ;
uint32 type ;
fstring comment ;
1996-08-17 15:37:44 +04:00
fstring domain ;
BOOL server_added ;
1996-05-04 11:50:46 +04:00
} ;
/*******************************************************************
get server info lists from the files saved by nmbd . Return the
number of entries
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int get_server_info ( uint32 servertype ,
1996-08-17 15:37:44 +04:00
struct srv_info_struct * * servers ,
1996-06-06 15:43:09 +04:00
char * domain )
1996-05-04 11:50:46 +04:00
{
FILE * f ;
pstring fname ;
int count = 0 ;
int alloced = 0 ;
pstring line ;
1997-07-01 05:19:13 +04:00
BOOL local_list_only ;
1996-05-04 11:50:46 +04:00
1997-09-26 22:55:29 +04:00
pstrcpy ( fname , lp_lockdir ( ) ) ;
1996-05-04 11:50:46 +04:00
trim_string ( fname , NULL , " / " ) ;
1998-05-12 04:55:32 +04:00
pstrcat ( fname , " / " ) ;
pstrcat ( fname , SERVER_LIST ) ;
1996-05-04 11:50:46 +04:00
f = fopen ( fname , " r " ) ;
if ( ! f ) {
DEBUG ( 4 , ( " Can't open %s - %s \n " , fname , strerror ( errno ) ) ) ;
return ( 0 ) ;
}
1996-06-01 19:25:30 +04:00
/* request for everything is code for request all servers */
1997-07-01 05:19:13 +04:00
if ( servertype = = SV_TYPE_ALL )
servertype & = ~ ( SV_TYPE_DOMAIN_ENUM | SV_TYPE_LOCAL_LIST_ONLY ) ;
local_list_only = ( servertype & SV_TYPE_LOCAL_LIST_ONLY ) ;
1996-05-04 11:50:46 +04:00
1996-08-17 15:37:44 +04:00
DEBUG ( 4 , ( " Servertype search: %8x \n " , servertype ) ) ;
1996-06-01 19:25:30 +04:00
1996-05-04 11:50:46 +04:00
while ( ! feof ( f ) )
{
fstring stype ;
struct srv_info_struct * s ;
char * ptr = line ;
1996-06-01 19:25:30 +04:00
BOOL ok = True ;
1996-05-04 11:50:46 +04:00
* ptr = 0 ;
fgets ( line , sizeof ( line ) - 1 , f ) ;
if ( ! * line ) continue ;
1996-06-01 19:25:30 +04:00
1996-05-04 11:50:46 +04:00
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 ] ;
1996-06-01 19:25:30 +04:00
1998-08-31 07:11:42 +04:00
if ( ! next_token ( & ptr , s - > name , NULL , sizeof ( s - > name ) ) ) continue ;
if ( ! next_token ( & ptr , stype , NULL , sizeof ( stype ) ) ) continue ;
if ( ! next_token ( & ptr , s - > comment , NULL , sizeof ( s - > comment ) ) ) continue ;
if ( ! next_token ( & ptr , s - > domain , NULL , sizeof ( s - > domain ) ) ) {
1996-10-02 19:41:30 +04:00
/* this allows us to cope with an old nmbd */
1998-05-12 04:55:32 +04:00
pstrcpy ( s - > domain , global_myworkgroup ) ;
1996-10-02 19:41:30 +04:00
}
1996-06-01 19:25:30 +04:00
1996-06-06 15:43:09 +04:00
if ( sscanf ( stype , " %X " , & s - > type ) ! = 1 ) {
DEBUG ( 4 , ( " r:host file " ) ) ;
ok = False ;
}
1996-06-01 19:25:30 +04:00
1997-07-01 05:19:13 +04:00
/* Filter the servers/domains we return based on what was asked for. */
/* Check to see if we are being asked for a local list only. */
if ( local_list_only & & ( ( s - > type & SV_TYPE_LOCAL_LIST_ONLY ) = = 0 ) ) {
DEBUG ( 4 , ( " r: local list only " ) ) ;
ok = False ;
}
1996-05-04 11:50:46 +04:00
/* doesn't match up: don't want it */
1996-06-06 15:43:09 +04:00
if ( ! ( servertype & s - > type ) ) {
DEBUG ( 4 , ( " r:serv type " ) ) ;
ok = False ;
}
1996-06-01 19:25:30 +04:00
1996-08-17 15:37:44 +04:00
if ( ( servertype & SV_TYPE_DOMAIN_ENUM ) ! =
1996-06-01 19:25:30 +04:00
( s - > type & SV_TYPE_DOMAIN_ENUM ) )
{
1996-08-17 15:37:44 +04:00
DEBUG ( 4 , ( " s: dom mismatch " ) ) ;
1996-06-01 19:25:30 +04:00
ok = False ;
}
1996-08-17 15:37:44 +04:00
if ( ! strequal ( domain , s - > domain ) & & ! ( servertype & SV_TYPE_DOMAIN_ENUM ) )
1996-06-01 19:25:30 +04:00
{
1996-08-17 15:37:44 +04:00
ok = False ;
1996-06-01 19:25:30 +04:00
}
1997-07-01 05:19:13 +04:00
/* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
s - > type & = ~ SV_TYPE_LOCAL_LIST_ONLY ;
1996-06-01 19:25:30 +04:00
if ( ok )
{
DEBUG ( 4 , ( " **SV** %20s %8x %25s %15s \n " ,
s - > name , s - > type , s - > comment , s - > domain ) ) ;
s - > server_added = True ;
count + + ;
}
else
{
DEBUG ( 4 , ( " %20s %8x %25s %15s \n " ,
s - > name , s - > type , s - > comment , s - > domain ) ) ;
}
1996-05-04 11:50:46 +04:00
}
1996-06-01 19:25:30 +04:00
1996-05-04 11:50:46 +04:00
fclose ( f ) ;
return ( count ) ;
}
1996-06-06 15:43:09 +04:00
1996-05-04 11:50:46 +04:00
/*******************************************************************
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 ;
}
1996-06-06 15:43:09 +04:00
static BOOL srv_comp ( struct srv_info_struct * s1 , struct srv_info_struct * s2 )
{
return ( strcmp ( s1 - > name , s2 - > name ) ) ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
view list of servers available ( or possibly domains ) . The info is
extracted from lists saved by nmbd on the local host
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_RNetServerEnum ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ;
1998-01-17 10:08:21 +03:00
int f_len = 0 , s_len = 0 ;
1996-05-04 11:50:46 +04:00
struct srv_info_struct * servers = NULL ;
int counted = 0 , total = 0 ;
1996-08-20 19:45:16 +04:00
int i , missed ;
1996-05-04 11:50:46 +04:00
fstring domain ;
1996-06-01 19:25:30 +04:00
BOOL domain_request ;
1997-08-14 00:16:32 +04:00
BOOL local_request ;
1996-06-01 19:25:30 +04:00
1997-08-14 00:16:32 +04:00
/* If someone sets all the bits they don't really mean to set
DOMAIN_ENUM and LOCAL_LIST_ONLY , they just want all the
known servers . */
if ( servertype = = SV_TYPE_ALL )
servertype & = ~ ( SV_TYPE_DOMAIN_ENUM | SV_TYPE_LOCAL_LIST_ONLY ) ;
1996-06-01 19:25:30 +04:00
1997-08-19 23:22:26 +04:00
/* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
any other bit ( they may just set this bit on it ' s own ) they
want all the locally seen servers . However this bit can be
set on its own so set the requested servers to be
ALL - DOMAIN_ENUM . */
if ( ( servertype & SV_TYPE_LOCAL_LIST_ONLY ) & & ! ( servertype & SV_TYPE_DOMAIN_ENUM ) )
servertype = SV_TYPE_ALL & ~ ( SV_TYPE_DOMAIN_ENUM ) ;
1996-08-17 15:37:44 +04:00
domain_request = ( ( servertype & SV_TYPE_DOMAIN_ENUM ) ! = 0 ) ;
1997-08-14 00:16:32 +04:00
local_request = ( ( servertype & SV_TYPE_LOCAL_LIST_ONLY ) ! = 0 ) ;
1996-05-04 11:50:46 +04:00
p + = 8 ;
if ( ! prefix_ok ( str1 , " WrLehD " ) ) return False ;
if ( ! check_server_info ( uLevel , str2 ) ) return False ;
1996-06-01 19:25:30 +04:00
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 ) ) ) ;
1996-05-04 11:50:46 +04:00
1996-08-17 15:37:44 +04:00
if ( strcmp ( str1 , " WrLehDz " ) = = 0 ) {
1996-05-04 11:50:46 +04:00
StrnCpy ( domain , p , sizeof ( fstring ) - 1 ) ;
1996-10-02 19:41:30 +04:00
} else {
1998-04-25 05:12:08 +04:00
StrnCpy ( domain , global_myworkgroup , sizeof ( fstring ) - 1 ) ;
1996-05-04 11:50:46 +04:00
}
if ( lp_browse_list ( ) )
1996-08-17 15:37:44 +04:00
total = get_server_info ( servertype , & servers , domain ) ;
1996-05-04 11:50:46 +04:00
data_len = fixed_len = string_len = 0 ;
1996-08-20 19:45:16 +04:00
missed = 0 ;
1996-05-04 11:50:46 +04:00
1996-06-06 15:43:09 +04:00
qsort ( servers , total , sizeof ( servers [ 0 ] ) , QSORT_CAST srv_comp ) ;
1996-06-01 19:25:30 +04:00
{
1996-06-06 15:43:09 +04:00
char * lastname = NULL ;
1996-06-01 19:25:30 +04:00
for ( i = 0 ; i < total ; i + + )
{
struct srv_info_struct * s = & servers [ i ] ;
1996-08-17 15:37:44 +04:00
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 ) ) ;
1996-08-20 19:45:16 +04:00
if ( data_len < = buf_len ) {
1996-08-17 15:37:44 +04:00
counted + + ;
fixed_len + = f_len ;
string_len + = s_len ;
1996-08-20 19:45:16 +04:00
} else {
missed + + ;
}
1996-05-04 11:50:46 +04:00
}
1996-06-01 19:25:30 +04:00
}
1996-05-04 11:50:46 +04:00
* 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 ;
{
1996-06-06 15:43:09 +04:00
char * lastname = NULL ;
1996-05-04 11:50:46 +04:00
int count2 = counted ;
1996-06-01 19:25:30 +04:00
for ( i = 0 ; i < total & & count2 ; i + + )
{
1996-06-06 15:43:09 +04:00
struct srv_info_struct * s = & servers [ i ] ;
1996-08-17 15:37:44 +04:00
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 - - ;
1996-05-04 11:50:46 +04:00
}
}
* rparam_len = 8 ;
* rparam = REALLOC ( * rparam , * rparam_len ) ;
1998-06-04 22:49:13 +04:00
SSVAL ( * rparam , 0 , ( missed = = 0 ? NERR_Success : ERRmoredata ) ) ;
1996-05-04 11:50:46 +04:00
SSVAL ( * rparam , 2 , 0 ) ;
SSVAL ( * rparam , 4 , counted ) ;
1996-08-20 19:45:16 +04:00
SSVAL ( * rparam , 6 , counted + missed ) ;
1996-05-04 11:50:46 +04:00
if ( servers ) free ( servers ) ;
DEBUG ( 3 , ( " NetServerEnum domain = %s uLevel=%d counted=%d total=%d \n " ,
1996-08-20 19:45:16 +04:00
domain , uLevel , counted , counted + missed ) ) ;
1996-05-04 11:50:46 +04:00
return ( True ) ;
}
1998-03-12 00:11:04 +03:00
/****************************************************************************
command 0x34 - suspected of being a " Lookup Names " stub api
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_RNetGroupGetUsers ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1998-03-12 00:11:04 +03:00
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 ) ;
int counted = 0 ;
int missed = 0 ;
DEBUG ( 5 , ( " RNetGroupGetUsers: %s %s %s %d %d \n " ,
str1 , str2 , p , uLevel , buf_len ) ) ;
if ( ! prefix_ok ( str1 , " zWrLeh " ) ) return False ;
* rdata_len = 0 ;
* rdata = NULL ;
* rparam_len = 8 ;
* rparam = REALLOC ( * rparam , * rparam_len ) ;
SSVAL ( * rparam , 0 , 0x08AC ) ; /* informational warning message */
SSVAL ( * rparam , 2 , 0 ) ;
SSVAL ( * rparam , 4 , counted ) ;
SSVAL ( * rparam , 6 , counted + missed ) ;
return ( True ) ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
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 ;
}
1998-08-14 21:38:29 +04:00
static int fill_share_info ( connection_struct * conn , int snum , int uLevel ,
1996-05-04 11:50:46 +04:00
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 ;
1998-08-14 21:38:29 +04:00
if ( uLevel > 0 ) len + = StrlenExpanded ( conn , snum , lp_comment ( snum ) ) ;
1996-05-04 11:50:46 +04:00
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 ) ) ;
1998-08-14 21:38:29 +04:00
len + = CopyExpanded ( conn , snum , & p2 , lp_comment ( snum ) , & l2 ) ;
1996-05-04 11:50:46 +04:00
}
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 ;
}
1998-08-14 21:38:29 +04:00
static BOOL api_RNetShareGetInfo ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ;
1998-08-14 21:38:29 +04:00
* rdata_len = fill_share_info ( conn , snum , uLevel , & p , & mdrcnt , 0 , 0 , 0 ) ;
1996-05-04 11:50:46 +04:00
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_RNetShareEnum ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ;
1998-06-03 05:04:45 +04:00
BOOL missed = False ;
1996-05-04 11:50:46 +04:00
int i ;
int data_len , fixed_len , string_len ;
1998-01-17 10:08:21 +03:00
int f_len = 0 , s_len = 0 ;
1996-05-04 11:50:46 +04:00
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 ) )
1998-06-03 05:04:45 +04:00
{
total + + ;
1998-08-14 21:38:29 +04:00
data_len + = fill_share_info ( conn , i , uLevel , 0 , & f_len , 0 , & s_len , 0 ) ;
1998-06-03 05:04:45 +04:00
if ( data_len < = buf_len )
1996-05-04 11:50:46 +04:00
{
1998-06-03 05:04:45 +04:00
counted + + ;
fixed_len + = f_len ;
string_len + = s_len ;
1996-05-04 11:50:46 +04:00
}
1998-06-03 05:04:45 +04:00
else
missed = True ;
}
1996-05-04 11:50:46 +04:00
* 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 ) )
1998-08-14 21:38:29 +04:00
if ( fill_share_info ( conn , i , uLevel , & p , & f_len , & p2 , & s_len , * rdata ) < 0 )
1996-05-04 11:50:46 +04:00
break ;
* rparam_len = 8 ;
* rparam = REALLOC ( * rparam , * rparam_len ) ;
1998-06-04 22:49:13 +04:00
SSVAL ( * rparam , 0 , missed ? ERRmoredata : NERR_Success ) ;
1996-05-04 11:50:46 +04:00
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_NetRemoteTOD ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ) */
1996-05-31 19:13:29 +04:00
t = LocalTime ( & unixdate ) ;
1996-05-04 11:50:46 +04:00
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_SetUserPassword ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ;
1997-09-26 22:55:29 +04:00
fstrcpy ( user , p ) ;
1996-05-04 11:50:46 +04:00
p = skip_string ( p , 1 ) ;
1998-01-17 10:08:21 +03:00
memcpy ( pass1 , p , 16 ) ;
memcpy ( pass2 , p + 16 , 16 ) ;
1996-05-04 11:50:46 +04:00
* rparam_len = 4 ;
* rparam = REALLOC ( * rparam , * rparam_len ) ;
* rdata_len = 0 ;
1996-08-09 22:05:34 +04:00
SSVAL ( * rparam , 0 , NERR_badpass ) ;
1996-05-04 11:50:46 +04:00
SSVAL ( * rparam , 2 , 0 ) ; /* converter word */
DEBUG ( 3 , ( " Set password for <%s> \n " , user ) ) ;
1998-06-10 23:45:13 +04:00
/*
* Pass the user through the NT - > unix user mapping
* function .
*/
1998-06-12 07:08:23 +04:00
( void ) map_username ( user ) ;
1998-06-10 23:45:13 +04:00
/*
* Do any UNIX username case mangling .
*/
( void ) Get_Pwnam ( user , True ) ;
1998-01-17 10:08:21 +03:00
/*
* Attempt the plaintext password change first .
* Older versions of Windows seem to do this .
*/
1998-10-17 01:36:19 +04:00
if ( password_ok ( user , pass1 , strlen ( pass1 ) , NULL ) & &
1998-03-27 22:59:14 +03:00
chgpasswd ( user , pass1 , pass2 , False ) )
1996-08-09 22:05:34 +04:00
{
SSVAL ( * rparam , 0 , NERR_Success ) ;
}
1996-05-04 11:50:46 +04:00
1998-01-17 10:08:21 +03:00
/*
* If the plaintext change failed , attempt
* the encrypted . NT will generate this
* after trying the samr method .
*/
if ( SVAL ( * rparam , 0 ) ! = NERR_Success )
{
1998-05-07 22:19:05 +04:00
struct smb_passwd * sampw = NULL ;
1998-01-17 10:08:21 +03:00
1998-05-07 22:19:05 +04:00
if ( check_lanman_password ( user , ( unsigned char * ) pass1 , ( unsigned char * ) pass2 , & sampw ) & &
change_lanman_password ( sampw , ( unsigned char * ) pass1 , ( unsigned char * ) pass2 ) )
1998-01-17 10:08:21 +03:00
{
SSVAL ( * rparam , 0 , NERR_Success ) ;
}
}
1996-05-04 11:50:46 +04:00
bzero ( pass1 , sizeof ( fstring ) ) ;
bzero ( pass2 , sizeof ( fstring ) ) ;
return ( True ) ;
}
1998-03-18 22:07:53 +03:00
/****************************************************************************
Set the user password ( SamOEM version - gets plaintext ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_SamOEMChangePassword ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1998-03-18 22:07:53 +03:00
int mdrcnt , int mprcnt ,
char * * rdata , char * * rparam ,
int * rdata_len , int * rparam_len )
{
fstring user ;
char * p = param + 2 ;
* rparam_len = 2 ;
* rparam = REALLOC ( * rparam , * rparam_len ) ;
* rdata_len = 0 ;
SSVAL ( * rparam , 0 , NERR_badpass ) ;
/*
* Check the parameter definition is correct .
*/
if ( ! strequal ( param + 2 , " zsT " ) ) {
DEBUG ( 0 , ( " api_SamOEMChangePassword: Invalid parameter string %sn \n " , param + 2 ) ) ;
return False ;
}
p = skip_string ( p , 1 ) ;
if ( ! strequal ( p , " B516B16 " ) ) {
DEBUG ( 0 , ( " api_SamOEMChangePassword: Invalid data parameter string %sn \n " , p ) ) ;
return False ;
}
p = skip_string ( p , 1 ) ;
fstrcpy ( user , p ) ;
p = skip_string ( p , 1 ) ;
1998-06-10 23:45:13 +04:00
DEBUG ( 3 , ( " api_SamOEMChangePassword: Change password for <%s> \n " , user ) ) ;
/*
* Pass the user through the NT - > unix user mapping
* function .
*/
1998-06-12 07:08:23 +04:00
( void ) map_username ( user ) ;
1998-06-10 23:45:13 +04:00
/*
* Do any UNIX username case mangling .
*/
( void ) Get_Pwnam ( user , True ) ;
1998-10-19 21:32:10 +04:00
if ( pass_oem_change ( user , ( uchar * ) data , & data [ 516 ] , NULL , NULL ) )
{
1998-03-18 22:07:53 +03:00
SSVAL ( * rparam , 0 , NERR_Success ) ;
}
return ( True ) ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
delete a print job
Form : < W > < >
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_RDosPrintJobDel ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ) ;
1997-08-31 06:18:59 +04:00
int jobid , snum ;
1996-05-04 11:50:46 +04:00
int i , count ;
1997-08-31 06:18:59 +04:00
printjob_decode ( SVAL ( p , 0 ) , & snum , & jobid ) ;
1996-05-04 11:50:46 +04:00
/* 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 ) ;
1998-08-14 21:38:29 +04:00
count = get_printqueue ( snum , conn , & queue , NULL ) ;
1996-05-04 11:50:46 +04:00
for ( i = 0 ; i < count ; i + + )
1997-08-31 06:18:59 +04:00
if ( ( queue [ i ] . job & 0xFF ) = = jobid )
1996-05-04 11:50:46 +04:00
{
switch ( function ) {
case 81 : /* delete */
DEBUG ( 3 , ( " Deleting queue entry %d \n " , queue [ i ] . job ) ) ;
1998-08-14 21:38:29 +04:00
del_printqueue ( conn , snum , queue [ i ] . job ) ;
1996-05-04 11:50:46 +04:00
break ;
case 82 : /* pause */
case 83 : /* resume */
DEBUG ( 3 , ( " %s queue entry %d \n " ,
( function = = 82 ? " pausing " : " resuming " ) , queue [ i ] . job ) ) ;
1998-08-14 21:38:29 +04:00
status_printjob ( conn , snum , queue [ i ] . job ,
1996-05-04 11:50:46 +04:00
( 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 ) ;
}
1998-07-16 04:06:29 +04:00
/****************************************************************************
Purge a print queue - or pause or resume it .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_WPrintQueuePurge ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
int mdrcnt , int mprcnt ,
char * * rdata , char * * rparam ,
int * rdata_len , int * rparam_len )
{
1998-07-16 04:06:29 +04:00
int function = SVAL ( param , 0 ) ;
1996-05-04 11:50:46 +04:00
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 ) ) {
lpq_reset ( snum ) ;
1998-07-16 04:06:29 +04:00
switch ( function ) {
case 74 : /* Pause queue */
case 75 : /* Resume queue */
1998-08-14 21:38:29 +04:00
status_printqueue ( conn , snum , ( function = = 74 ? LPSTAT_STOPPED : LPSTAT_OK ) ) ;
1998-07-16 04:06:29 +04:00
DEBUG ( 3 , ( " Print queue %s, queue=%s \n " ,
( function = = 74 ? " pause " : " resume " ) , QueueName ) ) ;
break ;
case 103 : /* Purge */
{
print_queue_struct * queue = NULL ;
int i , count ;
1998-08-14 21:38:29 +04:00
count = get_printqueue ( snum , conn , & queue , NULL ) ;
1998-07-16 04:06:29 +04:00
for ( i = 0 ; i < count ; i + + )
1998-08-14 21:38:29 +04:00
del_printqueue ( conn , snum , queue [ i ] . job ) ;
1998-07-16 04:06:29 +04:00
if ( queue ) free ( queue ) ;
DEBUG ( 3 , ( " Print queue purge, queue=%s \n " , QueueName ) ) ;
break ;
}
}
1996-05-04 11:50:46 +04:00
}
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 ;
}
1998-08-14 21:38:29 +04:00
static BOOL api_PrintJobInfo ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
int mdrcnt , int mprcnt ,
char * * rdata , char * * rparam ,
int * rdata_len , int * rparam_len )
{
1998-08-15 11:27:34 +04:00
struct pack_desc desc ;
char * str1 = param + 2 ;
char * str2 = skip_string ( str1 , 1 ) ;
char * p = skip_string ( str2 , 1 ) ;
int jobid , snum ;
int uLevel = SVAL ( p , 2 ) ;
int function = SVAL ( p , 4 ) ; /* what is this ?? */
int i ;
char * s = data ;
files_struct * fsp ;
1997-08-31 06:18:59 +04:00
1998-08-15 11:27:34 +04:00
printjob_decode ( SVAL ( p , 0 ) , & snum , & jobid ) ;
1996-05-04 11:50:46 +04:00
1998-08-15 11:27:34 +04:00
* rparam_len = 4 ;
* rparam = REALLOC ( * rparam , * rparam_len ) ;
1996-05-04 11:50:46 +04:00
1998-08-15 11:27:34 +04:00
* rdata_len = 0 ;
/* check it's a supported varient */
if ( ( strcmp ( str1 , " WWsTP " ) ) | |
( ! check_printjob_info ( & desc , uLevel , str2 ) ) )
return ( False ) ;
1996-05-04 11:50:46 +04:00
1998-08-15 11:27:34 +04:00
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 ;
1996-05-04 11:50:46 +04:00
1998-08-15 11:27:34 +04:00
lpq_reset ( snum ) ;
count = get_printqueue ( snum , conn , & queue , NULL ) ;
for ( i = 0 ; i < count ; i + + ) /* find job */
if ( ( queue [ i ] . job & 0xFF ) = = jobid ) break ;
1996-05-04 11:50:46 +04:00
1998-08-15 11:27:34 +04:00
if ( i = = count ) {
desc . errcode = NERR_JobNotFound ;
if ( queue ) free ( queue ) ;
} else {
desc . errcode = NERR_Success ;
i + + ;
1996-05-04 11:50:46 +04:00
#if 0
1998-08-15 11:27:34 +04:00
{
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 */ ;
}
1996-05-04 11:50:46 +04:00
# endif
1998-08-15 11:27:34 +04:00
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 ( ( int ) * s ) ) {
pstring name ;
int l = 0 ;
while ( l < 64 & & * s ) {
if ( issafe ( * s ) ) name [ l + + ] = * s ;
s + + ;
}
name [ l ] = 0 ;
1996-05-04 11:50:46 +04:00
1998-08-15 11:27:34 +04:00
DEBUG ( 3 , ( " Setting print name to %s \n " , name ) ) ;
1996-05-04 11:50:46 +04:00
1998-08-15 11:27:34 +04:00
fsp = file_find_print ( ) ;
if ( fsp ) {
connection_struct * fconn = fsp - > conn ;
unbecome_user ( ) ;
1996-05-04 11:50:46 +04:00
1998-08-15 11:27:34 +04:00
if ( ! become_user ( fconn , vuid ) | |
! become_service ( fconn , True ) )
break ;
1996-05-04 11:50:46 +04:00
1998-09-02 00:11:54 +04:00
if ( dos_rename ( fsp - > fsp_name , name ) = = 0 ) {
1998-08-15 11:27:34 +04:00
string_set ( & fsp - > fsp_name , name ) ;
}
break ;
}
}
desc . errcode = NERR_Success ;
break ;
1997-10-16 01:53:59 +04:00
1998-08-15 11:27:34 +04:00
default : /* not implemented */
return False ;
}
1996-05-04 11:50:46 +04:00
1998-08-15 11:27:34 +04:00
SSVALS ( * rparam , 0 , desc . errcode ) ;
SSVAL ( * rparam , 2 , 0 ) ; /* converter word */
return ( True ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
get info about the server
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_RNetServerGetInfo ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ;
1997-07-30 23:17:51 +04:00
uint32 servertype = lp_default_server_announce ( ) ;
1996-05-04 11:50:46 +04:00
1997-09-26 22:55:29 +04:00
pstrcpy ( comment , lp_serverstring ( ) ) ;
1996-05-04 11:50:46 +04:00
1998-04-25 05:12:08 +04:00
if ( ( count = get_server_info ( SV_TYPE_ALL , & servers , global_myworkgroup ) ) > 0 ) {
1996-05-04 11:50:46 +04:00
for ( i = 0 ; i < count ; i + + )
1997-03-09 17:58:22 +03:00
if ( strequal ( servers [ i ] . name , local_machine ) )
{
1996-05-04 11:50:46 +04:00
servertype = servers [ i ] . type ;
1997-09-26 22:55:29 +04:00
pstrcpy ( comment , servers [ i ] . comment ) ;
1996-05-04 11:50:46 +04:00
}
}
if ( servers ) free ( servers ) ;
1997-07-30 23:17:51 +04:00
SCVAL ( p , 0 , lp_major_announce_version ( ) ) ;
SCVAL ( p , 1 , lp_minor_announce_version ( ) ) ;
1996-05-04 11:50:46 +04:00
SIVAL ( p , 2 , servertype ) ;
1996-08-09 22:05:34 +04:00
1996-05-04 11:50:46 +04:00
if ( mdrcnt = = struct_len ) {
SIVAL ( p , 6 , 0 ) ;
} else {
SIVAL ( p , 6 , PTR_DIFF ( p2 , * rdata ) ) ;
1998-08-14 21:38:29 +04:00
standard_sub ( conn , comment ) ;
1996-05-04 11:50:46 +04:00
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_NetWkstaGetInfo ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ;
1997-03-09 17:58:22 +03:00
SIVAL ( p , 0 , PTR_DIFF ( p2 , * rdata ) ) ; /* host name */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , local_machine ) ;
1997-03-09 17:58:22 +03:00
strupper ( p2 ) ;
1996-05-04 11:50:46 +04:00
p2 = skip_string ( p2 , 1 ) ;
p + = 4 ;
SIVAL ( p , 0 , PTR_DIFF ( p2 , * rdata ) ) ;
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , sesssetup_user ) ;
1996-05-04 11:50:46 +04:00
p2 = skip_string ( p2 , 1 ) ;
p + = 4 ;
1997-03-09 17:58:22 +03:00
SIVAL ( p , 0 , PTR_DIFF ( p2 , * rdata ) ) ; /* login domain */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , global_myworkgroup ) ;
1997-03-09 17:58:22 +03:00
strupper ( p2 ) ;
1996-05-04 11:50:46 +04:00
p2 = skip_string ( p2 , 1 ) ;
p + = 4 ;
1997-07-30 23:17:51 +04:00
SCVAL ( p , 0 , lp_major_announce_version ( ) ) ; /* system version - e.g 4 in 4.1 */
SCVAL ( p , 1 , lp_minor_announce_version ( ) ) ; /* system version - e.g .1 in 4.1 */
1996-05-04 11:50:46 +04:00
p + = 2 ;
SIVAL ( p , 0 , PTR_DIFF ( p2 , * rdata ) ) ;
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , global_myworkgroup ) ; /* don't know. login domain?? */
1996-05-04 11:50:46 +04:00
p2 = skip_string ( p2 , 1 ) ;
p + = 4 ;
1997-03-09 17:58:22 +03:00
SIVAL ( p , 0 , PTR_DIFF ( p2 , * rdata ) ) ; /* don't know */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , " " ) ;
1996-05-04 11:50:46 +04:00
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
1997-03-09 17:58:22 +03:00
struct user_info_11 {
char usri11_name [ 21 ] ; 0 - 20
char usri11_pad ; 21
char * usri11_comment ; 22 - 25
char * usri11_usr_comment ; 26 - 29
unsigned short usri11_priv ; 30 - 31
unsigned long usri11_auth_flags ; 32 - 35
long usri11_password_age ; 36 - 39
char * usri11_homedir ; 40 - 43
char * usri11_parms ; 44 - 47
long usri11_last_logon ; 48 - 51
long usri11_last_logoff ; 52 - 55
unsigned short usri11_bad_pw_count ; 56 - 57
unsigned short usri11_num_logons ; 58 - 59
char * usri11_logon_server ; 60 - 63
unsigned short usri11_country_code ; 64 - 65
char * usri11_workstations ; 66 - 69
unsigned long usri11_max_storage ; 70 - 73
unsigned short usri11_units_per_week ; 74 - 75
unsigned char * usri11_logon_hours ; 76 - 79
unsigned short usri11_code_page ; 80 - 81
} ;
where :
usri11_name specifies the user name for which information is retireved
usri11_pad aligns the next data structure element to a word boundary
usri11_comment is a null terminated ASCII comment
usri11_user_comment is a null terminated ASCII comment about the user
usri11_priv specifies the level of the privilege assigned to the user .
The possible values are :
Name Value Description
USER_PRIV_GUEST 0 Guest privilege
USER_PRIV_USER 1 User privilege
USER_PRV_ADMIN 2 Administrator privilege
usri11_auth_flags specifies the account operator privileges . The
possible values are :
Name Value Description
AF_OP_PRINT 0 Print operator
Leach , Naik [ Page 28 ]
INTERNET - DRAFT CIFS Remote Admin Protocol January 10 , 1997
AF_OP_COMM 1 Communications operator
AF_OP_SERVER 2 Server operator
AF_OP_ACCOUNTS 3 Accounts operator
usri11_password_age specifies how many seconds have elapsed since the
password was last changed .
usri11_home_dir points to a null terminated ASCII string that contains
the path name of the user ' s home directory .
usri11_parms points to a null terminated ASCII string that is set
aside for use by applications .
usri11_last_logon specifies the time when the user last logged on .
This value is stored as the number of seconds elapsed since
00 : 00 : 00 , January 1 , 1970.
usri11_last_logoff specifies the time when the user last logged off .
This value is stored as the number of seconds elapsed since
00 : 00 : 00 , January 1 , 1970. A value of 0 means the last logoff
time is unknown .
usri11_bad_pw_count specifies the number of incorrect passwords
entered since the last successful logon .
usri11_log1_num_logons specifies the number of times this user has
logged on . A value of - 1 means the number of logons is unknown .
usri11_logon_server points to a null terminated ASCII string that
contains the name of the server to which logon requests are sent .
A null string indicates logon requests should be sent to the
domain controller .
usri11_country_code specifies the country code for the user ' s language
of choice .
usri11_workstations points to a null terminated ASCII string that
contains the names of workstations the user may log on from .
There may be up to 8 workstations , with the names separated by
commas . A null strings indicates there are no restrictions .
usri11_max_storage specifies the maximum amount of disk space the user
can occupy . A value of 0xffffffff indicates there are no
restrictions .
usri11_units_per_week specifies the equal number of time units into
which a week is divided . This value must be equal to 168.
usri11_logon_hours points to a 21 byte ( 168 bits ) string that
specifies the time during which the user can log on . Each bit
represents one unique hour in a week . The first bit ( bit 0 , word
0 ) is Sunday , 0 : 00 to 0 : 59 , the second bit ( bit 1 , word 0 ) is
Leach , Naik [ Page 29 ]
INTERNET - DRAFT CIFS Remote Admin Protocol January 10 , 1997
Sunday , 1 : 00 to 1 : 59 and so on . A null pointer indicates there
are no restrictions .
usri11_code_page specifies the code page for the user ' s language of
choice
All of the pointers in this data structure need to be treated
specially . The pointer is a 32 bit pointer . The higher 16 bits need
to be ignored . The converter word returned in the parameters section
needs to be subtracted from the lower 16 bits to calculate an offset
into the return buffer where this ASCII string resides .
There is no auxiliary data in the response .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-03-09 17:58:22 +03:00
# define usri11_name 0
# define usri11_pad 21
# define usri11_comment 22
# define usri11_usr_comment 26
# define usri11_full_name 30
# define usri11_priv 34
# define usri11_auth_flags 36
# define usri11_password_age 40
# define usri11_homedir 44
# define usri11_parms 48
# define usri11_last_logon 52
# define usri11_last_logoff 56
# define usri11_bad_pw_count 60
# define usri11_num_logons 62
# define usri11_logon_server 64
# define usri11_country_code 68
# define usri11_workstations 70
# define usri11_max_storage 74
# define usri11_units_per_week 78
# define usri11_logon_hours 80
# define usri11_code_page 84
# define usri11_end 86
1996-05-04 11:50:46 +04:00
# define USER_PRIV_GUEST 0
# define USER_PRIV_USER 1
# define USER_PRIV_ADMIN 2
1997-03-09 17:58:22 +03:00
# define AF_OP_PRINT 0
# define AF_OP_COMM 1
# define AF_OP_SERVER 2
# define AF_OP_ACCOUNTS 3
1997-05-07 21:56:46 +04:00
1998-08-14 21:38:29 +04:00
static BOOL api_RNetUserGetInfo ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
int mdrcnt , int mprcnt ,
char * * rdata , char * * rparam ,
int * rdata_len , int * rparam_len )
{
1997-03-09 17:58:22 +03:00
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 ;
1997-05-07 21:56:46 +04:00
/* get NIS home of a previously validated user - simeon */
1998-03-12 00:11:04 +03:00
/* With share level security vuid will always be zero.
Don ' t depend on vuser being non - null ! ! . JRA */
1997-05-07 21:56:46 +04:00
user_struct * vuser = get_valid_user_struct ( vuid ) ;
1998-03-12 00:11:04 +03:00
if ( vuser ! = NULL )
1998-09-30 00:24:17 +04:00
DEBUG ( 3 , ( " Username of UID %d is %s \n " , ( int ) vuser - > uid , vuser - > name ) ) ;
1997-03-09 17:58:22 +03:00
1997-05-07 21:56:46 +04:00
* rparam_len = 6 ;
* rparam = REALLOC ( * rparam , * rparam_len ) ;
1997-10-21 13:09:55 +04:00
DEBUG ( 4 , ( " RNetUserGetInfo level=%d \n " , uLevel ) ) ;
1997-05-07 21:56:46 +04:00
/* check it's a supported variant */
1997-03-09 17:58:22 +03:00
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 ;
}
1996-05-04 11:50:46 +04:00
1997-03-09 17:58:22 +03:00
if ( strcmp ( p2 , str2 ) ! = 0 ) return False ;
1996-05-04 11:50:46 +04:00
1997-03-09 17:58:22 +03:00
* rdata_len = mdrcnt + 1024 ;
* rdata = REALLOC ( * rdata , * rdata_len ) ;
1996-05-04 11:50:46 +04:00
1997-03-09 17:58:22 +03:00
SSVAL ( * rparam , 0 , NERR_Success ) ;
SSVAL ( * rparam , 2 , 0 ) ; /* converter word */
1996-05-04 11:50:46 +04:00
1997-03-09 17:58:22 +03:00
p = * rdata ;
p2 = p + usri11_end ;
1996-05-04 11:50:46 +04:00
1997-03-09 17:58:22 +03:00
memset ( p , 0 , 21 ) ;
1997-09-26 22:55:29 +04:00
fstrcpy ( p + usri11_name , UserName ) ; /* 21 bytes - user name */
1996-05-04 11:50:46 +04:00
1997-03-09 17:58:22 +03:00
if ( uLevel > 0 )
{
SCVAL ( p , usri11_pad , 0 ) ; /* padding - 1 byte */
* p2 = 0 ;
}
if ( uLevel > = 10 )
{
SIVAL ( p , usri11_comment , PTR_DIFF ( p2 , p ) ) ; /* comment */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , " Comment " ) ;
1997-03-09 17:58:22 +03:00
p2 = skip_string ( p2 , 1 ) ;
SIVAL ( p , usri11_usr_comment , PTR_DIFF ( p2 , p ) ) ; /* user_comment */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , " UserComment " ) ;
1997-03-09 17:58:22 +03:00
p2 = skip_string ( p2 , 1 ) ;
1997-09-26 22:55:29 +04:00
/* EEK! the cifsrap.txt doesn't have this in!!!! */
1997-03-09 17:58:22 +03:00
SIVAL ( p , usri11_full_name , PTR_DIFF ( p2 , p ) ) ; /* full name */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , ( ( vuser ! = NULL ) ? vuser - > real_name : UserName ) ) ;
1997-03-09 17:58:22 +03:00
p2 = skip_string ( p2 , 1 ) ;
}
1997-05-07 21:56:46 +04:00
1997-03-09 17:58:22 +03:00
if ( uLevel = = 11 ) /* modelled after NTAS 3.51 reply */
{
1998-08-14 21:38:29 +04:00
SSVAL ( p , usri11_priv , conn - > admin_user ? USER_PRIV_ADMIN : USER_PRIV_USER ) ;
1997-03-09 17:58:22 +03:00
SIVAL ( p , usri11_auth_flags , AF_OP_PRINT ) ; /* auth flags */
1997-11-29 16:29:13 +03:00
SIVALS ( p , usri11_password_age , - 1 ) ; /* password age */
1997-03-09 17:58:22 +03:00
SIVAL ( p , usri11_homedir , PTR_DIFF ( p2 , p ) ) ; /* home dir */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , lp_logon_path ( ) ) ;
1997-03-09 17:58:22 +03:00
p2 = skip_string ( p2 , 1 ) ;
SIVAL ( p , usri11_parms , PTR_DIFF ( p2 , p ) ) ; /* parms */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , " " ) ;
1997-03-09 17:58:22 +03:00
p2 = skip_string ( p2 , 1 ) ;
SIVAL ( p , usri11_last_logon , 0 ) ; /* last logon */
SIVAL ( p , usri11_last_logoff , 0 ) ; /* last logoff */
1997-11-29 16:29:13 +03:00
SSVALS ( p , usri11_bad_pw_count , - 1 ) ; /* bad pw counts */
SSVALS ( p , usri11_num_logons , - 1 ) ; /* num logons */
1997-03-09 17:58:22 +03:00
SIVAL ( p , usri11_logon_server , PTR_DIFF ( p2 , p ) ) ; /* logon server */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , " \\ \\ * " ) ;
1997-03-09 17:58:22 +03:00
p2 = skip_string ( p2 , 1 ) ;
SSVAL ( p , usri11_country_code , 0 ) ; /* country code */
SIVAL ( p , usri11_workstations , PTR_DIFF ( p2 , p ) ) ; /* workstations */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , " " ) ;
1997-03-09 17:58:22 +03:00
p2 = skip_string ( p2 , 1 ) ;
1997-11-29 16:29:13 +03:00
SIVALS ( p , usri11_max_storage , - 1 ) ; /* max storage */
1997-03-09 17:58:22 +03:00
SSVAL ( p , usri11_units_per_week , 168 ) ; /* units per week */
SIVAL ( p , usri11_logon_hours , PTR_DIFF ( p2 , p ) ) ; /* logon hours */
/* a simple way to get logon hours at all times. */
memset ( p2 , 0xff , 21 ) ;
SCVAL ( p2 , 21 , 0 ) ; /* fix zero termination */
p2 = skip_string ( p2 , 1 ) ;
SSVAL ( p , usri11_code_page , 0 ) ; /* code page */
}
if ( uLevel = = 1 | | uLevel = = 2 )
{
memset ( p + 22 , ' ' , 16 ) ; /* password */
SIVALS ( p , 38 , - 1 ) ; /* password age */
SSVAL ( p , 42 ,
1998-08-14 21:38:29 +04:00
conn - > admin_user ? USER_PRIV_ADMIN : USER_PRIV_USER ) ;
1997-03-09 17:58:22 +03:00
SIVAL ( p , 44 , PTR_DIFF ( p2 , * rdata ) ) ; /* home dir */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , lp_logon_path ( ) ) ;
1997-03-09 17:58:22 +03:00
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 */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , ( ( vuser ! = NULL ) ? vuser - > real_name : UserName ) ) ;
1997-03-09 17:58:22 +03:00
p2 = skip_string ( p2 , 1 ) ;
SIVAL ( p , 68 , 0 ) ; /* urs_comment */
SIVAL ( p , 72 , PTR_DIFF ( p2 , * rdata ) ) ; /* parms */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , " " ) ;
1997-03-09 17:58:22 +03:00
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 */
1998-05-12 04:55:32 +04:00
pstrcpy ( p2 , " \\ \\ %L " ) ;
1997-03-09 17:58:22 +03:00
standard_sub_basic ( p2 ) ;
p2 = skip_string ( p2 , 1 ) ;
SSVAL ( p , 110 , 49 ) ; /* country_code */
SSVAL ( p , 112 , 860 ) ; /* code page */
}
}
1996-05-04 11:50:46 +04:00
1997-03-09 17:58:22 +03:00
* rdata_len = PTR_DIFF ( p2 , * rdata ) ;
1996-05-04 11:50:46 +04:00
1997-03-09 17:58:22 +03:00
SSVAL ( * rparam , 4 , * rdata_len ) ; /* is this right?? */
1996-05-04 11:50:46 +04:00
1997-03-09 17:58:22 +03:00
return ( True ) ;
1996-05-04 11:50:46 +04:00
}
/*******************************************************************
get groups that a user is a member of
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_NetUserGetGroups ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 */
1998-05-12 04:55:32 +04:00
pstrcpy ( p , " Users " ) ; p + = 21 ; count + + ;
pstrcpy ( p , " Domain Users " ) ; p + = 21 ; count + + ;
pstrcpy ( p , " Guests " ) ; p + = 21 ; count + + ;
pstrcpy ( p , " Domain Guests " ) ; p + = 21 ; count + + ;
1996-05-04 11:50:46 +04:00
* rdata_len = PTR_DIFF ( p , * rdata ) ;
SSVAL ( * rparam , 4 , count ) ; /* is this right?? */
SSVAL ( * rparam , 6 , count ) ; /* is this right?? */
return ( True ) ;
}
1998-08-14 21:38:29 +04:00
static BOOL api_WWkstaUserLogon ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ;
1997-09-17 17:53:59 +04:00
char * logon_script ;
1996-05-04 11:50:46 +04:00
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 ;
1997-03-09 17:58:22 +03:00
if ( init_package ( & desc , 1 , 0 ) )
{
1996-05-04 11:50:46 +04:00
PACKI ( & desc , " W " , 0 ) ; /* code */
PACKS ( & desc , " B21 " , name ) ; /* eff. name */
PACKS ( & desc , " B " , " " ) ; /* pad */
PACKI ( & desc , " W " ,
1998-08-14 21:38:29 +04:00
conn - > admin_user ? USER_PRIV_ADMIN : USER_PRIV_USER ) ;
1996-05-04 11:50:46 +04:00
PACKI ( & desc , " D " , 0 ) ; /* auth flags XXX */
PACKI ( & desc , " W " , 0 ) ; /* num logons */
PACKI ( & desc , " W " , 0 ) ; /* bad pw count */
1997-03-09 17:58:22 +03:00
PACKI ( & desc , " D " , 0 ) ; /* last logon */
1996-05-04 11:50:46 +04:00
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 ;
1998-05-12 04:55:32 +04:00
fstrcpy ( mypath , " \\ \\ " ) ;
fstrcat ( mypath , local_machine ) ;
1996-05-04 11:50:46 +04:00
strupper ( mypath ) ;
PACKS ( & desc , " z " , mypath ) ; /* computer */
}
1998-04-25 05:12:08 +04:00
PACKS ( & desc , " z " , global_myworkgroup ) ; /* domain */
1997-09-17 17:53:59 +04:00
/* JHT - By calling lp_logon_script() and standard_sub() we have */
/* made sure all macros are fully substituted and available */
logon_script = lp_logon_script ( ) ;
1998-08-14 21:38:29 +04:00
standard_sub ( conn , logon_script ) ;
1997-09-17 17:53:59 +04:00
PACKS ( & desc , " z " , logon_script ) ; /* script path */
/* End of JHT mods */
1997-03-09 17:58:22 +03:00
PACKI ( & desc , " D " , 0x00000000 ) ; /* reserved */
1996-05-04 11:50:46 +04:00
}
* 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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_WAccessGetUserPerms ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_WPrintJobGetInfo ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ) ;
1998-09-17 23:16:12 +04:00
int uLevel ;
1996-05-04 11:50:46 +04:00
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 ) ;
bzero ( & desc , sizeof ( desc ) ) ;
bzero ( & status , sizeof ( status ) ) ;
1997-08-31 06:18:59 +04:00
DEBUG ( 3 , ( " WPrintJobGetInfo uLevel=%d uJobId=0x%X \n " , uLevel , SVAL ( p , 0 ) ) ) ;
1996-05-04 11:50:46 +04:00
/* check it's a supported varient */
if ( strcmp ( str1 , " WWrLh " ) ! = 0 ) return False ;
if ( ! check_printjob_info ( & desc , uLevel , str2 ) ) return False ;
1997-08-31 06:18:59 +04:00
printjob_decode ( SVAL ( p , 0 ) , & snum , & job ) ;
1996-05-04 11:50:46 +04:00
if ( snum < 0 | | ! VALID_SNUM ( snum ) ) return ( False ) ;
1998-08-14 21:38:29 +04:00
count = get_printqueue ( snum , conn , & queue , & status ) ;
1996-05-04 11:50:46 +04:00
for ( i = 0 ; i < count ; i + + ) {
1997-08-31 06:18:59 +04:00
if ( ( queue [ i ] . job & 0xFF ) = = job ) break ;
1996-05-04 11:50:46 +04:00
}
if ( mdrcnt > 0 ) * rdata = REALLOC ( * rdata , mdrcnt ) ;
desc . base = * rdata ;
desc . buflen = mdrcnt ;
if ( init_package ( & desc , 1 , 0 ) ) {
if ( i < count ) {
1998-08-14 21:38:29 +04:00
fill_printjob_info ( conn , snum , uLevel , & desc , & queue [ i ] , i ) ;
1996-05-04 11:50:46 +04:00
* 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 ) ;
}
1998-08-14 21:38:29 +04:00
static BOOL api_WPrintJobEnumerate ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ;
1998-09-17 23:16:12 +04:00
int uLevel ;
1996-05-04 11:50:46 +04:00
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 ) ;
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 ) ;
1998-08-14 21:38:29 +04:00
count = get_printqueue ( snum , conn , & queue , & status ) ;
1996-05-04 11:50:46 +04:00
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 + + ) {
1998-08-14 21:38:29 +04:00
fill_printjob_info ( conn , snum , uLevel , & desc , & queue [ i ] , i ) ;
1996-05-04 11:50:46 +04:00
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 ;
}
1998-08-14 21:38:29 +04:00
static void fill_printdest_info ( connection_struct * conn , int snum , int uLevel ,
1996-05-04 11:50:46 +04:00
struct pack_desc * desc )
{
char buf [ 100 ] ;
1997-09-26 22:55:29 +04:00
strncpy ( buf , SERVICE ( snum ) , sizeof ( buf ) - 1 ) ;
buf [ sizeof ( buf ) - 1 ] = 0 ;
1996-05-04 11:50:46 +04:00
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 */
}
}
}
1998-08-14 21:38:29 +04:00
static BOOL api_WPrintDestGetInfo ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ;
1998-09-17 23:16:12 +04:00
int uLevel ;
1996-05-04 11:50:46 +04:00
struct pack_desc desc ;
int snum ;
bzero ( & desc , sizeof ( desc ) ) ;
p = skip_string ( p , 1 ) ;
uLevel = SVAL ( p , 0 ) ;
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 ) ) {
1998-08-14 21:38:29 +04:00
fill_printdest_info ( conn , snum , uLevel , & desc ) ;
1996-05-04 11:50:46 +04:00
}
* 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 ) ;
}
1998-08-14 21:38:29 +04:00
static BOOL api_WPrintDestEnum ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ) ;
1998-09-17 23:16:12 +04:00
int uLevel ;
1996-05-04 11:50:46 +04:00
int queuecnt ;
int i , n , succnt = 0 ;
struct pack_desc desc ;
int services = lp_numservices ( ) ;
bzero ( & desc , sizeof ( desc ) ) ;
uLevel = SVAL ( p , 0 ) ;
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 ) ) {
1998-08-14 21:38:29 +04:00
fill_printdest_info ( conn , i , uLevel , & desc ) ;
1996-05-04 11:50:46 +04:00
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 ) ;
}
1998-08-14 21:38:29 +04:00
static BOOL api_WPrintDriverEnum ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ) ;
1998-09-17 23:16:12 +04:00
int uLevel ;
1996-05-04 11:50:46 +04:00
int succnt ;
struct pack_desc desc ;
bzero ( & desc , sizeof ( desc ) ) ;
uLevel = SVAL ( p , 0 ) ;
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 ) ;
}
1998-08-14 21:38:29 +04:00
static BOOL api_WPrintQProcEnum ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ) ;
1998-09-17 23:16:12 +04:00
int uLevel ;
1996-05-04 11:50:46 +04:00
int succnt ;
struct pack_desc desc ;
bzero ( & desc , sizeof ( desc ) ) ;
uLevel = SVAL ( p , 0 ) ;
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 ) ;
}
1998-08-14 21:38:29 +04:00
static BOOL api_WPrintPortEnum ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ) ;
1998-09-17 23:16:12 +04:00
int uLevel ;
1996-05-04 11:50:46 +04:00
int succnt ;
struct pack_desc desc ;
bzero ( & desc , sizeof ( desc ) ) ;
uLevel = SVAL ( p , 0 ) ;
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 ) ;
}
1998-10-08 01:42:24 +04:00
static void api_rpc_trans_reply ( char * outbuf ,
1998-03-12 00:11:04 +03:00
pipes_struct * p ,
prs_struct * pd )
{
1998-10-08 01:42:24 +04:00
send_trans_reply ( outbuf , p - > rhdr . data , NULL , NULL , 0 , p - > file_offset ) ;
1998-03-12 00:11:04 +03:00
1998-10-08 01:42:24 +04:00
if ( mem_buf_len ( p - > rhdr . data ) < = p - > file_offset )
1998-03-12 00:11:04 +03:00
{
1998-10-08 01:42:24 +04:00
/* all of data was sent: no need to wait for SMBreadX calls */
mem_free_data ( p - > rhdr . data ) ;
mem_free_data ( p - > rdata . data ) ;
1998-10-20 22:27:49 +04:00
mem_free_data ( p - > rdata_i . data ) ;
1998-03-12 00:11:04 +03:00
}
}
1998-10-15 09:47:29 +04:00
/****************************************************************************
WaitNamedPipeHandleState
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL api_WNPHS ( char * outbuf , pipes_struct * p , char * param )
{
uint16 priority ;
if ( ! param ) return False ;
priority = param [ 0 ] + ( param [ 1 ] < < 8 ) ;
DEBUG ( 4 , ( " WaitNamedPipeHandleState priority %x \n " , priority ) ) ;
if ( wait_rpc_pipe_hnd_state ( p , priority ) )
{
/* now send the reply */
send_trans_reply ( outbuf , NULL , NULL , NULL , 0 , p - > file_offset ) ;
return True ;
}
return False ;
}
1998-03-12 00:11:04 +03:00
/****************************************************************************
SetNamedPipeHandleState
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL api_SNPHS ( char * outbuf , pipes_struct * p , char * param )
{
uint16 id ;
if ( ! param ) return False ;
id = param [ 0 ] + ( param [ 1 ] < < 8 ) ;
1998-10-15 09:47:29 +04:00
DEBUG ( 4 , ( " SetNamedPipeHandleState to code %x \n " , id ) ) ;
1998-03-12 00:11:04 +03:00
if ( set_rpc_pipe_hnd_state ( p , id ) )
{
/* now send the reply */
1998-04-21 06:36:37 +04:00
send_trans_reply ( outbuf , NULL , NULL , NULL , 0 , p - > file_offset ) ;
1998-03-12 00:11:04 +03:00
return True ;
}
return False ;
1996-08-15 19:11:34 +04:00
}
1998-03-12 00:11:04 +03:00
/****************************************************************************
when no reply is generated , indicate unsupported .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL api_no_reply ( char * outbuf , int max_rdata_len )
{
struct mem_buf rparam ;
mem_init ( & rparam , 0 ) ;
mem_alloc_data ( & rparam , 4 ) ;
rparam . offset . start = 0 ;
rparam . offset . end = 4 ;
/* unsupported */
SSVAL ( rparam . data , 0 , NERR_notsupported ) ;
SSVAL ( rparam . data , 2 , 0 ) ; /* converter word */
DEBUG ( 3 , ( " Unsupported API fd command \n " ) ) ;
/* now send the reply */
send_trans_reply ( outbuf , NULL , & rparam , NULL , 0 , max_rdata_len ) ;
mem_free_data ( & rparam ) ;
return ( - 1 ) ;
}
/****************************************************************************
handle remote api calls delivered to a named pipe already opened .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static int api_fd_reply ( connection_struct * conn , uint16 vuid , char * outbuf ,
1998-03-12 00:11:04 +03:00
uint16 * setup , char * data , char * params ,
int suwcnt , int tdscnt , int tpscnt , int mdrcnt , int mprcnt )
{
BOOL reply = False ;
int pnum ;
int subcommand ;
pipes_struct * p = NULL ;
prs_struct pd ;
DEBUG ( 5 , ( " api_fd_reply \n " ) ) ;
1998-10-20 22:27:49 +04:00
/* make a static data parsing structure from the api_fd_reply data */
prs_init ( & pd , 0 , 4 , True , 0 ) ;
mem_create ( pd . data , data , 0 , tdscnt , 0 , False ) ;
1998-03-12 00:11:04 +03:00
/* First find out the name of this file. */
if ( suwcnt ! = 2 )
{
DEBUG ( 0 , ( " Unexpected named pipe transaction. \n " ) ) ;
return ( - 1 ) ;
}
/* Get the file handle and hence the file name. */
pnum = setup [ 1 ] ;
subcommand = setup [ 0 ] ;
1998-08-17 07:06:20 +04:00
p = get_rpc_pipe ( pnum ) ;
1998-03-12 00:11:04 +03:00
if ( p ! = NULL )
{
DEBUG ( 3 , ( " Got API command 0x%x on pipe \" %s \" (pnum %x) " ,
subcommand , p - > name , pnum ) ) ;
/* record maximum data length that can be transmitted in an SMBtrans */
1998-04-21 06:36:37 +04:00
p - > file_offset = mdrcnt ;
1998-03-12 00:11:04 +03:00
1998-04-21 06:36:37 +04:00
DEBUG ( 10 , ( " api_fd_reply: p:%p file_offset: %d \n " ,
p , p - > file_offset ) ) ;
1998-04-10 22:21:16 +04:00
1998-03-12 00:11:04 +03:00
switch ( subcommand )
{
case 0x26 :
{
/* dce/rpc command */
1998-10-08 01:42:24 +04:00
reply = rpc_command ( p , & pd ) ;
if ( reply )
{
api_rpc_trans_reply ( outbuf , p , & pd ) ;
}
1998-03-12 00:11:04 +03:00
break ;
}
1998-10-15 09:47:29 +04:00
case 0x53 :
{
/* Wait Named Pipe Handle state */
reply = api_WNPHS ( outbuf , p , params ) ;
break ;
}
1998-03-12 00:11:04 +03:00
case 0x01 :
{
/* Set Named Pipe Handle state */
reply = api_SNPHS ( outbuf , p , params ) ;
break ;
}
}
}
else
{
DEBUG ( 1 , ( " api_fd_reply: INVALID PIPE HANDLE: %x \n " , pnum ) ) ;
}
1998-10-20 22:27:49 +04:00
mem_free_data ( pd . data ) ;
1998-03-12 00:11:04 +03:00
if ( ! reply )
{
return api_no_reply ( outbuf , mdrcnt ) ;
}
return - 1 ;
}
1996-08-15 19:11:34 +04:00
1996-05-04 11:50:46 +04:00
/****************************************************************************
the buffer was too small
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_TooSmall ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static BOOL api_Unsupported ( connection_struct * conn , uint16 vuid , char * param , char * data ,
1996-05-04 11:50:46 +04:00
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 ;
1998-08-14 21:38:29 +04:00
BOOL ( * fn ) ( connection_struct * , uint16 , char * , char * ,
int , int , char * * , char * * , int * , int * ) ;
1996-05-04 11:50:46 +04:00
int flags ;
} api_commands [ ] = {
1998-04-13 23:24:06 +04:00
{ " RNetShareEnum " , 0 , api_RNetShareEnum , 0 } ,
{ " RNetShareGetInfo " , 1 , api_RNetShareGetInfo , 0 } ,
{ " RNetServerGetInfo " , 13 , api_RNetServerGetInfo , 0 } ,
{ " RNetGroupGetUsers " , 52 , api_RNetGroupGetUsers , 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 } ,
1998-07-16 04:06:29 +04:00
{ " WPrintQueuePause " , 74 , api_WPrintQueuePurge , 0 } ,
{ " WPrintQueueResume " , 75 , api_WPrintQueuePurge , 0 } ,
1998-04-13 23:24:06 +04:00
{ " 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 } ,
{ " SamOEMChangePassword " , 214 , api_SamOEMChangePassword , 0 } ,
{ NULL , - 1 , api_Unsupported , 0 } } ;
1996-05-04 11:50:46 +04:00
/****************************************************************************
handle remote api calls
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static int api_reply ( connection_struct * conn , uint16 vuid , char * outbuf , char * data , char * params ,
1996-05-04 11:50:46 +04:00
int tdscnt , int tpscnt , int mdrcnt , int mprcnt )
{
1998-10-08 10:49:00 +04:00
int api_command ;
1998-03-12 00:11:04 +03:00
struct mem_buf rdata_buf ;
struct mem_buf rparam_buf ;
1996-05-04 11:50:46 +04:00
char * rdata = NULL ;
char * rparam = NULL ;
int rdata_len = 0 ;
int rparam_len = 0 ;
BOOL reply = False ;
int i ;
1998-10-08 10:49:00 +04:00
SMB_ASSERT ( params ! = 0 ) ;
api_command = SVAL ( params , 0 ) ;
1996-05-04 11:50:46 +04:00
DEBUG ( 3 , ( " Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d) \n " ,
1998-10-08 10:49:00 +04:00
api_command ,
params + 2 ,
skip_string ( params + 2 , 1 ) ,
1996-05-04 11:50:46 +04:00
tdscnt , tpscnt , mdrcnt , mprcnt ) ) ;
for ( i = 0 ; api_commands [ i ] . name ; i + + )
if ( api_commands [ i ] . id = = api_command & & api_commands [ i ] . fn )
{
1998-09-29 03:55:09 +04:00
DEBUG ( 3 , ( " Doing %s \n " , api_commands [ i ] . name ) ) ;
break ;
1996-05-04 11:50:46 +04:00
}
rdata = ( char * ) malloc ( 1024 ) ; if ( rdata ) bzero ( rdata , 1024 ) ;
rparam = ( char * ) malloc ( 1024 ) ; if ( rparam ) bzero ( rparam , 1024 ) ;
1998-09-29 03:55:09 +04:00
if ( ! rdata | | ! rparam ) {
DEBUG ( 0 , ( " api_reply: malloc fail ! \n " ) ) ;
return - 1 ;
}
1998-08-14 21:38:29 +04:00
reply = api_commands [ i ] . fn ( conn , vuid , params , data , mdrcnt , mprcnt ,
1996-05-04 11:50:46 +04:00
& rdata , & rparam , & rdata_len , & rparam_len ) ;
if ( rdata_len > mdrcnt | |
rparam_len > mprcnt )
{
1998-08-14 21:38:29 +04:00
reply = api_TooSmall ( conn , vuid , params , data , mdrcnt , mprcnt ,
1996-05-04 11:50:46 +04:00
& rdata , & rparam , & rdata_len , & rparam_len ) ;
}
/* if we get False back then it's actually unsupported */
if ( ! reply )
1998-08-14 21:38:29 +04:00
api_Unsupported ( conn , vuid , params , data , mdrcnt , mprcnt ,
1996-05-04 11:50:46 +04:00
& rdata , & rparam , & rdata_len , & rparam_len ) ;
1998-10-20 22:27:49 +04:00
mem_create ( & rdata_buf , rdata , 0 , rdata_len , 0 , False ) ;
mem_create ( & rparam_buf , rparam , 0 , rparam_len , 0 , False ) ;
1996-05-04 11:50:46 +04:00
/* now send the reply */
1998-03-12 00:11:04 +03:00
send_trans_reply ( outbuf , & rdata_buf , & rparam_buf , NULL , 0 , 0 ) ;
1996-05-04 11:50:46 +04:00
1998-03-12 00:11:04 +03:00
if ( rdata ) free ( rdata ) ;
if ( rparam ) free ( rparam ) ;
1996-05-04 11:50:46 +04:00
return ( - 1 ) ;
}
/****************************************************************************
handle named pipe commands
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
static int named_pipe ( connection_struct * conn , uint16 vuid , char * outbuf , char * name ,
1996-05-04 11:50:46 +04:00
uint16 * setup , char * data , char * params ,
int suwcnt , int tdscnt , int tpscnt ,
int msrcnt , int mdrcnt , int mprcnt )
{
1997-10-24 17:15:34 +04:00
DEBUG ( 3 , ( " named pipe command on <%s> name \n " , name ) ) ;
1996-05-04 11:50:46 +04:00
1997-10-22 22:37:43 +04:00
if ( strequal ( name , " LANMAN " ) )
{
1998-08-14 21:38:29 +04:00
return api_reply ( conn , vuid , outbuf , data , params , tdscnt , tpscnt , mdrcnt , mprcnt ) ;
1997-10-22 22:37:43 +04:00
}
1996-05-04 11:50:46 +04:00
1998-10-15 09:47:29 +04:00
if ( strequal ( name , " WKSSVC " ) | |
strequal ( name , " SRVSVC " ) | |
strequal ( name , " WINREG " ) | |
strequal ( name , " SAMR " ) | |
strequal ( name , " LSARPC " ) )
{
DEBUG ( 4 , ( " named pipe command from Win95 (wow!) \n " ) ) ;
return api_fd_reply ( conn , vuid , outbuf , setup , data , params , suwcnt , tdscnt , tpscnt , mdrcnt , mprcnt ) ;
}
1997-10-22 22:37:43 +04:00
if ( strlen ( name ) < 1 )
{
1998-08-14 21:38:29 +04:00
return api_fd_reply ( conn , vuid , outbuf , setup , data , params , suwcnt , tdscnt , tpscnt , mdrcnt , mprcnt ) ;
1997-10-22 22:37:43 +04:00
}
1996-08-15 19:11:34 +04:00
1997-10-22 22:37:43 +04:00
if ( setup )
{
DEBUG ( 3 , ( " unknown named pipe: setup 0x%X setup1=%d \n " , ( int ) setup [ 0 ] , ( int ) setup [ 1 ] ) ) ;
}
1996-08-15 19:11:34 +04:00
1997-10-22 22:37:43 +04:00
return 0 ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
reply to a SMBtrans
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
int reply_trans ( connection_struct * conn , char * inbuf , char * outbuf , int size , int bufsize )
{
fstring name ;
1998-10-15 04:55:17 +04:00
int name_offset = 0 ;
1998-08-14 21:38:29 +04:00
char * data = NULL , * params = NULL ;
uint16 * setup = NULL ;
int outsize = 0 ;
uint16 vuid = 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 ) ;
bzero ( name , sizeof ( name ) ) ;
fstrcpy ( name , smb_buf ( inbuf ) ) ;
if ( dscnt > tdscnt | | pscnt > tpscnt ) {
exit_server ( " invalid trans parameters \n " ) ;
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
if ( tdscnt ) {
1998-09-29 03:55:09 +04:00
if ( ( data = ( char * ) malloc ( tdscnt ) ) = = NULL ) {
1998-10-08 10:49:00 +04:00
DEBUG ( 0 , ( " reply_trans: data malloc fail for %d bytes ! \n " , tdscnt ) ) ;
return ( ERROR ( ERRDOS , ERRnomem ) ) ;
}
1998-08-14 21:38:29 +04:00
memcpy ( data , smb_base ( inbuf ) + dsoff , dscnt ) ;
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
if ( tpscnt ) {
1998-09-29 03:55:09 +04:00
if ( ( params = ( char * ) malloc ( tpscnt ) ) = = NULL ) {
1998-10-08 10:49:00 +04:00
DEBUG ( 0 , ( " reply_trans: param malloc fail for %d bytes ! \n " , tpscnt ) ) ;
return ( ERROR ( ERRDOS , ERRnomem ) ) ;
}
1998-08-14 21:38:29 +04:00
memcpy ( params , smb_base ( inbuf ) + psoff , pscnt ) ;
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
if ( suwcnt ) {
int i ;
1998-09-29 03:55:09 +04:00
if ( ( setup = ( uint16 * ) malloc ( suwcnt * sizeof ( uint16 ) ) ) = = NULL ) {
DEBUG ( 0 , ( " reply_trans: setup malloc fail for %d bytes ! \n " , suwcnt * sizeof ( uint16 ) ) ) ;
return ( ERROR ( ERRDOS , ERRnomem ) ) ;
}
1998-08-14 21:38:29 +04:00
for ( i = 0 ; i < suwcnt ; i + + )
setup [ i ] = SVAL ( inbuf , smb_vwv14 + i * SIZEOFWORD ) ;
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
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 ) ;
}
1996-06-10 09:16:19 +04:00
1998-08-14 21:38:29 +04:00
/* receive the rest of the trans packet */
while ( pscnt < tpscnt | | dscnt < tdscnt ) {
BOOL ret ;
int pcnt , poff , dcnt , doff , pdisp , ddisp ;
1996-05-04 11:50:46 +04:00
1998-09-23 05:48:45 +04:00
ret = receive_next_smb ( inbuf , bufsize , SMB_SECONDARY_WAIT ) ;
1998-08-14 21:38:29 +04:00
if ( ( ret & & ( CVAL ( inbuf , smb_com ) ! = SMBtrans ) ) | | ! ret ) {
if ( ret ) {
DEBUG ( 0 , ( " reply_trans: Invalid secondary trans packet \n " ) ) ;
} else {
DEBUG ( 0 , ( " reply_trans: %s in getting secondary trans response. \n " ,
( smb_read_error = = READ_ERROR ) ? " error " : " timeout " ) ) ;
}
if ( params ) free ( params ) ;
if ( data ) free ( data ) ;
if ( setup ) free ( setup ) ;
return ( ERROR ( ERRSRV , ERRerror ) ) ;
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
show_msg ( inbuf ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
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 ( dscnt > tdscnt | | pscnt > tpscnt ) {
exit_server ( " invalid trans parameters \n " ) ;
}
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 ) ) ;
1998-10-15 04:55:17 +04:00
/*
* WinCE wierdness . . . .
*/
if ( name [ 0 ] = = ' \\ ' & & ( StrnCaseCmp ( & name [ 1 ] , local_machine ,
strlen ( local_machine ) ) = = 0 ) ) {
name_offset = strlen ( local_machine ) + 1 ;
}
if ( strncmp ( & name [ name_offset ] , " \\ PIPE \\ " , strlen ( " \\ PIPE \\ " ) ) = = 0 ) {
1998-08-14 21:38:29 +04:00
DEBUG ( 5 , ( " calling named_pipe \n " ) ) ;
1998-10-08 10:49:00 +04:00
outsize = named_pipe ( conn , vuid , outbuf ,
1998-10-15 04:55:17 +04:00
name + name_offset + strlen ( " \\ PIPE \\ " ) , setup , data , params ,
1998-08-14 21:38:29 +04:00
suwcnt , tdscnt , tpscnt , msrcnt , mdrcnt , mprcnt ) ;
} else {
DEBUG ( 3 , ( " invalid pipe name \n " ) ) ;
outsize = 0 ;
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
if ( data ) free ( data ) ;
if ( params ) free ( params ) ;
if ( setup ) free ( setup ) ;
if ( close_on_completion )
close_cnum ( conn , vuid ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
if ( one_way )
return ( - 1 ) ;
if ( outsize = = 0 )
return ( ERROR ( ERRSRV , ERRnosupport ) ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}