extern int DEBUGLEVEL;
extern int Protocol;
extern int Client;
-extern int oplock_sock;
extern int smb_read_error;
extern int global_oplock_break;
extern int chain_size;
"\\ntsvcs",
"\\lsass",
"\\lsarpc",
+ "\\winreg",
NULL
};
return 0;
}
+/****************************************************************************
+ (Hopefully) temporary call to fix bugs in NT5.0beta2. This OS sends unicode
+ strings in NT calls AND DOESN'T SET THE UNICODE BIT !!!!!!!
+****************************************************************************/
+
+static void my_wcstombs(char *dst, uint16 *src, size_t len)
+{
+ size_t i;
+
+ for(i = 0; i < len; i++)
+ dst[i] = (char)SVAL(src,i*2);
+}
+
+static void get_filename( char *fname, char *inbuf, int data_offset, int data_len, int fname_len)
+{
+ if(data_len - fname_len > 1) {
+ /*
+ * NT 5.0 Beta 2 has kindly sent us a UNICODE string
+ * without bothering to set the unicode bit. How kind.
+ *
+ * Firstly - ensure that the data offset is aligned
+ * on a 2 byte boundary - add one if not.
+ */
+ fname_len = fname_len/2;
+ if(data_offset & 1)
+ data_offset++;
+ my_wcstombs( fname, (uint16 *)(inbuf+data_offset), fname_len);
+ } else {
+ StrnCpy(fname,inbuf+data_offset,fname_len);
+ }
+ fname[fname_len] = '\0';
+}
+
/****************************************************************************
Save case statics.
****************************************************************************/
static int map_create_disposition( uint32 create_disposition)
{
+ int ret;
+
switch( create_disposition ) {
case FILE_CREATE:
/* create if not exist, fail if exist */
- return 0x10;
+ ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL);
+ break;
case FILE_SUPERSEDE:
case FILE_OVERWRITE_IF:
/* create if not exist, trunc if exist */
- return 0x12;
+ ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE);
+ break;
case FILE_OPEN:
/* fail if not exist, open if exists */
- return 0x1;
+ ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN);
+ break;
case FILE_OPEN_IF:
/* create if not exist, open if exists */
- return 0x11;
+ ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_OPEN);
+ break;
case FILE_OVERWRITE:
/* fail if not exist, truncate if exists */
- return 0x2;
+ ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE);
+ break;
default:
DEBUG(0,("map_create_disposition: Incorrect value for create_disposition = %d\n",
create_disposition ));
return -1;
}
+
+ DEBUG(10,("map_create_disposition: Mapped create_disposition %lx to %x\n",
+ (unsigned long)create_disposition, ret ));
+
+ return ret;
}
/****************************************************************************
Utility function to map share modes.
****************************************************************************/
-static int map_share_mode( uint32 desired_access, uint32 share_access, uint32 file_attributes)
+static int map_share_mode( char *fname, uint32 desired_access, uint32 share_access, uint32 file_attributes)
{
int smb_open_mode = -1;
switch( desired_access & (FILE_READ_DATA|FILE_WRITE_DATA) ) {
case FILE_READ_DATA:
- smb_open_mode = 0;
+ smb_open_mode = DOS_OPEN_RDONLY;
break;
case FILE_WRITE_DATA:
- smb_open_mode = 1;
+ smb_open_mode = DOS_OPEN_WRONLY;
break;
case FILE_READ_DATA|FILE_WRITE_DATA:
- smb_open_mode = 2;
+ smb_open_mode = DOS_OPEN_RDWR;
break;
}
+ /*
+ * NB. For DELETE_ACCESS we should really check the
+ * directory permissions, as that is what controls
+ * delete, and for WRITE_DAC_ACCESS we should really
+ * check the ownership, as that is what controls the
+ * chmod. Note that this is *NOT* a security hole (this
+ * note is for you, Andrew) as we are not *allowing*
+ * the access at this point, the actual unlink or
+ * chown or chmod call would do this. We are just helping
+ * clients out by telling them if they have a hope
+ * of any of this succeeding. POSIX acls may still
+ * deny the real call. JRA.
+ */
+
if (smb_open_mode == -1) {
- if(desired_access & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES))
- smb_open_mode = 2;
- else if( desired_access & FILE_EXECUTE)
- smb_open_mode = 0;
+ if(desired_access & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|
+ FILE_EXECUTE|FILE_READ_ATTRIBUTES|
+ FILE_WRITE_ATTRIBUTES|READ_CONTROL_ACCESS))
+ smb_open_mode = DOS_OPEN_RDONLY;
else {
- DEBUG(0,("map_share_mode: Incorrect value for desired_access = %x\n",
- desired_access));
+ DEBUG(0,("map_share_mode: Incorrect value %lx for desired_access to file %s\n",
+ (unsigned long)desired_access, fname));
return -1;
}
}
- /* Add in the requested share mode - ignore FILE_SHARE_DELETE for now. */
+ /*
+ * Set the special bit that means allow share delete.
+ * This is held outside the normal share mode bits at 1<<15.
+ * JRA.
+ */
+
+ if(share_access & FILE_SHARE_DELETE)
+ smb_open_mode |= ALLOW_SHARE_DELETE;
+
+ /* Add in the requested share mode. */
switch( share_access & (FILE_SHARE_READ|FILE_SHARE_WRITE)) {
case FILE_SHARE_READ:
- smb_open_mode |= (DENY_WRITE<<4);
+ smb_open_mode |= SET_DENY_MODE(DENY_WRITE);
break;
case FILE_SHARE_WRITE:
- smb_open_mode |= (DENY_READ<<4);
+ smb_open_mode |= SET_DENY_MODE(DENY_READ);
break;
case (FILE_SHARE_READ|FILE_SHARE_WRITE):
- smb_open_mode |= (DENY_NONE<<4);
+ smb_open_mode |= SET_DENY_MODE(DENY_NONE);
break;
case FILE_SHARE_NONE:
- smb_open_mode |= (DENY_ALL<<4);
+ smb_open_mode |= SET_DENY_MODE(DENY_ALL);
break;
}
/*
- * Handle a O_SYNC request.
+ * Handle an O_SYNC request.
*/
+
if(file_attributes & FILE_FLAG_WRITE_THROUGH)
- smb_open_mode |= (1<<14);
+ smb_open_mode |= FILE_SYNC_OPENMODE;
+ DEBUG(10,("map_share_mode: Mapped desired access %lx, share access %lx, file attributes %lx \
+to open_mode %x\n", (unsigned long)desired_access, (unsigned long)share_access,
+ (unsigned long)file_attributes, smb_open_mode ));
+
return smb_open_mode;
}
+/*
+ * This is a *disgusting* hack.
+ * This is *so* bad that even I'm embarrassed (and I
+ * have no shame). Here's the deal :
+ * Until we get the correct SPOOLSS code into smbd
+ * then when we're running with NT SMB support then
+ * NT makes this call with a level of zero, and then
+ * immediately follows it with an open request to
+ * the \\SRVSVC pipe. If we allow that open to
+ * succeed then NT barfs when it cannot open the
+ * \\SPOOLSS pipe immediately after and continually
+ * whines saying "Printer name is invalid" forever
+ * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
+ * to fail, then NT downgrades to using the downlevel code
+ * and everything works as well as before. I hate
+ * myself for adding this code.... JRA.
+ *
+ * The HACK_FAIL_TIME define allows only a 2
+ * second window for this to occur, just in
+ * case...
+ */
+
+static BOOL fail_next_srvsvc = False;
+static time_t fail_time;
+#define HACK_FAIL_TIME 2 /* In seconds. */
+
+void fail_next_srvsvc_open(void)
+{
+ fail_next_srvsvc = True;
+ fail_time = time(NULL);
+ DEBUG(10,("fail_next_srvsvc_open: setting up timeout close of \\srvsvc pipe for print fix.\n"));
+}
+
/****************************************************************************
Reply to an NT create and X call on a pipe.
****************************************************************************/
if( strequal(fname,known_nt_pipes[i]))
break;
+ /*
+ * HACK alert.... see above - JRA.
+ */
+
+ if(fail_next_srvsvc && (time(NULL) > fail_time + HACK_FAIL_TIME)) {
+ fail_next_srvsvc = False;
+ fail_time = (time_t)0;
+ DEBUG(10,("nt_open_pipe: End of timeout close of \\srvsvc pipe for print fix.\n"));
+ }
+
+ if(fail_next_srvsvc && strequal(fname, "\\srvsvc")) {
+ fail_next_srvsvc = False;
+ DEBUG(10,("nt_open_pipe: Deliberately failing open of \\srvsvc pipe for print fix.\n"));
+ return(ERROR(ERRSRV,ERRaccess));
+ }
+
+ /*
+ * End hack alert.... see above - JRA.
+ */
+
if ( known_nt_pipes[i] == NULL )
return(ERROR(ERRSRV,ERRaccess));
/****************************************************************************
Reply to an NT create and X call.
****************************************************************************/
+
int reply_ntcreate_and_X(connection_struct *conn,
char *inbuf,char *outbuf,int length,int bufsize)
{
uint32 file_attributes = IVAL(inbuf,smb_ntcreate_FileAttributes);
uint32 share_access = IVAL(inbuf,smb_ntcreate_ShareAccess);
uint32 create_disposition = IVAL(inbuf,smb_ntcreate_CreateDisposition);
+ uint32 create_options = IVAL(inbuf,smb_ntcreate_CreateOptions);
uint32 fname_len = MIN(((uint32)SVAL(inbuf,smb_ntcreate_NameLength)),
((uint32)sizeof(fname)-1));
+ uint16 root_dir_fid = (uint16)IVAL(inbuf,smb_ntcreate_RootDirectoryFid);
int smb_ofun;
int smb_open_mode;
int smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK);
/* Breakout the oplock request bits so we can set the
reply bits separately. */
int oplock_request = 0;
- int unixmode, pnum = -1;
- int fmode=0,mtime=0,rmode=0;
+ mode_t unixmode;
+ int pnum = -1;
+ int fmode=0,rmode=0;
SMB_OFF_T file_len = 0;
SMB_STRUCT_STAT sbuf;
int smb_action = 0;
if((smb_ofun = map_create_disposition( create_disposition )) == -1)
return(ERROR(ERRDOS,ERRbadaccess));
- /*
- * Now contruct the smb_open_mode value from the desired access
- * and the share access.
- */
-
- if((smb_open_mode = map_share_mode(desired_access,
- share_access,
- file_attributes)) == -1) {
- return(ERROR(ERRDOS,ERRbadaccess));
- }
-
/*
* Get the file name.
*/
- StrnCpy(fname,smb_buf(inbuf),fname_len);
- fname[fname_len] = '\0';
+
+ if(root_dir_fid != 0) {
+ /*
+ * This filename is relative to a directory fid.
+ */
+ files_struct *dir_fsp = file_fsp(inbuf,smb_ntcreate_RootDirectoryFid);
+ size_t dir_name_len;
+
+ if(!dir_fsp || !dir_fsp->is_directory)
+ return(ERROR(ERRDOS,ERRbadfid));
+
+ /*
+ * Copy in the base directory name.
+ */
+
+ pstrcpy( fname, dir_fsp->fsp_name );
+ dir_name_len = strlen(fname);
+
+ /*
+ * Ensure it ends in a '\'.
+ */
+
+ if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
+ pstrcat(fname, "\\");
+ dir_name_len++;
+ }
+
+ if(fname_len + dir_name_len >= sizeof(pstring))
+ return(ERROR(ERRSRV,ERRfilespecs));
+
+ get_filename(&fname[dir_name_len], inbuf, smb_buf(inbuf)-inbuf,
+ smb_buflen(inbuf),fname_len);
+#if 0
+ StrnCpy(&fname[dir_name_len], smb_buf(inbuf),fname_len);
+ fname[dir_name_len+fname_len] = '\0';
+#endif
+
+ } else {
+
+ get_filename(fname, inbuf, smb_buf(inbuf)-inbuf,
+ smb_buflen(inbuf),fname_len);
+
+#if 0
+ StrnCpy(fname,smb_buf(inbuf),fname_len);
+ fname[fname_len] = '\0';
+#endif
+ }
/* If it's an IPC, use the pipe handler. */
- if (IS_IPC(conn)) {
-
+ if (IS_IPC(conn) && lp_nt_pipe_support() && lp_security() != SEC_SHARE)
+ {
int ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum);
if(ret != 0)
return ret;
return chain_reply(inbuf,outbuf,length,bufsize);
}
+ /*
+ * Now contruct the smb_open_mode value from the filename,
+ * desired access and the share access.
+ */
+
+ if((smb_open_mode = map_share_mode(fname, desired_access,
+ share_access,
+ file_attributes)) == -1) {
+ return(ERROR(ERRDOS,ERRbadaccess));
+ }
+
/*
* Ordinary file or directory.
*/
* If it's a request for a directory open, deal with it separately.
*/
- if(flags & OPEN_DIRECTORY) {
+ if(create_options & FILE_DIRECTORY_FILE) {
oplock_request = 0;
open_directory(fsp, conn, fname, smb_ofun,
fmode = dos_mode(conn,fname,&sbuf);
if(fmode == 0)
fmode = FILE_ATTRIBUTE_NORMAL;
- mtime = sbuf.st_mtime;
if (!fsp->is_directory && (fmode & aDIR)) {
close_file(fsp,False);
return(ERROR(ERRDOS,ERRnoaccess));
put_long_date(p,sbuf.st_mtime); /* change time */
p += 8;
SIVAL(p,0,fmode); /* File Attributes. */
- p += 12;
-#ifdef LARGE_SMB_OFF_T
- SIVAL(p,0, file_len & 0xFFFFFFFF);
- SIVAL(p,4, file_len >> 32);
-#else /* LARGE_SMB_OFF_T */
- SIVAL(p,0,file_len);
-#endif /* LARGE_SMB_OFF_T */
+ p += 4;
+ SOFF_T(p, 0, file_len);
+ p += 8;
+ SOFF_T(p,0,file_len);
p += 12;
SCVAL(p,0,fsp->is_directory ? 1 : 0);
uint32 file_attributes = IVAL(params,20);
uint32 share_access = IVAL(params,24);
uint32 create_disposition = IVAL(params,28);
+ uint32 create_options = IVAL(params,32);
uint32 fname_len = MIN(((uint32)IVAL(params,44)),
((uint32)sizeof(fname)-1));
+ uint16 root_dir_fid = (uint16)IVAL(params,4);
int smb_ofun;
int smb_open_mode;
int smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK);
/* Breakout the oplock request bits so we can set the
reply bits separately. */
int oplock_request = 0;
- int unixmode, pnum = -1;
- int fmode=0,mtime=0,rmode=0;
- off_t file_len = 0;
+ mode_t unixmode;
+ int pnum = -1;
+ int fmode=0,rmode=0;
+ SMB_OFF_T file_len = 0;
SMB_STRUCT_STAT sbuf;
int smb_action = 0;
BOOL bad_path = False;
return(ERROR(ERRDOS,ERRbadaccess));
/*
- * Now contruct the smb_open_mode value from the desired access
- * and the share access.
+ * Get the file name.
*/
- if((smb_open_mode = map_share_mode( desired_access, share_access, file_attributes)) == -1)
- return(ERROR(ERRDOS,ERRbadaccess));
+ if(root_dir_fid != 0) {
+ /*
+ * This filename is relative to a directory fid.
+ */
- /*
- * Get the file name.
- */
+ files_struct *dir_fsp = file_fsp(params,4);
+ size_t dir_name_len;
- StrnCpy(fname,params+53,fname_len);
- fname[fname_len] = '\0';
+ if(!dir_fsp || !dir_fsp->is_directory)
+ return(ERROR(ERRDOS,ERRbadfid));
+
+ /*
+ * Copy in the base directory name.
+ */
+
+ pstrcpy( fname, dir_fsp->fsp_name );
+ dir_name_len = strlen(fname);
+
+ /*
+ * Ensure it ends in a '\'.
+ */
+
+ if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) {
+ pstrcat(fname, "\\");
+ dir_name_len++;
+ }
+
+ if(fname_len + dir_name_len >= sizeof(pstring))
+ return(ERROR(ERRSRV,ERRfilespecs));
+
+ StrnCpy(&fname[dir_name_len], params+53, fname_len);
+ fname[dir_name_len+fname_len] = '\0';
+
+ } else {
+ StrnCpy(fname,params+53,fname_len);
+ fname[fname_len] = '\0';
+ }
/* If it's an IPC, use the pipe handler. */
if (IS_IPC(conn)) {
oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+ /*
+ * Now contruct the smb_open_mode value from the desired access
+ * and the share access.
+ */
+
+ if((smb_open_mode = map_share_mode( fname, desired_access, share_access, file_attributes)) == -1)
+ return(ERROR(ERRDOS,ERRbadaccess));
+
/*
* If it's a request for a directory open, deal with it separately.
*/
- if(flags & OPEN_DIRECTORY) {
+ if(create_options & FILE_DIRECTORY_FILE) {
oplock_request = 0;
fmode = dos_mode(conn,fname,&sbuf);
if(fmode == 0)
fmode = FILE_ATTRIBUTE_NORMAL;
- mtime = sbuf.st_mtime;
if (fmode & aDIR) {
close_file(fsp,False);
put_long_date(p,sbuf.st_mtime); /* change time */
p += 8;
SIVAL(p,0,fmode); /* File Attributes. */
- p += 12;
-#ifdef LARGE_SMB_OFF_T
- SIVAL(p,0, file_len & 0xFFFFFFFF);
- SIVAL(p,4, (file_len >> 32));
-#else /* LARGE_SMB_OFF_T */
- SIVAL(p,0,file_len);
-#endif /* LARGE_SMB_OFF_T */
+ p += 4;
+ SOFF_T(p,0,file_len);
+ p += 8;
+ SOFF_T(p,0,file_len);
}
/* Send the required number of replies */
int bufsize,
char **ppsetup, char **ppparams, char **ppdata)
{
- DEBUG(0,("call_nt_transact_query_security_desc: Currently not implemented.\n"));
+ static BOOL logged_message = False;
+
+ if(!logged_message) {
+ DEBUG(0,("call_nt_transact_query_security_desc: Currently not implemented.\n"));
+ logged_message = True; /* Only print this once... */
+ }
+
return(ERROR(ERRSRV,ERRnosupport));
}
char **ppsetup,
char **ppparams, char **ppdata)
{
- DEBUG(0,("call_nt_transact_set_security_desc: Currently not implemented.\n"));
- return(ERROR(ERRSRV,ERRnosupport));
+ static BOOL logged_message = False;
+
+ if(!logged_message) {
+ DEBUG(0,("call_nt_transact_set_security_desc: Currently not implemented.\n"));
+ logged_message = True; /* Only print this once... */
+ }
+ return(ERROR(ERRSRV,ERRnosupport));
}
/****************************************************************************
int bufsize,
char **ppsetup, char **ppparams, char **ppdata)
{
- DEBUG(0,("call_nt_transact_ioctl: Currently not implemented.\n"));
- return(ERROR(ERRSRV,ERRnosupport));
+ static BOOL logged_message = False;
+
+ if(!logged_message) {
+ DEBUG(0,("call_nt_transact_ioctl: Currently not implemented.\n"));
+ logged_message = True; /* Only print this once... */
+ }
+ return(ERROR(ERRSRV,ERRnosupport));
}
/****************************************************************************
while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
BOOL ret;
- ret = receive_next_smb(Client,oplock_sock,inbuf,bufsize,
- SMB_SECONDARY_WAIT);
+ ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) {
outsize = set_message(outbuf,0,0,True);