summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/blocking.c55
-rw-r--r--source3/smbd/chgpasswd.c277
-rw-r--r--source3/smbd/close.c92
-rw-r--r--source3/smbd/connection.c14
-rw-r--r--source3/smbd/dfree.c36
-rw-r--r--source3/smbd/dir.c643
-rw-r--r--source3/smbd/dosmode.c25
-rw-r--r--source3/smbd/fileio.c567
-rw-r--r--source3/smbd/filename.c68
-rw-r--r--source3/smbd/files.c18
-rw-r--r--source3/smbd/groupname.c223
-rw-r--r--source3/smbd/ipc.c493
-rw-r--r--source3/smbd/mangle.c101
-rw-r--r--source3/smbd/message.c20
-rw-r--r--source3/smbd/negprot.c95
-rw-r--r--source3/smbd/nttrans.c1217
-rw-r--r--source3/smbd/open.c386
-rw-r--r--source3/smbd/oplock.c664
-rw-r--r--source3/smbd/password.c1042
-rw-r--r--source3/smbd/pipes.c64
-rw-r--r--source3/smbd/predict.c14
-rw-r--r--source3/smbd/process.c501
-rw-r--r--source3/smbd/quotas.c111
-rw-r--r--source3/smbd/reply.c1829
-rw-r--r--source3/smbd/server.c324
-rw-r--r--source3/smbd/service.c262
-rw-r--r--source3/smbd/ssl.c12
-rw-r--r--source3/smbd/trans2.c1034
-rw-r--r--source3/smbd/uid.c434
29 files changed, 6978 insertions, 3643 deletions
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
index 32b6d010a4..16882be2bb 100644
--- a/source3/smbd/blocking.c
+++ b/source3/smbd/blocking.c
@@ -211,18 +211,16 @@ static void reply_lockingX_error(blocking_lock_record *blr, int eclass, int32 ec
for(i = blr->lock_num; i >= 0; i--) {
int dummy1;
uint32 dummy2;
- if(!large_file_format) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- }
-#ifdef LARGE_SMB_OFF_T
- else {
- count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
- offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
- }
-#endif /* LARGE_SMB_OFF_T */
+ BOOL err;
+
+ count = get_lock_count( data, i, large_file_format, &err);
+ offset = get_lock_offset( data, i, large_file_format, &err);
+
+ /*
+ * We know err cannot be set as if it was the lock
+ * request would never have been queued. JRA.
+ */
+
do_unlock(fsp,conn,count,offset,&dummy1,&dummy2);
}
@@ -313,7 +311,7 @@ static BOOL process_lockread(blocking_lock_record *blr)
SSVAL(smb_buf(outbuf),1,nread);
DEBUG(3, ( "process_lockread file = %s, fnum=%d num=%d nread=%d\n",
- fsp->fsp_name, fsp->fnum, numtoread, nread ) );
+ fsp->fsp_name, fsp->fnum, (int)numtoread, (int)nread ) );
send_blocking_reply(outbuf,outsize);
return True;
@@ -401,18 +399,15 @@ static BOOL process_lockingX(blocking_lock_record *blr)
*/
for(; blr->lock_num < num_locks; blr->lock_num++) {
- if(!large_file_format) {
- count = IVAL(data,SMB_LKLEN_OFFSET(blr->lock_num));
- offset = IVAL(data,SMB_LKOFF_OFFSET(blr->lock_num));
- }
-#ifdef LARGE_SMB_OFF_T
- else {
- count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(blr->lock_num))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(blr->lock_num)));
- offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(blr->lock_num))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(blr->lock_num)));
- }
-#endif /* LARGE_SMB_OFF_T */
+ BOOL err;
+
+ count = get_lock_count( data, blr->lock_num, large_file_format, &err);
+ offset = get_lock_offset( data, blr->lock_num, large_file_format, &err);
+
+ /*
+ * We know err cannot be set as if it was the lock
+ * request would never have been queued. JRA.
+ */
errno = 0;
if(!do_lock(fsp,conn,count,offset, ((locktype & 1) ? F_RDLCK : F_WRLCK),
&eclass, &ecode))
@@ -527,6 +522,16 @@ file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
}
/****************************************************************************
+ Return True if the blocking lock queue has entries.
+*****************************************************************************/
+
+BOOL blocking_locks_pending(void)
+{
+ blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue );
+ return (blr == NULL ? False : True);
+}
+
+/****************************************************************************
Process the blocking lock queue. Note that this is only called as root.
*****************************************************************************/
diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c
index 3d31db7fb5..b86091e773 100644
--- a/source3/smbd/chgpasswd.c
+++ b/source3/smbd/chgpasswd.c
@@ -52,24 +52,20 @@
extern int DEBUGLEVEL;
#if ALLOW_CHANGE_PASSWORD
-#define MINPASSWDLENGTH 5
-#define BUFSIZE 512
static int findpty(char **slave)
{
int master;
-#ifndef HAVE_GRANTPT
static fstring line;
- DIR *dirp;
- struct dirent *dentry;
+ void *dirp;
char *dpname;
-#endif /* !HAVE_GRANTPT */
#if defined(HAVE_GRANTPT)
- if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 1) {
+ /* Try to open /dev/ptmx. If that fails, fall through to old method. */
+ if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0) {
grantpt(master);
unlockpt(master);
- *slave = ptsname(master);
+ *slave = (char *)ptsname(master);
if (*slave == NULL) {
DEBUG(0,("findpty: Unable to create master/slave pty pair.\n"));
/* Stop fd leak on error. */
@@ -80,14 +76,14 @@ static int findpty(char **slave)
return (master);
}
}
-#else /* HAVE_GRANTPT */
+#endif /* HAVE_GRANTPT */
+
fstrcpy( line, "/dev/ptyXX" );
- dirp = opendir("/dev");
+ dirp = OpenDir(NULL, "/dev", False);
if (!dirp)
return(-1);
- while ((dentry = readdir(dirp)) != NULL) {
- dpname = dentry->d_name;
+ while ((dpname = ReadDirName(dirp)) != NULL) {
if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
DEBUG(3,("pty: try to open %s, line was %s\n", dpname, line ) );
line[8] = dpname[3];
@@ -96,13 +92,12 @@ static int findpty(char **slave)
DEBUG(3,("pty: opened %s\n", line ) );
line[5] = 't';
*slave = line;
- closedir(dirp);
+ CloseDir(dirp);
return (master);
}
}
}
- closedir(dirp);
-#endif /* HAVE_GRANTPT */
+ CloseDir(dirp);
return (-1);
}
@@ -110,9 +105,9 @@ static int dochild(int master,char *slavedev, char *name, char *passwordprogram,
{
int slave;
struct termios stermios;
- const struct passwd *pass = Get_Pwnam(name,True);
- int gid;
- int uid;
+ struct passwd *pass = Get_Pwnam(name,True);
+ gid_t gid;
+ uid_t uid;
if (pass == NULL) {
DEBUG(0,("dochild: user name %s doesn't exist in the UNIX password database.\n",
@@ -122,11 +117,8 @@ static int dochild(int master,char *slavedev, char *name, char *passwordprogram,
gid = pass->pw_gid;
uid = pass->pw_uid;
-#ifdef HAVE_SETRESUID
- setresuid(0,0,0);
-#else
- setuid(0);
-#endif
+
+ gain_root_privilege();
/* Start new session - gets rid of controlling terminal. */
if (setsid() < 0) {
@@ -186,19 +178,7 @@ static int dochild(int master,char *slavedev, char *name, char *passwordprogram,
/* make us completely into the right uid */
if (!as_root) {
-#ifdef HAVE_SETRESUID
- setresgid(0,0,0);
- setresuid(0,0,0);
- setresgid(gid,gid,gid);
- setresuid(uid,uid,uid);
-#else
- setuid(0);
- seteuid(0);
- setgid(gid);
- setegid(gid);
- setuid(uid);
- seteuid(uid);
-#endif
+ become_user_permanently(uid, gid);
}
DEBUG(10, ("Invoking '%s' as password change program.\n", passwordprogram));
@@ -211,92 +191,91 @@ static int dochild(int master,char *slavedev, char *name, char *passwordprogram,
return(True);
}
-static int expect(int master,char *expected,char *buf)
+static int expect(int master, char *issue, char *expected)
{
- int n, m;
-
- n = 0;
- buf[0] = 0;
- while (1) {
- if (n >= BUFSIZE-1) {
- return False;
- }
+ pstring buffer;
+ int attempts, timeout, nread, len;
+ BOOL match = False;
- /* allow 4 seconds for some output to appear */
- m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000);
- if (m < 0)
- return False;
+ for (attempts = 0; attempts < 2; attempts++)
+ {
+ if (!strequal(issue, "."))
+ {
+ if (lp_passwd_chat_debug())
+ DEBUG(100, ("expect: sending [%s]\n", issue));
- n += m;
- buf[n] = 0;
+ write(master, issue, strlen(issue));
+ }
- {
- pstring s1,s2;
- pstrcpy(s1,buf);
- pstrcpy(s2,expected);
- if (do_match(s1, s2, False))
- return(True);
- }
- }
+ if (strequal(expected, "."))
+ return True;
+
+ timeout = 2000;
+ nread = 0;
+ buffer[nread] = 0;
+
+ while ((len = read_with_timeout(master, buffer + nread, 1,
+ sizeof(buffer) - nread - 1, timeout)) > 0)
+ {
+ nread += len;
+ buffer[nread] = 0;
+
+ if ((match = unix_do_match(buffer, expected, False)))
+ timeout = 200;
+ }
+
+ if (lp_passwd_chat_debug())
+ DEBUG(100, ("expect: expected [%s] received [%s]\n",
+ expected, buffer));
+
+ if (match)
+ break;
+
+ if (len < 0)
+ {
+ DEBUG(2, ("expect: %s\n", strerror(errno)));
+ return False;
+ }
+ }
+
+ return match;
}
static void pwd_sub(char *buf)
{
- string_sub(buf,"\\n","\n");
- string_sub(buf,"\\r","\r");
- string_sub(buf,"\\s"," ");
- string_sub(buf,"\\t","\t");
+ all_string_sub(buf,"\\n","\n",0);
+ all_string_sub(buf,"\\r","\r",0);
+ all_string_sub(buf,"\\s"," ",0);
+ all_string_sub(buf,"\\t","\t",0);
}
-static void writestring(int fd,char *s)
+static int talktochild(int master, char *seq)
{
- int l;
-
- l = strlen (s);
- write (fd, s, l);
-}
+ int count = 0;
+ fstring issue, expected;
+ fstrcpy(issue, ".");
-static int talktochild(int master, char *chatsequence)
-{
- char buf[BUFSIZE];
- int count=0;
- char *ptr=chatsequence;
- fstring chatbuf;
-
- *buf = 0;
- sleep(1);
-
- while (next_token(&ptr,chatbuf,NULL,sizeof(chatbuf))) {
- BOOL ok=True;
- count++;
- pwd_sub(chatbuf);
- if (!strequal(chatbuf,"."))
- ok = expect(master,chatbuf,buf);
-
- if (lp_passwd_chat_debug())
- DEBUG(100,("talktochild: chatbuf=[%s] responsebuf=[%s]\n",chatbuf,buf));
-
- if (!ok) {
- DEBUG(3,("response %d incorrect\n",count));
- return(False);
- }
+ while (next_token(&seq, expected, NULL, sizeof(expected)))
+ {
+ pwd_sub(expected);
+ count++;
- if (!next_token(&ptr,chatbuf,NULL,sizeof(chatbuf))) break;
- pwd_sub(chatbuf);
- if (!strequal(chatbuf,"."))
- writestring(master,chatbuf);
+ if (!expect(master, issue, expected))
+ {
+ DEBUG(3,("Response %d incorrect\n", count));
+ return False;
+ }
- if (lp_passwd_chat_debug())
- DEBUG(100,("talktochild: sendbuf=[%s]\n",chatbuf));
- }
+ if (!next_token(&seq, issue, NULL, sizeof(issue)))
+ fstrcpy(issue, ".");
- if (count<1) return(False);
+ pwd_sub(issue);
+ }
- return (True);
+ return (count > 0);
}
-
static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence, BOOL as_root)
{
char *slavedev;
@@ -311,9 +290,17 @@ static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequenc
return(False);
}
+ /*
+ * We need to temporarily stop CatchChild from eating
+ * SIGCLD signals as it also eats the exit status code. JRA.
+ */
+
+ CatchChildLeaveStatus();
+
if ((pid = fork()) < 0) {
DEBUG(3,("Cannot fork() child for password change: %s\n",name));
close(master);
+ CatchChild();
return(False);
}
@@ -324,12 +311,26 @@ static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequenc
kill(pid, SIGKILL); /* be sure to end this process */
}
- if ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
+ while((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
+ if(errno == EINTR) {
+ errno = 0;
+ continue;
+ }
+ break;
+ }
+
+ if (wpid < 0) {
DEBUG(3,("The process is no longer waiting!\n\n"));
close(master);
+ CatchChild();
return(False);
}
+ /*
+ * Go back to ignoring children.
+ */
+ CatchChild();
+
close(master);
if (pid != wpid) {
@@ -362,8 +363,12 @@ static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequenc
DEBUG(3,("Dochild for user %s (uid=%d,gid=%d)\n",name,(int)getuid(),(int)getgid()));
chstat = dochild(master, slavedev, name, passwordprogram, as_root);
- if (as_root)
- unbecome_root(False);
+ /*
+ * The child should never return from dochild() ....
+ */
+
+ DEBUG(0,("chat_with_program: Error: dochild() returned %d\n", chstat ));
+ exit(1);
}
if (chstat)
@@ -376,8 +381,8 @@ BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root)
{
pstring passwordprogram;
pstring chatsequence;
- int i;
- int len;
+ size_t i;
+ size_t len;
strlower(name);
DEBUG(3,("Password change for user: %s\n",name));
@@ -388,9 +393,10 @@ BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root)
/* Take the passed information and test it for minimum criteria */
/* Minimum password length */
- if (strlen(newpass) < MINPASSWDLENGTH) /* too short, must be at least MINPASSWDLENGTH */
+ if (strlen(newpass) < lp_min_passwd_length()) /* too short, must be at least MINPASSWDLENGTH */
{
- DEBUG(2,("Password Change: %s, New password is shorter than MINPASSWDLENGTH\n",name));
+ DEBUG(0,("Password Change: user %s, New password is shorter than minimum password length = %d\n",
+ name, lp_min_passwd_length()));
return (False); /* inform the user */
}
@@ -435,13 +441,14 @@ BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root)
}
}
- string_sub(passwordprogram,"%u",name);
- all_string_sub(passwordprogram,"%o",oldpass);
- all_string_sub(passwordprogram,"%n",newpass);
+ pstring_sub(passwordprogram,"%u",name);
+ /* note that we do NOT substitute the %o and %n in the password program
+ as this would open up a security hole where the user could use
+ a new password containing shell escape characters */
- string_sub(chatsequence,"%u",name);
- all_string_sub(chatsequence,"%o",oldpass);
- all_string_sub(chatsequence,"%n",newpass);
+ pstring_sub(chatsequence,"%u",name);
+ all_string_sub(chatsequence,"%o",oldpass,sizeof(pstring));
+ all_string_sub(chatsequence,"%n",newpass,sizeof(pstring));
return(chat_with_program(passwordprogram,name,chatsequence, as_root));
}
@@ -531,7 +538,7 @@ BOOL change_lanman_password(struct smb_passwd *smbpw, uchar *pass1, uchar *pass2
if (smbpw->acct_ctrl & ACB_DISABLED)
{
- DEBUG(0,("change_lanman_password: account %s disabled.\n", smbpw->unix_name));
+ DEBUG(0,("change_lanman_password: account %s disabled.\n", smbpw->smb_name));
return False;
}
@@ -573,14 +580,6 @@ BOOL pass_oem_change(char *user,
&sampw,
new_passwd, sizeof(new_passwd));
- /* now we check to see if we are actually allowed to change the
- password. */
-
- if (ret && (sampw->acct_ctrl & ACB_PWLOCK))
- {
- ret = False;
- }
-
/*
* At this point we have the new case-sensitive plaintext
* password in the fstring new_passwd. If we wanted to synchronise
@@ -621,12 +620,12 @@ BOOL check_oem_password(char *user,
static uchar null_pw[16];
static uchar null_ntpw[16];
struct smb_passwd *smbpw = NULL;
+ int new_pw_len;
uchar new_ntp16[16];
uchar unenc_old_ntpw[16];
uchar new_p16[16];
uchar unenc_old_pw[16];
char no_pw[2];
- uint32 len;
BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
@@ -683,11 +682,35 @@ BOOL check_oem_password(char *user,
*/
SamOEMhash( (uchar *)lmdata, (uchar *)smbpw->smb_passwd, True);
- if (!decode_pw_buffer(lmdata, new_passwd, new_passwd_size, &len))
+ /*
+ * The length of the new password is in the last 4 bytes of
+ * the data buffer.
+ */
+
+ new_pw_len = IVAL(lmdata, 512);
+ if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1)
{
+ DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len));
return False;
}
+ if (nt_pass_set)
+ {
+ /*
+ * nt passwords are in unicode
+ */
+ int uni_pw_len = new_pw_len;
+ char *pw;
+ new_pw_len /= 2;
+ pw = dos_unistrn2((uint16*)(&lmdata[512-uni_pw_len]), new_pw_len);
+ memcpy(new_passwd, pw, new_pw_len+1);
+ }
+ else
+ {
+ memcpy(new_passwd, &lmdata[512-new_pw_len], new_pw_len);
+ new_passwd[new_pw_len] = '\0';
+ }
+
/*
* To ensure we got the correct new password, hash it and
* use it as a key to test the passed old password.
diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index c37c2ceab2..d06cb3b5bb 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -23,9 +23,6 @@
extern int DEBUGLEVEL;
-extern int32 global_oplocks_open;
-
-
/****************************************************************************
run a file if it is a magic script
****************************************************************************/
@@ -72,6 +69,8 @@ static void close_filestruct(files_struct *fsp)
{
connection_struct *conn = fsp->conn;
+ flush_write_cache(fsp, CLOSE_FLUSH);
+
fsp->open = False;
fsp->is_directory = False;
@@ -80,13 +79,6 @@ static void close_filestruct(files_struct *fsp)
free((char *)fsp->wbmpx_ptr);
fsp->wbmpx_ptr = NULL;
}
-
-#if WITH_MMAP
- if(fsp->mmap_ptr) {
- munmap(fsp->mmap_ptr,fsp->mmap_size);
- fsp->mmap_ptr = NULL;
- }
-#endif
}
/****************************************************************************
@@ -97,14 +89,16 @@ static void close_filestruct(files_struct *fsp)
the closing of the connection. In the latter case printing and
magic scripts are not run.
****************************************************************************/
-void close_file(files_struct *fsp, BOOL normal_close)
+
+static int close_normal_file(files_struct *fsp, BOOL normal_close)
{
SMB_DEV_T dev = fsp->fd_ptr->dev;
SMB_INO_T inode = fsp->fd_ptr->inode;
int token;
- BOOL last_reference = False;
- BOOL delete_on_close = fsp->fd_ptr->delete_on_close;
+ BOOL last_reference = False;
+ BOOL delete_on_close = fsp->fd_ptr->delete_on_close;
connection_struct *conn = fsp->conn;
+ int err = 0;
remove_pending_lock_requests_by_fid(fsp);
@@ -119,7 +113,10 @@ void close_file(files_struct *fsp, BOOL normal_close)
del_share_mode(token, fsp);
}
- if(fd_attempt_close(fsp) == 0)
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ release_file_oplock(fsp);
+
+ if(fd_attempt_close(fsp->fd_ptr,&err) == 0)
last_reference = True;
fsp->fd_ptr = NULL;
@@ -129,7 +126,7 @@ void close_file(files_struct *fsp, BOOL normal_close)
/* NT uses smbclose to start a print - weird */
if (normal_close && fsp->print_file)
- print_file(conn, SNUM(conn), fsp);
+ print_file(conn, fsp);
/* check for magic scripts */
if (normal_close) {
@@ -144,7 +141,8 @@ void close_file(files_struct *fsp, BOOL normal_close)
if (normal_close && last_reference && delete_on_close) {
DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n",
fsp->fsp_name));
- if(fsp->conn->vfs_ops.unlink(dos_to_unix(fsp->fsp_name, False)) != 0) {
+ if(dos_unlink(fsp->fsp_name) != 0) {
+
/*
* This call can potentially fail as another smbd may have
* had the file open with delete on close set and deleted
@@ -157,31 +155,47 @@ with error %s\n", fsp->fsp_name, strerror(errno) ));
}
}
- if(fsp->granted_oplock == True)
- global_oplocks_open--;
-
- fsp->sent_oplock_break = False;
-
- DEBUG(2,("%s closed file %s (numopen=%d)\n",
+ DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
conn->user,fsp->fsp_name,
- conn->num_files_open));
+ conn->num_files_open, err ? strerror(err) : ""));
if (fsp->fsp_name) {
string_free(&fsp->fsp_name);
}
file_free(fsp);
+
+ return err;
}
/****************************************************************************
Close a directory opened by an NT SMB call.
****************************************************************************/
-void close_directory(files_struct *fsp)
+static int close_directory(files_struct *fsp, BOOL normal_close)
{
remove_pending_change_notify_requests_by_fid(fsp);
/*
+ * NT can set delete_on_close of the last open
+ * reference to a directory also.
+ */
+
+ if (normal_close && fsp->directory_delete_on_close) {
+ BOOL ok = rmdir_internals(fsp->conn, fsp->fsp_name);
+ DEBUG(5,("close_directory: %s. Delete on close was set - deleting directory %s.\n",
+ fsp->fsp_name, ok ? "succeeded" : "failed" ));
+
+ /*
+ * Ensure we remove any change notify requests that would
+ * now fail as the directory has been deleted.
+ */
+
+ if(ok)
+ remove_pending_change_notify_requests_by_filename(fsp);
+ }
+
+ /*
* Do the code common to files and directories.
*/
close_filestruct(fsp);
@@ -190,5 +204,35 @@ void close_directory(files_struct *fsp)
string_free(&fsp->fsp_name);
file_free(fsp);
+
+ return 0;
+}
+
+/****************************************************************************
+ Close a file opened with null permissions in order to read permissions.
+****************************************************************************/
+
+static int close_statfile(files_struct *fsp, BOOL normal_close)
+{
+ close_filestruct(fsp);
+
+ if (fsp->fsp_name)
+ string_free(&fsp->fsp_name);
+
+ file_free(fsp);
+
+ return 0;
}
+/****************************************************************************
+ Close a directory opened by an NT SMB call.
+****************************************************************************/
+
+int close_file(files_struct *fsp, BOOL normal_close)
+{
+ if(fsp->is_directory)
+ return close_directory(fsp, normal_close);
+ else if(fsp->stat_open)
+ return close_statfile(fsp, normal_close);
+ return close_normal_file(fsp, normal_close);
+}
diff --git a/source3/smbd/connection.c b/source3/smbd/connection.c
index db6c66f1d5..393a3e7372 100644
--- a/source3/smbd/connection.c
+++ b/source3/smbd/connection.c
@@ -34,7 +34,7 @@ BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
struct connect_record crec;
pstring fname;
int fd;
- int mypid = getpid();
+ pid_t mypid = getpid();
int i;
DEBUG(3,("Yielding connection to %s\n",name));
@@ -42,7 +42,7 @@ BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
if (max_connections <= 0)
return(True);
- bzero(&crec,sizeof(crec));
+ memset((char *)&crec,'\0',sizeof(crec));
pstrcpy(fname,lp_lockdir());
trim_string(fname,"","/");
@@ -85,7 +85,7 @@ BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
return(False);
}
- bzero((void *)&crec,sizeof(crec));
+ memset((void *)&crec,'\0',sizeof(crec));
/* remove our mark */
if (sys_lseek(fd,i*sizeof(crec),SEEK_SET) != i*sizeof(crec) ||
@@ -154,7 +154,7 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO
return False;
}
- total_recs = file_size(fname) / sizeof(crec);
+ total_recs = get_file_size(fname) / sizeof(crec);
/* find a free spot */
for (i=0;i<max_connections;i++) {
@@ -168,10 +168,10 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO
if (Clear && crec.pid && !process_exists(crec.pid)) {
if(sys_lseek(fd,i*sizeof(crec),SEEK_SET) != i*sizeof(crec)) {
DEBUG(0,("claim_connection: ERROR: sys_lseek failed to seek \
-to %d\n", i*sizeof(crec) ));
+to %d\n", (int)(i*sizeof(crec)) ));
continue;
}
- bzero((void *)&crec,sizeof(crec));
+ memset((void *)&crec,'\0',sizeof(crec));
write(fd, &crec,sizeof(crec));
if (foundi < 0) foundi = i;
continue;
@@ -192,7 +192,7 @@ to %d\n", i*sizeof(crec) ));
}
/* fill in the crec */
- bzero((void *)&crec,sizeof(crec));
+ memset((void *)&crec,'\0',sizeof(crec));
crec.magic = 0x280267;
crec.pid = getpid();
if (conn) {
diff --git a/source3/smbd/dfree.c b/source3/smbd/dfree.c
index 8cba8d0644..86a155f526 100644
--- a/source3/smbd/dfree.c
+++ b/source3/smbd/dfree.c
@@ -27,7 +27,7 @@ extern int DEBUGLEVEL;
/****************************************************************************
normalise for DOS usage
****************************************************************************/
-static void disk_norm(SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+static void disk_norm(BOOL small_query, SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
{
/* check if the disk is beyond the max disk size */
SMB_BIG_UINT maxdisksize = lp_maxdisksize();
@@ -39,18 +39,23 @@ static void disk_norm(SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsiz
/* the -1 should stop applications getting div by 0
errors */
}
-
+
while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) {
*dfree /= 2;
*dsize /= 2;
*bsize *= 2;
- if (*bsize > WORDMAX) {
- *bsize = WORDMAX;
- if (*dsize > WORDMAX)
- *dsize = WORDMAX;
- if (*dfree > WORDMAX)
- *dfree = WORDMAX;
- break;
+ if(small_query) {
+ /*
+ * Force max to fit in 16 bit fields.
+ */
+ if (*bsize > (WORDMAX*512)) {
+ *bsize = (WORDMAX*512);
+ if (*dsize > WORDMAX)
+ *dsize = WORDMAX;
+ if (*dfree > WORDMAX)
+ *dfree = WORDMAX;
+ break;
+ }
}
}
}
@@ -152,7 +157,7 @@ static int fsusage(const char *path, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
#endif /* STAT_STATFS4 */
-#ifdef STAT_STATVFS /* SVR4 */
+#if defined(STAT_STATVFS) || defined(STAT_STATVFS64) /* SVR4 */
# define CONVERT_BLOCKS(B) \
adjust_blocks ((SMB_BIG_UINT)(B), fsd.f_frsize ? (SMB_BIG_UINT)fsd.f_frsize : (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
@@ -185,7 +190,9 @@ static int fsusage(const char *path, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
/****************************************************************************
return number of 1K blocks available on a path and total number
****************************************************************************/
-static SMB_BIG_UINT disk_free(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+
+static SMB_BIG_UINT disk_free(char *path, BOOL small_query,
+ SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
{
int dfree_retval;
SMB_BIG_UINT dfree_q = 0;
@@ -219,7 +226,7 @@ static SMB_BIG_UINT disk_free(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree
*dfree = MAX(1,*dfree);
}
- disk_norm(bsize,dfree,dsize);
+ disk_norm(small_query,bsize,dfree,dsize);
if ((*bsize) < 1024) {
dfree_retval = (*dfree)/(1024/(*bsize));
@@ -234,7 +241,8 @@ static SMB_BIG_UINT disk_free(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree
/****************************************************************************
wrap it to get filenames right
****************************************************************************/
-SMB_BIG_UINT sys_disk_free(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+SMB_BIG_UINT sys_disk_free(char *path, BOOL small_query,
+ SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
{
- return(disk_free(dos_to_unix(path,False),bsize,dfree,dsize));
+ return(disk_free(dos_to_unix(path,False),small_query, bsize,dfree,dsize));
}
diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
index b7ae2af47c..28faa9a06b 100644
--- a/source3/smbd/dir.c
+++ b/source3/smbd/dir.c
@@ -27,257 +27,378 @@ extern int DEBUGLEVEL;
This module implements directory related functions for Samba.
*/
-
-
-static uint32 dircounter = 0;
-
-
-#define NUMDIRPTRS 256
-
-
-static struct dptr_struct {
- int pid;
+typedef struct _dptr_struct {
+ struct _dptr_struct *next, *prev;
+ int dnum;
+ uint16 spid;
connection_struct *conn;
- uint32 lastused;
void *ptr;
- BOOL valid;
- BOOL finished;
BOOL expect_close;
char *wcard; /* Field only used for trans2_ searches */
uint16 attr; /* Field only used for trans2_ searches */
char *path;
-}
-dirptrs[NUMDIRPTRS];
+} dptr_struct;
+static struct bitmap *dptr_bmap;
+static dptr_struct *dirptrs;
static int dptrs_open = 0;
+#define INVALID_DPTR_KEY (-3)
+
/****************************************************************************
-initialise the dir array
+ Initialise the dir bitmap.
****************************************************************************/
+
void init_dptrs(void)
{
static BOOL dptrs_init=False;
- int i;
- if (dptrs_init) return;
- for (i=0;i<NUMDIRPTRS;i++)
- {
- dirptrs[i].valid = False;
- dirptrs[i].wcard = NULL;
- dirptrs[i].ptr = NULL;
- string_init(&dirptrs[i].path,"");
- }
+ if (dptrs_init)
+ return;
+
+ dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
+
+ if (!dptr_bmap)
+ exit_server("out of memory in init_dptrs\n");
+
dptrs_init = True;
}
/****************************************************************************
-idle a dptr - the directory is closed but the control info is kept
+ Idle a dptr - the directory is closed but the control info is kept.
****************************************************************************/
-static void dptr_idle(int key)
+
+static void dptr_idle(dptr_struct *dptr)
{
- if (dirptrs[key].valid && dirptrs[key].ptr) {
- DEBUG(4,("Idling dptr key %d\n",key));
+ if (dptr->ptr) {
+ DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
dptrs_open--;
- CloseDir(dirptrs[key].ptr);
- dirptrs[key].ptr = NULL;
- }
+ CloseDir(dptr->ptr);
+ dptr->ptr = NULL;
+ }
}
/****************************************************************************
-idle the oldest dptr
+ Idle the oldest dptr.
****************************************************************************/
+
static void dptr_idleoldest(void)
{
- int i;
- uint32 old=dircounter+1;
- int oldi= -1;
- for (i=0;i<NUMDIRPTRS;i++)
- if (dirptrs[i].valid && dirptrs[i].ptr && dirptrs[i].lastused < old) {
- old = dirptrs[i].lastused;
- oldi = i;
+ dptr_struct *dptr;
+
+ /*
+ * Go to the end of the list.
+ */
+ for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
+ ;
+
+ if(!dptr) {
+ DEBUG(0,("No dptrs available to idle ?\n"));
+ return;
+ }
+
+ /*
+ * Idle the oldest pointer.
+ */
+
+ for(; dptr; dptr = dptr->prev) {
+ if (dptr->ptr) {
+ dptr_idle(dptr);
+ return;
}
- if (oldi != -1)
- dptr_idle(oldi);
- else
- DEBUG(0,("No dptrs available to idle??\n"));
+ }
}
/****************************************************************************
-get the dir ptr for a dir index
+ Get the dptr_struct for a dir index.
****************************************************************************/
-static void *dptr_get(int key,uint32 lastused)
+
+static dptr_struct *dptr_get(int key, BOOL forclose)
{
- struct dptr_struct *dp = &dirptrs[key];
-
- if (dp->valid) {
- if (lastused) dp->lastused = lastused;
- if (!dp->ptr) {
- if (dptrs_open >= MAX_OPEN_DIRECTORIES)
- dptr_idleoldest();
- DEBUG(4,("Reopening dptr key %d\n",key));
- if ((dp->ptr = OpenDir(dp->conn, dp->path, True)))
- dptrs_open++;
- }
- return(dp->ptr);
- }
- return(NULL);
+ dptr_struct *dptr;
+
+ for(dptr = dirptrs; dptr; dptr = dptr->next) {
+ if(dptr->dnum == key) {
+ if (!forclose && !dptr->ptr) {
+ if (dptrs_open >= MAX_OPEN_DIRECTORIES)
+ dptr_idleoldest();
+ DEBUG(4,("Reopening dptr key %d\n",key));
+ if ((dptr->ptr = OpenDir(dptr->conn, dptr->path, True)))
+ dptrs_open++;
+ }
+ DLIST_PROMOTE(dirptrs,dptr);
+ return dptr;
+ }
+ }
+ return(NULL);
}
/****************************************************************************
-get the dir path for a dir index
+ Get the dptr ptr for a dir index.
****************************************************************************/
+
+static void *dptr_ptr(int key)
+{
+ dptr_struct *dptr = dptr_get(key, False);
+
+ if (dptr)
+ return(dptr->ptr);
+ return(NULL);
+}
+
+/****************************************************************************
+ Get the dir path for a dir index.
+****************************************************************************/
+
char *dptr_path(int key)
{
- if (dirptrs[key].valid)
- return(dirptrs[key].path);
+ dptr_struct *dptr = dptr_get(key, False);
+
+ if (dptr)
+ return(dptr->path);
return(NULL);
}
/****************************************************************************
-get the dir wcard for a dir index (lanman2 specific)
+ Get the dir wcard for a dir index (lanman2 specific).
****************************************************************************/
+
char *dptr_wcard(int key)
{
- if (dirptrs[key].valid)
- return(dirptrs[key].wcard);
+ dptr_struct *dptr = dptr_get(key, False);
+
+ if (dptr)
+ return(dptr->wcard);
return(NULL);
}
/****************************************************************************
-set the dir wcard for a dir index (lanman2 specific)
-Returns 0 on ok, 1 on fail.
+ Set the dir wcard for a dir index (lanman2 specific).
+ Returns 0 on ok, 1 on fail.
****************************************************************************/
+
BOOL dptr_set_wcard(int key, char *wcard)
{
- if (dirptrs[key].valid) {
- dirptrs[key].wcard = wcard;
+ dptr_struct *dptr = dptr_get(key, False);
+
+ if (dptr) {
+ dptr->wcard = wcard;
return True;
}
return False;
}
/****************************************************************************
-set the dir attrib for a dir index (lanman2 specific)
-Returns 0 on ok, 1 on fail.
+ Set the dir attrib for a dir index (lanman2 specific).
+ Returns 0 on ok, 1 on fail.
****************************************************************************/
+
BOOL dptr_set_attr(int key, uint16 attr)
{
- if (dirptrs[key].valid) {
- dirptrs[key].attr = attr;
+ dptr_struct *dptr = dptr_get(key, False);
+
+ if (dptr) {
+ dptr->attr = attr;
return True;
}
return False;
}
/****************************************************************************
-get the dir attrib for a dir index (lanman2 specific)
+ Get the dir attrib for a dir index (lanman2 specific)
****************************************************************************/
+
uint16 dptr_attr(int key)
{
- if (dirptrs[key].valid)
- return(dirptrs[key].attr);
+ dptr_struct *dptr = dptr_get(key, False);
+
+ if (dptr)
+ return(dptr->attr);
return(0);
}
/****************************************************************************
-close a dptr
+ Close a dptr (internal func).
+****************************************************************************/
+
+static void dptr_close_internal(dptr_struct *dptr)
+{
+ DEBUG(4,("closing dptr key %d\n",dptr->dnum));
+
+ DLIST_REMOVE(dirptrs, dptr);
+
+ /*
+ * Free the dnum in the bitmap. Remember the dnum value is always
+ * biased by one with respect to the bitmap.
+ */
+
+ if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
+ DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
+ dptr->dnum ));
+ }
+
+ bitmap_clear(dptr_bmap, dptr->dnum - 1);
+
+ if (dptr->ptr) {
+ CloseDir(dptr->ptr);
+ dptrs_open--;
+ }
+
+ /* Lanman 2 specific code */
+ if (dptr->wcard)
+ free(dptr->wcard);
+ string_set(&dptr->path,"");
+ free((char *)dptr);
+}
+
+/****************************************************************************
+ Close a dptr given a key.
****************************************************************************/
-void dptr_close(int key)
+
+void dptr_close(int *key)
{
+ dptr_struct *dptr;
+
+ if(*key == INVALID_DPTR_KEY)
+ return;
+
/* OS/2 seems to use -1 to indicate "close all directories" */
- if (key == -1) {
- int i;
- for (i=0;i<NUMDIRPTRS;i++)
- dptr_close(i);
+ if (*key == -1) {
+ dptr_struct *next;
+ for(dptr = dirptrs; dptr; dptr = next) {
+ next = dptr->next;
+ dptr_close_internal(dptr);
+ }
+ *key = INVALID_DPTR_KEY;
return;
}
- if (key < 0 || key >= NUMDIRPTRS) {
- DEBUG(3,("Invalid key %d given to dptr_close\n",key));
+ dptr = dptr_get(*key, True);
+
+ if (!dptr) {
+ DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
return;
}
- if (dirptrs[key].valid) {
- DEBUG(4,("closing dptr key %d\n",key));
- if (dirptrs[key].ptr) {
- CloseDir(dirptrs[key].ptr);
- dptrs_open--;
- }
- /* Lanman 2 specific code */
- if (dirptrs[key].wcard)
- free(dirptrs[key].wcard);
- dirptrs[key].valid = False;
- string_set(&dirptrs[key].path,"");
- }
+ dptr_close_internal(dptr);
+
+ *key = INVALID_DPTR_KEY;
}
/****************************************************************************
-close all dptrs for a cnum
+ Close all dptrs for a cnum.
****************************************************************************/
+
void dptr_closecnum(connection_struct *conn)
{
- int i;
- for (i=0;i<NUMDIRPTRS;i++)
- if (dirptrs[i].valid && dirptrs[i].conn == conn)
- dptr_close(i);
+ dptr_struct *dptr, *next;
+ for(dptr = dirptrs; dptr; dptr = next) {
+ next = dptr->next;
+ if (dptr->conn == conn)
+ dptr_close_internal(dptr);
+ }
}
/****************************************************************************
-idle all dptrs for a cnum
+ Idle all dptrs for a cnum.
****************************************************************************/
+
void dptr_idlecnum(connection_struct *conn)
{
- int i;
- for (i=0;i<NUMDIRPTRS;i++)
- if (dirptrs[i].valid && dirptrs[i].conn == conn && dirptrs[i].ptr)
- dptr_idle(i);
+ dptr_struct *dptr;
+ for(dptr = dirptrs; dptr; dptr = dptr->next) {
+ if (dptr->conn == conn && dptr->ptr)
+ dptr_idle(dptr);
+ }
}
/****************************************************************************
-close a dptr that matches a given path, only if it matches the pid also
+ Close a dptr that matches a given path, only if it matches the spid also.
****************************************************************************/
-void dptr_closepath(char *path,int pid)
+
+void dptr_closepath(char *path,uint16 spid)
{
- int i;
- for (i=0;i<NUMDIRPTRS;i++)
- if (dirptrs[i].valid && pid == dirptrs[i].pid &&
- strequal(dirptrs[i].path,path))
- dptr_close(i);
+ dptr_struct *dptr, *next;
+ for(dptr = dirptrs; dptr; dptr = next) {
+ next = dptr->next;
+ if (spid == dptr->spid && strequal(dptr->path,path))
+ dptr_close_internal(dptr);
+ }
}
/****************************************************************************
- start a directory listing
+ Start a directory listing.
****************************************************************************/
+
static BOOL start_dir(connection_struct *conn,char *directory)
{
- DEBUG(5,("start_dir dir=%s\n",directory));
+ DEBUG(5,("start_dir dir=%s\n",directory));
- if (!check_name(directory,conn))
- return(False);
+ if (!check_name(directory,conn))
+ return(False);
- if (! *directory)
- directory = ".";
-
- conn->dirptr = OpenDir(conn, directory, True);
- if (conn->dirptr) {
- dptrs_open++;
- string_set(&conn->dirpath,directory);
- return(True);
- }
+ if (! *directory)
+ directory = ".";
+
+ conn->dirptr = OpenDir(conn, directory, True);
+ if (conn->dirptr) {
+ dptrs_open++;
+ string_set(&conn->dirpath,directory);
+ return(True);
+ }
- return(False);
+ return(False);
}
+/****************************************************************************
+ Try and close the oldest handle not marked for
+ expect close in the hope that the client has
+ finished with that one.
+****************************************************************************/
+
+static void dptr_close_oldest(BOOL old)
+{
+ dptr_struct *dptr;
+
+ /*
+ * Go to the end of the list.
+ */
+ for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
+ ;
+
+ if(!dptr) {
+ DEBUG(0,("No old dptrs available to close oldest ?\n"));
+ return;
+ }
+
+ /*
+ * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
+ * does not have expect_close set. If 'old' is false, close
+ * one of the new dnum handles.
+ */
+
+ for(; dptr; dptr = dptr->prev) {
+ if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
+ (!old && (dptr->dnum > 255))) {
+ dptr_close_internal(dptr);
+ return;
+ }
+ }
+}
/****************************************************************************
-create a new dir ptr
+ Create a new dir ptr. If the flag old_handle is true then we must allocate
+ from the bitmap range 0 - 255 as old SMBsearch directory handles are only
+ one byte long. If old_handle is false we allocate from the range
+ 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
+ a directory handle is never zero. All the above is folklore taught to
+ me at Andrew's knee.... :-) :-). JRA.
****************************************************************************/
-int dptr_create(connection_struct *conn,char *path, BOOL expect_close,int pid)
+
+int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect_close,uint16 spid)
{
- int i;
- uint32 old;
- int oldi;
+ dptr_struct *dptr;
if (!start_dir(conn,path))
return(-2); /* Code to say use a unix error return code. */
@@ -285,70 +406,103 @@ int dptr_create(connection_struct *conn,char *path, BOOL expect_close,int pid)
if (dptrs_open >= MAX_OPEN_DIRECTORIES)
dptr_idleoldest();
- for (i=0;i<NUMDIRPTRS;i++)
- if (!dirptrs[i].valid)
- break;
- if (i == NUMDIRPTRS) i = -1;
+ dptr = (dptr_struct *)malloc(sizeof(dptr_struct));
+ if(!dptr) {
+ DEBUG(0,("malloc fail in dptr_create.\n"));
+ return -1;
+ }
+
+ ZERO_STRUCTP(dptr);
+
+ if(old_handle) {
+
+ /*
+ * This is an old-style SMBsearch request. Ensure the
+ * value we return will fit in the range 1-255.
+ */
+
+ dptr->dnum = bitmap_find(dptr_bmap, 0);
+
+ if(dptr->dnum == -1 || dptr->dnum > 254) {
+
+ /*
+ * Try and close the oldest handle not marked for
+ * expect close in the hope that the client has
+ * finished with that one.
+ */
+
+ dptr_close_oldest(True);
+ /* Now try again... */
+ dptr->dnum = bitmap_find(dptr_bmap, 0);
- /* as a 2nd option, grab the oldest not marked for expect_close */
- if (i == -1) {
- old=dircounter+1;
- oldi= -1;
- for (i=0;i<NUMDIRPTRS;i++)
- if (!dirptrs[i].expect_close && dirptrs[i].lastused < old) {
- old = dirptrs[i].lastused;
- oldi = i;
+ if(dptr->dnum == -1 || dptr->dnum > 254) {
+ DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
+ free((char *)dptr);
+ return -1;
}
- i = oldi;
- }
+ }
+ } else {
+
+ /*
+ * This is a new-style trans2 request. Allocate from
+ * a range that will return 256 - MAX_DIRECTORY_HANDLES.
+ */
+
+ dptr->dnum = bitmap_find(dptr_bmap, 255);
+
+ if(dptr->dnum == -1 || dptr->dnum < 255) {
- /* a 3rd option - grab the oldest one */
- if (i == -1) {
- old=dircounter+1;
- oldi= -1;
- for (i=0;i<NUMDIRPTRS;i++)
- if (dirptrs[i].lastused < old) {
- old = dirptrs[i].lastused;
- oldi = i;
+ /*
+ * Try and close the oldest handle close in the hope that
+ * the client has finished with that one. This will only
+ * happen in the case of the Win98 client bug where it leaks
+ * directory handles.
+ */
+
+ dptr_close_oldest(False);
+
+ /* Now try again... */
+ dptr->dnum = bitmap_find(dptr_bmap, 255);
+
+ if(dptr->dnum == -1 || dptr->dnum < 255) {
+ DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
+ free((char *)dptr);
+ return -1;
}
- i = oldi;
+ }
}
- if (i == -1) {
- DEBUG(0,("Error - all dirptrs in use??\n"));
- return(-1);
- }
+ bitmap_set(dptr_bmap, dptr->dnum);
+
+ dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
- if (dirptrs[i].valid)
- dptr_close(i);
+ dptr->ptr = conn->dirptr;
+ string_set(&dptr->path,path);
+ dptr->conn = conn;
+ dptr->spid = spid;
+ dptr->expect_close = expect_close;
+ dptr->wcard = NULL; /* Only used in lanman2 searches */
+ dptr->attr = 0; /* Only used in lanman2 searches */
- dirptrs[i].ptr = conn->dirptr;
- string_set(&dirptrs[i].path,path);
- dirptrs[i].lastused = dircounter++;
- dirptrs[i].finished = False;
- dirptrs[i].conn = conn;
- dirptrs[i].pid = pid;
- dirptrs[i].expect_close = expect_close;
- dirptrs[i].wcard = NULL; /* Only used in lanman2 searches */
- dirptrs[i].attr = 0; /* Only used in lanman2 searches */
- dirptrs[i].valid = True;
+ DLIST_ADD(dirptrs, dptr);
DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
- i,path,expect_close));
+ dptr->dnum,path,expect_close));
- return(i);
+ return(dptr->dnum);
}
#define DPTR_MASK ((uint32)(((uint32)1)<<31))
/****************************************************************************
-fill the 5 byte server reserved dptr field
+ Fill the 5 byte server reserved dptr field.
****************************************************************************/
+
BOOL dptr_fill(char *buf1,unsigned int key)
{
unsigned char *buf = (unsigned char *)buf1;
- void *p = dptr_get(key,0);
+ void *p = dptr_ptr(key);
uint32 offset;
if (!p) {
DEBUG(1,("filling null dirptr %d\n",key));
@@ -364,20 +518,22 @@ BOOL dptr_fill(char *buf1,unsigned int key)
/****************************************************************************
-return True is the offset is at zero
+ Return True if the offset is at zero.
****************************************************************************/
+
BOOL dptr_zero(char *buf)
{
return((IVAL(buf,1)&~DPTR_MASK) == 0);
}
/****************************************************************************
-fetch the dir ptr and seek it given the 5 byte server field
+ Fetch the dir ptr and seek it given the 5 byte server field.
****************************************************************************/
+
void *dptr_fetch(char *buf,int *num)
{
unsigned int key = *(unsigned char *)buf;
- void *p = dptr_get(key,dircounter++);
+ void *p = dptr_ptr(key);
uint32 offset;
if (!p) {
DEBUG(3,("fetched null dirptr %d\n",key));
@@ -392,11 +548,12 @@ void *dptr_fetch(char *buf,int *num)
}
/****************************************************************************
-fetch the dir ptr.
+ Fetch the dir ptr.
****************************************************************************/
+
void *dptr_fetch_lanman2(int dptr_num)
{
- void *p = dptr_get(dptr_num,dircounter++);
+ void *p = dptr_ptr(dptr_num);
if (!p) {
DEBUG(3,("fetched null dirptr %d\n",dptr_num));
@@ -407,8 +564,9 @@ void *dptr_fetch_lanman2(int dptr_num)
}
/****************************************************************************
-check a filetype for being valid
+ Check a filetype for being valid.
****************************************************************************/
+
BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype)
{
if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
@@ -417,8 +575,9 @@ BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int di
}
/****************************************************************************
- get a directory entry
+ Get an 8.3 directory entry.
****************************************************************************/
+
BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname,
SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
{
@@ -437,64 +596,71 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname,
strequal(conn->dirpath,".") ||
strequal(conn->dirpath,"/"));
- needslash =
- ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
+ needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
if (!conn->dirptr)
return(False);
while (!found)
- {
- dname = ReadDirName(conn->dirptr);
+ {
+ BOOL filename_is_mask = False;
+ dname = ReadDirName(conn->dirptr);
- DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
- (long)conn->dirptr,TellDir(conn->dirptr)));
+ DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
+ (long)conn->dirptr,TellDir(conn->dirptr)));
- if (dname == NULL)
- return(False);
+ if (dname == NULL)
+ return(False);
- pstrcpy(filename,dname);
-
- if ((strcmp(filename,mask) == 0) ||
- (name_map_mangle(filename,True,SNUM(conn)) &&
- mask_match(filename,mask,False,False)))
- {
- if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
- continue;
-
- pstrcpy(fname,filename);
- *path = 0;
- pstrcpy(path,conn->dirpath);
- if(needslash)
- pstrcat(path,"/");
- pstrcpy(pathreal,path);
- pstrcat(path,fname);
- pstrcat(pathreal,dname);
- if (conn->vfs_ops.stat(dos_to_unix(pathreal, False), &sbuf) != 0)
- {
- DEBUG(5,("Couldn't stat 1 [%s]\n",path));
- continue;
- }
-
- if (check_descend &&
- !strequal(fname,".") && !strequal(fname,".."))
- continue;
+ pstrcpy(filename,dname);
+
+ if ((filename_is_mask = (strcmp(filename,mask) == 0)) ||
+ (name_map_mangle(filename,True,False,SNUM(conn)) &&
+ mask_match(filename,mask,False,False)))
+ {
+ if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
+ continue;
+
+ pstrcpy(fname,filename);
+ *path = 0;
+ pstrcpy(path,conn->dirpath);
+ if(needslash)
+ pstrcat(path,"/");
+ pstrcpy(pathreal,path);
+ pstrcat(path,fname);
+ pstrcat(pathreal,dname);
+ if (dos_stat(pathreal,&sbuf) != 0)
+ {
+ DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
+ continue;
+ }
+
+ if (check_descend && !strequal(fname,".") && !strequal(fname,".."))
+ continue;
- *mode = dos_mode(conn,pathreal,&sbuf);
+ *mode = dos_mode(conn,pathreal,&sbuf);
+
+ if (!dir_check_ftype(conn,*mode,&sbuf,dirtype))
+ {
+ DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
+ continue;
+ }
- if (!dir_check_ftype(conn,*mode,&sbuf,dirtype)) {
- DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
- continue;
- }
+ if (!filename_is_mask)
+ {
+ /* Now we can allow the mangled cache to be updated */
+ pstrcpy(filename,dname);
+ name_map_mangle(filename,True,True,SNUM(conn));
+ }
- *size = sbuf.st_size;
- *date = sbuf.st_mtime;
+ *size = sbuf.st_size;
+ *date = sbuf.st_mtime;
- DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
+ DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
- found = True;
- }
+ found = True;
}
+ }
return(found);
}
@@ -512,25 +678,26 @@ typedef struct
/*******************************************************************
-open a directory
+ Open a directory.
********************************************************************/
+
void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
{
Dir *dirp;
char *n;
- DIR *p = conn->vfs_ops.opendir(name);
+ DIR *p = dos_opendir(name);
int used=0;
if (!p) return(NULL);
dirp = (Dir *)malloc(sizeof(Dir));
if (!dirp) {
- conn->vfs_ops.closedir(p);
+ closedir(p);
return(NULL);
}
dirp->pos = dirp->numentries = dirp->mallocsize = 0;
dirp->data = dirp->current = NULL;
- while ((n = vfs_readdirname(conn, p)))
+ while ((n = dos_readdirname(p)))
{
int l = strlen(n)+1;
@@ -554,14 +721,15 @@ void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
dirp->numentries++;
}
- conn->vfs_ops.closedir(p);
+ closedir(p);
return((void *)dirp);
}
/*******************************************************************
-close a directory
+ Close a directory.
********************************************************************/
+
void CloseDir(void *p)
{
Dir *dirp = (Dir *)p;
@@ -571,8 +739,9 @@ void CloseDir(void *p)
}
/*******************************************************************
-read from a directory
+ Read from a directory.
********************************************************************/
+
char *ReadDirName(void *p)
{
char *ret;
@@ -589,8 +758,9 @@ char *ReadDirName(void *p)
/*******************************************************************
-seek a dir
+ Seek a dir.
********************************************************************/
+
BOOL SeekDir(void *p,int pos)
{
Dir *dirp = (Dir *)p;
@@ -608,8 +778,9 @@ BOOL SeekDir(void *p,int pos)
}
/*******************************************************************
-tell a dir position
+ Tell a dir position.
********************************************************************/
+
int TellDir(void *p)
{
Dir *dirp = (Dir *)p;
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index e6f1dc7206..27393fe1c6 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -50,7 +50,7 @@ mode_t unix_mode(connection_struct *conn,int dosmode)
can always create a file in a read-only directory. */
result |= (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR);
/* Apply directory mask */
- result &= lp_dir_mode(SNUM(conn));
+ result &= lp_dir_mask(SNUM(conn));
/* Add in force bits */
result |= lp_force_dir_mode(SNUM(conn));
} else {
@@ -64,7 +64,7 @@ mode_t unix_mode(connection_struct *conn,int dosmode)
result |= S_IXOTH;
/* Apply mode mask */
- result &= lp_create_mode(SNUM(conn));
+ result &= lp_create_mask(SNUM(conn));
/* Add in force bits */
result |= lp_force_create_mode(SNUM(conn));
}
@@ -148,7 +148,7 @@ int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *
if (!st) {
st = &st1;
- if (conn->vfs_ops.stat(dos_to_unix(fname,False),st)) return(-1);
+ if (dos_stat(fname,st)) return(-1);
}
if (S_ISDIR(st->st_mode)) dosmode |= aDIR;
@@ -179,14 +179,12 @@ int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *
}
/* if we previously had any w bits set then leave them alone
- if the new mode is not rdonly */
- if (!IS_DOS_READONLY(dosmode) &&
- (tmp = st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))) {
- unixmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
- unixmode |= tmp;
+ whilst adding in the new w bits, if the new mode is not rdonly */
+ if (!IS_DOS_READONLY(dosmode)) {
+ unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
}
- return(conn->vfs_ops.chmod(fname,unixmode));
+ return(dos_chmod(fname,unixmode));
}
@@ -202,7 +200,7 @@ int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
errno = 0;
- if(conn->vfs_ops.utime(dos_to_unix(fname, False), times) == 0)
+ if(dos_utime(fname, times) == 0)
return 0;
if((errno != EPERM) && (errno != EACCES))
@@ -217,7 +215,7 @@ int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
(as DOS does).
*/
- if(conn->vfs_ops.stat(dos_to_unix(fname,False),&sb) != 0)
+ if(dos_stat(fname,&sb) != 0)
return -1;
/* Check if we have write access. */
@@ -230,7 +228,7 @@ int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
current_user.ngroups,current_user.groups)))) {
/* We are allowed to become root and change the filetime. */
become_root(False);
- ret = conn->vfs_ops.utime(dos_to_unix(fname, False), times);
+ ret = dos_utime(fname, times);
unbecome_root(False);
}
}
@@ -251,9 +249,8 @@ BOOL set_filetime(connection_struct *conn, char *fname, time_t mtime)
if (file_utime(conn, fname, &times)) {
DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
+ return False;
}
return(True);
}
-
-
diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c
index 1e16627515..8b48a921fd 100644
--- a/source3/smbd/fileio.c
+++ b/source3/smbd/fileio.c
@@ -23,6 +23,7 @@
extern int DEBUGLEVEL;
+static BOOL setup_write_cache(files_struct *, SMB_OFF_T);
/****************************************************************************
seek a file. Try to avoid the seek if possible
@@ -36,7 +37,19 @@ SMB_OFF_T seek_file(files_struct *fsp,SMB_OFF_T pos)
if (fsp->print_file && lp_postscript(fsp->conn->service))
offset = 3;
- seek_ret = fsp->conn->vfs_ops.lseek(fsp->fd_ptr->fd,pos+offset,SEEK_SET);
+ seek_ret = sys_lseek(fsp->fd_ptr->fd,pos+offset,SEEK_SET);
+
+ /*
+ * We want to maintain the fiction that we can seek
+ * on a fifo for file system purposes. This allows
+ * people to set up UNIX fifo's that feed data to Windows
+ * applications. JRA.
+ */
+
+ if((seek_ret == -1) && (errno == ESPIPE)) {
+ seek_ret = pos+offset;
+ errno = 0;
+ }
if((seek_ret == -1) || (seek_ret != pos+offset)) {
DEBUG(0,("seek_file: sys_lseek failed. Error was %s\n", strerror(errno) ));
@@ -53,6 +66,29 @@ SMB_OFF_T seek_file(files_struct *fsp,SMB_OFF_T pos)
}
/****************************************************************************
+ Read from write cache if we can.
+****************************************************************************/
+
+static unsigned int cache_read_hits;
+
+BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
+{
+ write_cache *wcp = fsp->wcp;
+
+ if(!wcp)
+ return False;
+
+ if(n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size)
+ return False;
+
+ memcpy(data, wcp->data + (pos - wcp->offset), n);
+
+ cache_read_hits++;
+
+ return True;
+}
+
+/****************************************************************************
read from a file
****************************************************************************/
@@ -62,7 +98,7 @@ ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
#if USE_READ_PREDICTION
if (!fsp->can_write) {
- ret = read_predict(fsp, fsp->fd_ptr->fd,pos,data,NULL,n);
+ ret = read_predict(fsp->fd_ptr->fd,pos,data,NULL,n);
data += ret;
n -= ret;
@@ -70,40 +106,64 @@ ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
}
#endif
-#if WITH_MMAP
- if (fsp->mmap_ptr) {
- SMB_OFF_T num = (fsp->mmap_size > pos) ? (fsp->mmap_size - pos) : 0;
- num = MIN(n,num);
- if (num > 0) {
- memcpy(data,fsp->mmap_ptr+pos,num);
- data += num;
- pos += num;
- n -= num;
- ret += num;
- }
- }
-#endif
+ /*
+ * Serve from write cache if we can.
+ */
+ if(read_from_write_cache(fsp, data, pos, n))
+ return n;
+
+ flush_write_cache(fsp, READ_FLUSH);
if (seek_file(fsp,pos) == -1) {
DEBUG(3,("read_file: Failed to seek to %.0f\n",(double)pos));
return(ret);
}
-
+
if (n > 0) {
- readret = fsp->conn->vfs_ops.read(fsp->fd_ptr->fd,data,n);
+ readret = read(fsp->fd_ptr->fd,data,n);
if (readret > 0) ret += readret;
}
return(ret);
}
+/* Write cache static counters. */
+
+static unsigned int abutted_writes;
+static unsigned int total_writes;
+static unsigned int non_oplock_writes;
+static unsigned int direct_writes;
+static unsigned int init_writes;
+static unsigned int flushed_writes;
+static unsigned int num_perfect_writes;
+static unsigned int flush_reasons[NUM_FLUSH_REASONS];
+
+/* how many write cache buffers have been allocated */
+static unsigned int allocated_write_caches;
+static unsigned int num_write_caches;
+
+/****************************************************************************
+ *Really* write to a file
+****************************************************************************/
+
+static ssize_t real_write_file(files_struct *fsp,char *data,SMB_OFF_T pos, size_t n)
+{
+ if ((pos != -1) && (seek_file(fsp,pos) == -1))
+ return -1;
+
+ return write_data(fsp->fd_ptr->fd,data,n);
+}
/****************************************************************************
write to a file
****************************************************************************/
-ssize_t write_file(files_struct *fsp,char *data,size_t n)
+ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n)
{
+ write_cache *wcp = fsp->wcp;
+ ssize_t total_written = 0;
+ int write_path = -1;
+
if (!fsp->can_write) {
errno = EPERM;
return(0);
@@ -112,25 +172,488 @@ ssize_t write_file(files_struct *fsp,char *data,size_t n)
if (!fsp->modified) {
SMB_STRUCT_STAT st;
fsp->modified = True;
- if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&st) == 0) {
+
+ if (sys_fstat(fsp->fd_ptr->fd,&st) == 0) {
int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
if (MAP_ARCHIVE(fsp->conn) && !IS_DOS_ARCHIVE(dosmode)) {
file_chmod(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st);
}
+
+ /*
+ * If this is the first write and we have an exclusive oplock then setup
+ * the write cache.
+ */
+
+ if ((fsp->oplock_type == EXCLUSIVE_OPLOCK) && !wcp) {
+ setup_write_cache(fsp, st.st_size);
+ wcp = fsp->wcp;
+ }
}
}
- return(vfs_write_data(fsp,data,n));
+ total_writes++;
+ if (!fsp->oplock_type) {
+ non_oplock_writes++;
+ }
+
+ /*
+ * If this file is level II oplocked then we need
+ * to grab the shared memory lock and inform all
+ * other files with a level II lock that they need
+ * to flush their read caches. We keep the lock over
+ * the shared memory area whilst doing this.
+ */
+
+ if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) {
+ SMB_DEV_T dev = fsp->fd_ptr->dev;
+ SMB_INO_T inode = fsp->fd_ptr->inode;
+ share_mode_entry *share_list = NULL;
+ pid_t pid = getpid();
+ int token = -1;
+ int num_share_modes = 0;
+ int i;
+
+ if (lock_share_entry(fsp->conn, dev, inode, &token) == False) {
+ DEBUG(0,("write_file: failed to lock share mode entry for file %s.\n", fsp->fsp_name ));
+ }
+
+ num_share_modes = get_share_modes(fsp->conn, token, dev, inode, &share_list);
+
+ for(i = 0; i < num_share_modes; i++) {
+ share_mode_entry *share_entry = &share_list[i];
+
+ /*
+ * As there could have been multiple writes waiting at the lock_share_entry
+ * gate we may not be the first to enter. Hence the state of the op_types
+ * in the share mode entries may be partly NO_OPLOCK and partly LEVEL_II
+ * oplock. It will do no harm to re-send break messages to those smbd's
+ * that are still waiting their turn to remove their LEVEL_II state, and
+ * also no harm to ignore existing NO_OPLOCK states. JRA.
+ */
+
+ if (share_entry->op_type == NO_OPLOCK)
+ continue;
+
+ /* Paranoia .... */
+ if (EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) {
+ DEBUG(0,("write_file: PANIC. share mode entry %d is an exlusive oplock !\n", i ));
+ abort();
+ }
+
+ /*
+ * Check if this is a file we have open (including the
+ * file we've been called to do write_file on. If so
+ * then break it directly without releasing the lock.
+ */
+
+ if (pid == share_entry->pid) {
+ files_struct *new_fsp = file_find_dit(dev, inode, &share_entry->time);
+
+ /* Paranoia check... */
+ if(new_fsp == NULL) {
+ DEBUG(0,("write_file: PANIC. share mode entry %d is not a local file !\n", i ));
+ abort();
+ }
+ oplock_break_level2(new_fsp, True, token);
+
+ } else {
+
+ /*
+ * This is a remote file and so we send an asynchronous
+ * message.
+ */
+
+ request_oplock_break(share_entry, dev, inode);
+ }
+ }
+
+ free((char *)share_list);
+ unlock_share_entry(fsp->conn, dev, inode, token);
+ }
+
+ /* Paranoia check... */
+ if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) {
+ DEBUG(0,("write_file: PANIC. File %s still has a level II oplock.\n", fsp->fsp_name));
+ abort();
+ }
+
+ if (total_writes % 500 == 0) {
+ DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u flushes=%u total=%u \
+nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
+ init_writes, abutted_writes, flushed_writes, total_writes, non_oplock_writes,
+ allocated_write_caches,
+ num_write_caches, direct_writes, num_perfect_writes, cache_read_hits ));
+
+ DEBUG(3,("WRITECACHE: SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
+ flush_reasons[SEEK_FLUSH],
+ flush_reasons[READ_FLUSH],
+ flush_reasons[WRITE_FLUSH],
+ flush_reasons[READRAW_FLUSH],
+ flush_reasons[OPLOCK_RELEASE_FLUSH],
+ flush_reasons[CLOSE_FLUSH],
+ flush_reasons[SYNC_FLUSH] ));
+ }
+
+ if(!wcp) {
+ direct_writes++;
+ return real_write_file(fsp, data, pos, n);
+ }
+
+ DEBUG(9,("write_file(fd=%d pos=%d size=%d) wofs=%d wsize=%d\n",
+ fsp->fd_ptr->fd, (int)pos, (int)n, (int)wcp->offset, (int)wcp->data_size));
+
+ /*
+ * If we have active cache and it isn't contiguous then we flush.
+ * NOTE: There is a small problem with running out of disk ....
+ */
+
+ if (wcp->data_size) {
+
+ BOOL cache_flush_needed = False;
+
+ if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) {
+
+ /*
+ * Start of write overlaps or abutts the existing data.
+ */
+
+ size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n);
+
+ memcpy(wcp->data + (pos - wcp->offset), data, data_used);
+
+ /*
+ * Update the current buffer size with the new data.
+ */
+
+ if(pos + data_used > wcp->offset + wcp->data_size)
+ wcp->data_size = pos + data_used - wcp->offset;
+
+ /*
+ * If we used all the data then
+ * return here.
+ */
+
+ if(n == data_used)
+ return n;
+ else
+ cache_flush_needed = True;
+
+ /*
+ * Move the start of data forward by the amount used,
+ * cut down the amount left by the same amount.
+ */
+
+ data += data_used;
+ pos += data_used;
+ n -= data_used;
+
+ abutted_writes++;
+ total_written = data_used;
+
+ write_path = 1;
+
+ } else if ((pos < wcp->offset) && (pos + n > wcp->offset) &&
+ (pos + n <= wcp->offset + wcp->alloc_size)) {
+
+ /*
+ * End of write overlaps the existing data.
+ */
+
+ size_t data_used = pos + n - wcp->offset;
+
+ memcpy(wcp->data, data + n - data_used, data_used);
+
+ /*
+ * Update the current buffer size with the new data.
+ */
+
+ if(pos + n > wcp->offset + wcp->data_size)
+ wcp->data_size = pos + n - wcp->offset;
+
+ /*
+ * We don't need to move the start of data, but we
+ * cut down the amount left by the amount used.
+ */
+
+ n -= data_used;
+
+ /*
+ * We cannot have used all the data here.
+ */
+
+ cache_flush_needed = True;
+
+ abutted_writes++;
+ total_written = data_used;
+
+ write_path = 2;
+
+ } else if ( (pos >= wcp->file_size) &&
+ (pos > wcp->offset + wcp->data_size) &&
+ (pos < wcp->offset + wcp->alloc_size) ) {
+
+ /*
+ * Non-contiguous write part of which fits within
+ * the cache buffer and is extending the file.
+ */
+
+ size_t data_used;
+
+ if(pos + n <= wcp->offset + wcp->alloc_size)
+ data_used = n;
+ else
+ data_used = wcp->offset + wcp->alloc_size - pos;
+
+ /*
+ * Fill in the non-continuous area with zeros.
+ */
+
+ memset(wcp->data + wcp->data_size, '\0',
+ pos - (wcp->offset + wcp->data_size) );
+
+ memcpy(wcp->data + (pos - wcp->offset), data, data_used);
+
+ /*
+ * Update the current buffer size with the new data.
+ */
+
+ if(pos + data_used > wcp->offset + wcp->data_size)
+ wcp->data_size = pos + data_used - wcp->offset;
+
+ /*
+ * Update the known file length.
+ */
+
+ wcp->file_size = wcp->offset + wcp->data_size;
+
+#if 0
+ if (set_filelen(fsp->fd_ptr->fd, wcp->file_size) == -1) {
+ DEBUG(0,("write_file: error %s in setting file to length %.0f\n",
+ strerror(errno), (double)wcp->file_size ));
+ return -1;
+ }
+#endif
+
+ /*
+ * If we used all the data then
+ * return here.
+ */
+
+ if(n == data_used)
+ return n;
+ else
+ cache_flush_needed = True;
+
+ /*
+ * Move the start of data forward by the amount used,
+ * cut down the amount left by the same amount.
+ */
+
+ data += data_used;
+ pos += data_used;
+ n -= data_used;
+
+ abutted_writes++;
+ total_written = data_used;
+
+ write_path = 3;
+
+ } else {
+
+ /*
+ * Write is bigger than buffer, or there is no overlap on the
+ * low or high ends.
+ */
+
+ DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \
+len = %u\n",fsp->fd_ptr->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size ));
+
+ /*
+ * Update the file size if needed.
+ */
+
+ if(pos + n > wcp->file_size)
+ wcp->file_size = pos + n;
+
+ /*
+ * If write would fit in the cache, and is larger than
+ * the data already in the cache, flush the cache and
+ * preferentially copy the data new data into it. Otherwise
+ * just write the data directly.
+ */
+
+ if ( n <= wcp->alloc_size && n > wcp->data_size) {
+ cache_flush_needed = True;
+ } else {
+ direct_writes++;
+ return real_write_file(fsp, data, pos, n);
+ }
+
+ write_path = 4;
+
+ }
+
+ if(wcp->data_size > wcp->file_size)
+ wcp->file_size = wcp->data_size;
+
+ if (cache_flush_needed) {
+ flushed_writes++;
+
+ DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \
+n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
+ write_path, fsp->fd_ptr->fd, (double)wcp->file_size, (double)pos, (unsigned int)n,
+ (double)wcp->offset, (unsigned int)wcp->data_size ));
+
+ flush_write_cache(fsp, WRITE_FLUSH);
+ }
+ }
+
+ /*
+ * If the write request is bigger than the cache
+ * size, write it all out.
+ */
+
+ if (n > wcp->alloc_size ) {
+ if(real_write_file(fsp, data, pos, n) == -1)
+ return -1;
+ direct_writes++;
+ return total_written + n;
+ }
+
+ /*
+ * If there's any data left, cache it.
+ */
+
+ if (n) {
+ if (wcp->data_size) {
+ abutted_writes++;
+ DEBUG(9,("abutted write (%u)\n", abutted_writes));
+ } else {
+ init_writes++;
+ }
+ memcpy(wcp->data+wcp->data_size, data, n);
+ if (wcp->data_size == 0) {
+ wcp->offset = pos;
+ num_write_caches++;
+ }
+ wcp->data_size += n;
+ DEBUG(9,("cache return %u\n", (unsigned int)n));
+ total_written += n;
+ return total_written; /* .... that's a write :) */
+ }
+
+ return total_written;
}
+/****************************************************************************
+ Delete the write cache structure.
+****************************************************************************/
+void delete_write_cache(files_struct *fsp)
+{
+ write_cache *wcp;
+
+ if(!fsp)
+ return;
+
+ if(!(wcp = fsp->wcp))
+ return;
+
+ allocated_write_caches--;
+
+ SMB_ASSERT(wcp->data_size == 0);
+
+ free(wcp->data);
+ free(wcp);
+
+ fsp->wcp = NULL;
+}
+
+/****************************************************************************
+ Setup the write cache structure.
+****************************************************************************/
+
+static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size)
+{
+ ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn));
+ write_cache *wcp;
+
+ if (allocated_write_caches >= MAX_WRITE_CACHES) return False;
+
+ if(alloc_size == 0 || fsp->wcp)
+ return False;
+
+ if((wcp = (write_cache *)malloc(sizeof(write_cache))) == NULL) {
+ DEBUG(0,("setup_write_cache: malloc fail.\n"));
+ return False;
+ }
+
+ wcp->file_size = file_size;
+ wcp->offset = 0;
+ wcp->alloc_size = alloc_size;
+ wcp->data_size = 0;
+ if((wcp->data = malloc(wcp->alloc_size)) == NULL) {
+ DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n",
+ (unsigned int)wcp->alloc_size ));
+ free(wcp);
+ return False;
+ }
+
+ fsp->wcp = wcp;
+ allocated_write_caches++;
+
+ return True;
+}
+
+/****************************************************************************
+ Cope with a size change.
+****************************************************************************/
+
+void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size)
+{
+ if(fsp->wcp) {
+ flush_write_cache(fsp, SIZECHANGE_FLUSH);
+ fsp->wcp->file_size = file_size;
+ }
+}
+
+/*******************************************************************
+ Flush a write cache struct to disk.
+********************************************************************/
+
+ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason)
+{
+ write_cache *wcp = fsp->wcp;
+ size_t data_size;
+
+ if(!wcp || !wcp->data_size)
+ return 0;
+
+ data_size = wcp->data_size;
+ wcp->data_size = 0;
+
+ num_write_caches--;
+
+ flush_reasons[(int)reason]++;
+
+ DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n",
+ fsp->fd_ptr->fd, (double)wcp->offset, (unsigned int)data_size));
+
+ if(data_size == wcp->alloc_size)
+ num_perfect_writes++;
+
+ return real_write_file(fsp, wcp->data, wcp->offset, data_size);
+}
/*******************************************************************
sync a file
********************************************************************/
-void sys_sync_file(int fd)
+void sync_file(connection_struct *conn, files_struct *fsp)
{
#ifdef HAVE_FSYNC
- fsync(fd);
+ if(lp_strict_sync(SNUM(conn)) && fsp->fd_ptr != NULL) {
+ flush_write_cache(fsp, SYNC_FLUSH);
+ fsync(fsp->fd_ptr->fd);
+ }
#endif
}
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 1d9c5ef754..64f63805f3 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -26,7 +26,6 @@ extern BOOL case_sensitive;
extern BOOL case_preserve;
extern BOOL short_case_preserve;
extern fstring remote_machine;
-extern pstring global_myname;
extern BOOL use_mangled_map;
static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache);
@@ -97,7 +96,12 @@ static int global_stat_cache_hits;
void print_stat_cache_statistics(void)
{
- double eff = (100.0* (double)global_stat_cache_hits)/(double)global_stat_cache_lookups;
+ double eff;
+
+ if(global_stat_cache_lookups == 0)
+ return;
+
+ eff = (100.0* (double)global_stat_cache_hits)/(double)global_stat_cache_lookups;
DEBUG(0,("stat cache stats: lookups = %d, hits = %d, misses = %d, \
stat cache was %f%% effective.\n", global_stat_cache_lookups,
@@ -230,9 +234,7 @@ static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
Return True if we translated (and did a scuccessful stat on) the entire name.
*****************************************************************************/
-static BOOL stat_cache_lookup(struct connection_struct *conn, char *name,
- char *dirpath, char **start,
- SMB_STRUCT_STAT *pst)
+static BOOL stat_cache_lookup( char *name, char *dirpath, char **start, SMB_STRUCT_STAT *pst)
{
stat_cache_entry *scp;
stat_cache_entry *longest_hit = NULL;
@@ -285,7 +287,7 @@ static BOOL stat_cache_lookup(struct connection_struct *conn, char *name,
* and then promote it to the top.
*/
- if(conn->vfs_ops.stat(longest_hit->translated_name, pst) != 0) {
+ if(dos_stat( longest_hit->translated_name, pst) != 0) {
/*
* Discard this entry.
*/
@@ -310,35 +312,6 @@ static BOOL stat_cache_lookup(struct connection_struct *conn, char *name,
}
/****************************************************************************
- this routine converts from the dos and dfs namespace to the unix namespace.
-****************************************************************************/
-BOOL unix_dfs_convert(char *name,connection_struct *conn,
- char *saved_last_component,
- BOOL *bad_path, SMB_STRUCT_STAT *pst)
-{
- pstring local_path;
-
- DEBUG(10,("unix_dfs_convert: %s\n", name));
-
- if (name != NULL &&
- under_dfs(conn, name, local_path, sizeof(local_path)))
- {
- DEBUG(10,("%s is in dfs map.\n", name));
-
- /* check for our own name */
- if (StrCaseCmp(global_myname, name+1) > 0)
- {
- return False;
- }
-
- pstrcpy(name, local_path);
-
- DEBUG(10,("removed name: %s\n", name));
- }
- return unix_convert(name, conn, saved_last_component, bad_path, pst);
-}
-
-/****************************************************************************
This routine is called to convert names from the dos namespace to unix
namespace. It needs to handle any case conversions, mangling, format
changes etc.
@@ -359,15 +332,14 @@ used to pick the correct error code to return between ENOENT and ENOTDIR
as Windows applications depend on ERRbadpath being returned if a component
of a pathname does not exist.
****************************************************************************/
-BOOL unix_convert(char *name,connection_struct *conn,
- char *saved_last_component,
- BOOL *bad_path, SMB_STRUCT_STAT *pst)
+
+BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
+ BOOL *bad_path, SMB_STRUCT_STAT *pst)
{
SMB_STRUCT_STAT st;
char *start, *end;
pstring dirpath;
pstring orig_path;
- int saved_errno;
BOOL component_was_mangled = False;
BOOL name_has_wildcard = False;
#if 0
@@ -443,7 +415,7 @@ BOOL unix_convert(char *name,connection_struct *conn,
for (s=name2 ; *s ; s++)
if (!issafe(*s)) *s = '_';
- pstrcpy(name,(char *)mktemp(name2));
+ pstrcpy(name,(char *)smbd_mktemp(name2));
}
return(True);
}
@@ -463,7 +435,7 @@ BOOL unix_convert(char *name,connection_struct *conn,
pstrcpy(orig_path, name);
- if(stat_cache_lookup(conn, name, dirpath, &start, &st)) {
+ if(stat_cache_lookup( name, dirpath, &start, &st)) {
if(pst)
*pst = st;
return True;
@@ -473,7 +445,7 @@ BOOL unix_convert(char *name,connection_struct *conn,
* stat the name - if it exists then we are all done!
*/
- if (conn->vfs_ops.stat(name,&st) == 0) {
+ if (dos_stat(name,&st) == 0) {
stat_cache_add(orig_path, name);
DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
if(pst)
@@ -481,8 +453,6 @@ BOOL unix_convert(char *name,connection_struct *conn,
return(True);
}
- saved_errno = errno;
-
DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
name, dirpath, start));
@@ -492,7 +462,7 @@ BOOL unix_convert(char *name,connection_struct *conn,
*/
if (case_sensitive && !is_mangled(name) &&
- !lp_strip_dot() && !use_mangled_map && (saved_errno != ENOENT))
+ !lp_strip_dot() && !use_mangled_map)
return(False);
if(strchr(start,'?') || strchr(start,'*'))
@@ -541,8 +511,7 @@ BOOL unix_convert(char *name,connection_struct *conn,
/*
* Check if the name exists up to this point.
*/
-
- if (conn->vfs_ops.stat(name, &st) == 0) {
+ if (dos_stat(name, &st) == 0) {
/*
* It exists. it must either be a directory or this must be
* the last part of the path for it to be OK.
@@ -694,7 +663,7 @@ BOOL check_name(char *name,connection_struct *conn)
if (!lp_symlinks(SNUM(conn)))
{
SMB_STRUCT_STAT statbuf;
- if ( (conn->vfs_ops.lstat(dos_to_unix(name,False),&statbuf) != -1) &&
+ if ( (dos_lstat(name,&statbuf) != -1) &&
(S_ISLNK(statbuf.st_mode)) )
{
DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
@@ -758,7 +727,8 @@ static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL d
continue;
pstrcpy(name2,dname);
- if (!name_map_mangle(name2,False,SNUM(conn))) continue;
+ if (!name_map_mangle(name2,False,True,SNUM(conn)))
+ continue;
if ((mangled && mangled_equal(name,name2))
|| fname_equal(name, name2))
diff --git a/source3/smbd/files.c b/source3/smbd/files.c
index 7f4533e7ae..d6203580cf 100644
--- a/source3/smbd/files.c
+++ b/source3/smbd/files.c
@@ -186,10 +186,7 @@ void file_close_conn(connection_struct *conn)
for (fsp=Files;fsp;fsp=next) {
next = fsp->next;
if (fsp->conn == conn && fsp->open) {
- if (fsp->is_directory)
- close_directory(fsp);
- else
- close_file(fsp,False);
+ close_file(fsp,False);
}
}
}
@@ -226,7 +223,7 @@ open files, %d are available.\n", request_max_open_files, real_max_open_files));
}
/*
- * Ensure that pipe_handle_offset is set correctly.
+ * Ensure that pipe_handle_oppset is set correctly.
*/
set_pipe_handle_offset(real_max_open_files);
}
@@ -242,10 +239,7 @@ void file_close_user(int vuid)
for (fsp=Files;fsp;fsp=next) {
next=fsp->next;
if ((fsp->vuid == vuid) && fsp->open) {
- if(!fsp->is_directory)
- close_file(fsp,False);
- else
- close_directory(fsp);
+ close_file(fsp,False);
}
}
}
@@ -340,13 +334,13 @@ void file_sync_all(connection_struct *conn)
for (fsp=Files;fsp;fsp=next) {
next=fsp->next;
- if (fsp->open && (conn == fsp->conn) && (fsp->fd_ptr != NULL)
- && lp_strict_sync(SNUM(conn))){
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
+ if (fsp->open && (conn == fsp->conn) && (fsp->fd_ptr != NULL)) {
+ sync_file(conn,fsp);
}
}
}
+
/****************************************************************************
free up a fd_ptr
****************************************************************************/
diff --git a/source3/smbd/groupname.c b/source3/smbd/groupname.c
index 0be558848a..4dadfaa939 100644
--- a/source3/smbd/groupname.c
+++ b/source3/smbd/groupname.c
@@ -19,4 +19,225 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* this module is retired, it is moved to lib/domain_namemap.c */
+#ifdef USING_GROUPNAME_MAP
+
+#include "includes.h"
+extern int DEBUGLEVEL;
+extern DOM_SID global_sam_sid;
+
+
+/**************************************************************************
+ Groupname map functionality. The code loads a groupname map file and
+ (currently) loads it into a linked list. This is slow and memory
+ hungry, but can be changed into a more efficient storage format
+ if the demands on it become excessive.
+***************************************************************************/
+
+typedef struct groupname_map {
+ ubi_slNode next;
+
+ char *windows_name;
+ DOM_SID windows_sid;
+ char *unix_name;
+ gid_t unix_gid;
+} groupname_map_entry;
+
+static ubi_slList groupname_map_list;
+
+/**************************************************************************
+ Delete all the entries in the groupname map list.
+***************************************************************************/
+
+static void delete_groupname_map_list(void)
+{
+ groupname_map_entry *gmep;
+
+ while((gmep = (groupname_map_entry *)ubi_slRemHead( &groupname_map_list )) != NULL) {
+ if(gmep->windows_name)
+ free(gmep->windows_name);
+ if(gmep->unix_name)
+ free(gmep->unix_name);
+ free((char *)gmep);
+ }
+}
+
+/**************************************************************************
+ Load a groupname map file. Sets last accessed timestamp.
+***************************************************************************/
+
+void load_groupname_map(void)
+{
+ static time_t groupmap_file_last_modified = (time_t)0;
+ static BOOL initialized = False;
+ char *groupname_map_file = lp_groupname_map();
+ SMB_STRUCT_STAT st;
+ FILE *fp;
+ char *s;
+ pstring buf;
+ groupname_map_entry *new_ep;
+
+ if(!initialized) {
+ ubi_slInitList( &groupname_map_list );
+ initialized = True;
+ }
+
+ if (!*groupname_map_file)
+ return;
+
+ if(sys_stat(groupname_map_file, &st) != 0) {
+ DEBUG(0, ("load_groupname_map: Unable to stat file %s. Error was %s\n",
+ groupname_map_file, strerror(errno) ));
+ return;
+ }
+
+ /*
+ * Check if file has changed.
+ */
+ if( st.st_mtime <= groupmap_file_last_modified)
+ return;
+
+ groupmap_file_last_modified = st.st_mtime;
+
+ /*
+ * Load the file.
+ */
+
+ fp = sys_fopen(groupname_map_file,"r");
+ if (!fp) {
+ DEBUG(0,("load_groupname_map: can't open groupname map %s. Error was %s\n",
+ groupname_map_file, strerror(errno)));
+ return;
+ }
+
+ /*
+ * Throw away any previous list.
+ */
+ delete_groupname_map_list();
+
+ DEBUG(4,("load_groupname_map: Scanning groupname map %s\n",groupname_map_file));
+
+ while((s=fgets_slash(buf,sizeof(buf),fp))!=NULL) {
+ pstring unixname;
+ pstring windows_name;
+ struct group *gptr;
+ DOM_SID tmp_sid;
+
+ DEBUG(10,("load_groupname_map: Read line |%s|\n", s));
+
+ if (!*s || strchr("#;",*s))
+ continue;
+
+ if(!next_token(&s,unixname, "\t\n\r=", sizeof(unixname)))
+ continue;
+
+ if(!next_token(&s,windows_name, "\t\n\r=", sizeof(windows_name)))
+ continue;
+
+ trim_string(unixname, " ", " ");
+ trim_string(windows_name, " ", " ");
+
+ if (!*windows_name)
+ continue;
+
+ if(!*unixname)
+ continue;
+
+ DEBUG(5,("load_groupname_map: unixname = %s, windowsname = %s.\n",
+ unixname, windows_name));
+
+ /*
+ * Attempt to get the unix gid_t for this name.
+ */
+
+ if((gptr = (struct group *)getgrnam(unixname)) == NULL) {
+ DEBUG(0,("load_groupname_map: getgrnam for group %s failed.\
+Error was %s.\n", unixname, strerror(errno) ));
+ continue;
+ }
+
+ /*
+ * Now map to an NT SID.
+ */
+
+ if(!lookup_wellknown_sid_from_name(windows_name, &tmp_sid)) {
+ /*
+ * It's not a well known name, convert the UNIX gid_t
+ * to a rid within this domain SID.
+ */
+ tmp_sid = global_sam_sid;
+ tmp_sid.sub_auths[tmp_sid.num_auths++] =
+ pdb_gid_to_group_rid((gid_t)gptr->gr_gid);
+ }
+
+ /*
+ * Create the list entry and add it onto the list.
+ */
+
+ if((new_ep = (groupname_map_entry *)malloc( sizeof(groupname_map_entry) ))== NULL) {
+ DEBUG(0,("load_groupname_map: malloc fail for groupname_map_entry.\n"));
+ fclose(fp);
+ return;
+ }
+
+ new_ep->unix_gid = gptr->gr_gid;
+ new_ep->windows_sid = tmp_sid;
+ new_ep->windows_name = strdup( windows_name );
+ new_ep->unix_name = strdup( unixname );
+
+ if(new_ep->windows_name == NULL || new_ep->unix_name == NULL) {
+ DEBUG(0,("load_groupname_map: malloc fail for names in groupname_map_entry.\n"));
+ fclose(fp);
+ if(new_ep->windows_name != NULL)
+ free(new_ep->windows_name);
+ if(new_ep->unix_name != NULL)
+ free(new_ep->unix_name);
+ free((char *)new_ep);
+ return;
+ }
+ memset((char *)&new_ep->next, '\0', sizeof(new_ep->next) );
+
+ ubi_slAddHead( &groupname_map_list, (ubi_slNode *)new_ep);
+ }
+
+ DEBUG(10,("load_groupname_map: Added %ld entries to groupname map.\n",
+ ubi_slCount(&groupname_map_list)));
+
+ fclose(fp);
+}
+
+/***********************************************************
+ Lookup a SID entry by gid_t.
+************************************************************/
+
+void map_gid_to_sid( gid_t gid, DOM_SID *psid)
+{
+ groupname_map_entry *gmep;
+
+ /*
+ * Initialize and load if not already loaded.
+ */
+ load_groupname_map();
+
+ for( gmep = (groupname_map_entry *)ubi_slFirst( &groupname_map_list);
+ gmep; gmep = (groupname_map_entry *)ubi_slNext( gmep )) {
+
+ if( gmep->unix_gid == gid) {
+ *psid = gmep->windows_sid;
+ DEBUG(7,("map_gid_to_sid: Mapping unix group %s to windows group %s.\n",
+ gmep->unix_name, gmep->windows_name ));
+ return;
+ }
+ }
+
+ /*
+ * If there's no map, convert the UNIX gid_t
+ * to a rid within this domain SID.
+ */
+ *psid = global_sam_sid;
+ psid->sub_auths[psid->num_auths++] = pdb_gid_to_group_rid(gid);
+
+ return;
+}
+#else /* USING_GROUPNAME_MAP */
+ void load_groupname_map(void) {;}
+#endif /* USING_GROUPNAME_MAP */
diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c
index eeb367bcb5..4e9418fa94 100644
--- a/source3/smbd/ipc.c
+++ b/source3/smbd/ipc.c
@@ -61,7 +61,6 @@ extern fstring global_myworkgroup;
extern int Client;
extern int smb_read_error;
-extern uint32 global_client_caps;
static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
@@ -82,7 +81,7 @@ static int CopyExpanded(connection_struct *conn,
if (!src || !dst || !n || !(*dst)) return(0);
StrnCpy(buf,src,sizeof(buf)/2);
- string_sub(buf,"%S",lp_servicename(snum));
+ pstring_sub(buf,"%S",lp_servicename(snum));
standard_sub(conn,buf);
StrnCpy(*dst,buf,*n);
l = strlen(*dst) + 1;
@@ -95,7 +94,7 @@ static int CopyAndAdvance(char** dst, char* src, int* n)
{
int l;
if (!src || !dst || !n || !(*dst)) return(0);
- StrnCpy(*dst,src,*n);
+ StrnCpy(*dst,src,*n-1);
l = strlen(*dst) + 1;
(*dst) += l;
(*n) -= l;
@@ -107,7 +106,7 @@ static int StrlenExpanded(connection_struct *conn, int snum, char* s)
pstring buf;
if (!s) return(0);
StrnCpy(buf,s,sizeof(buf)/2);
- string_sub(buf,"%S",lp_servicename(snum));
+ pstring_sub(buf,"%S",lp_servicename(snum));
standard_sub(conn,buf);
return strlen(buf) + 1;
}
@@ -117,7 +116,7 @@ static char* Expand(connection_struct *conn, int snum, char* s)
static pstring buf;
if (!s) return(NULL);
StrnCpy(buf,s,sizeof(buf)/2);
- string_sub(buf,"%S",lp_servicename(snum));
+ pstring_sub(buf,"%S",lp_servicename(snum));
standard_sub(conn,buf);
return &buf[0];
}
@@ -139,70 +138,69 @@ static BOOL prefix_ok(char *str,char *prefix)
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)
+ char *rparam, int param_offset, int param_len,
+ char *rdata, int data_offset, int data_len)
{
char *copy_into = smb_buf(outbuf)+1;
+ if(param_len < 0)
+ param_len = 0;
+
+ if(data_len < 0)
+ data_len = 0;
+
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);
+ if (param_len)
+ memcpy(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);
+
+ if (data_len )
+ memcpy(copy_into, &rdata[data_offset], data_len);
}
/****************************************************************************
- send a trans reply
- ****************************************************************************/
+ Send a trans reply.
+ ****************************************************************************/
+
static void send_trans_reply(char *outbuf,
- struct mem_buf *rdata,
- struct mem_buf *rparam,
- uint16 *setup, int lsetup, int max_data_ret)
+ char *rparam, int rparam_len,
+ char *rdata, int rdata_len,
+ BOOL buffer_too_large)
{
- int i;
int this_ldata,this_lparam;
- int tot_data=0,tot_param=0;
+ int tot_data_sent = 0;
+ int tot_param_sent = 0;
int align;
- int ldata = rdata ? mem_buf_len(rdata ) : 0;
- int lparam = rparam ? mem_buf_len(rparam) : 0;
-
- BOOL buffer_too_large = max_data_ret ? ldata > max_data_ret : False;
+ int ldata = rdata ? rdata_len : 0;
+ int lparam = rparam ? rparam_len : 0;
if (buffer_too_large)
- {
- DEBUG(5,("send_trans_reply: buffer %d too large %d\n", ldata, max_data_ret));
- ldata = max_data_ret;
- }
+ DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
- this_lparam = MIN(lparam,max_send - (500+lsetup*SIZEOFWORD)); /* hack */
- this_ldata = MIN(ldata,max_send - (500+lsetup*SIZEOFWORD+this_lparam));
+ this_lparam = MIN(lparam,max_send - 500); /* hack */
+ this_ldata = MIN(ldata,max_send - (500+this_lparam));
align = ((this_lparam)%4);
- set_message(outbuf,10+lsetup,1+align+this_ldata+this_lparam,True);
+ set_message(outbuf,10,1+align+this_ldata+this_lparam,True);
if (buffer_too_large)
{
- if (global_client_caps & CAP_STATUS32)
- {
- /* 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, 0x80000005); /* STATUS_BUFFER_OVERFLOW */
- } else {
- SCVAL(outbuf, smb_rcls, ERRDOS);
- SSVAL(outbuf, smb_err, ERRmoredata);
- }
+ /* 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);
+ rparam, tot_param_sent, this_lparam,
+ rdata, tot_data_sent, this_ldata);
SSVAL(outbuf,smb_vwv0,lparam);
SSVAL(outbuf,smb_vwv1,ldata);
@@ -212,46 +210,46 @@ static void send_trans_reply(char *outbuf,
SSVAL(outbuf,smb_vwv6,this_ldata);
SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
SSVAL(outbuf,smb_vwv8,0);
- SSVAL(outbuf,smb_vwv9,lsetup);
-
- for (i=0;i<lsetup;i++)
- {
- SSVAL(outbuf,smb_vwv10+i*SIZEOFWORD,setup[i]);
- }
+ SSVAL(outbuf,smb_vwv9,0);
show_msg(outbuf);
send_smb(Client,outbuf);
- tot_data = this_ldata;
- tot_param = this_lparam;
+ tot_data_sent = this_ldata;
+ tot_param_sent = this_lparam;
- while (tot_data < ldata || tot_param < lparam)
+ while (tot_data_sent < ldata || tot_param_sent < lparam)
{
- this_lparam = MIN(lparam-tot_param, max_send - 500); /* hack */
- this_ldata = MIN(ldata -tot_data , max_send - (500+this_lparam));
+ this_lparam = MIN(lparam-tot_param_sent, max_send - 500); /* hack */
+ this_ldata = MIN(ldata -tot_data_sent, max_send - (500+this_lparam));
+
+ if(this_lparam < 0)
+ this_lparam = 0;
+
+ if(this_ldata < 0)
+ this_ldata = 0;
align = (this_lparam%4);
set_message(outbuf,10,1+this_ldata+this_lparam+align,False);
copy_trans_params_and_data(outbuf, align,
- rparam , rdata,
- tot_param , tot_data,
- this_lparam, this_ldata);
+ rparam, tot_param_sent, this_lparam,
+ rdata, tot_data_sent, this_ldata);
SSVAL(outbuf,smb_vwv3,this_lparam);
SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
- SSVAL(outbuf,smb_vwv5,tot_param);
+ SSVAL(outbuf,smb_vwv5,tot_param_sent);
SSVAL(outbuf,smb_vwv6,this_ldata);
SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
- SSVAL(outbuf,smb_vwv8,tot_data);
+ SSVAL(outbuf,smb_vwv8,tot_data_sent);
SSVAL(outbuf,smb_vwv9,0);
show_msg(outbuf);
send_smb(Client,outbuf);
- tot_data += this_ldata;
- tot_param += this_lparam;
+ tot_data_sent += this_ldata;
+ tot_param_sent += this_lparam;
}
}
@@ -378,7 +376,10 @@ va_dcl
#endif
stringneeded = -1;
- if (!p->curpos) return(0);
+ if (!p->curpos) {
+ va_end(args);
+ return(0);
+ }
switch( *p->curpos++ ) {
case 'W': /* word (2 byte) */
@@ -400,7 +401,7 @@ va_dcl
needed = get_counter(&p->curpos);
{
char *s = va_arg(args,char*);
- if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed);
+ if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
}
break;
case 'z': /* offset to zero terminated string (4 byte) */
@@ -656,7 +657,7 @@ static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
return;
}
- bzero(p, 8192*sizeof(char));
+ memset(p, '\0',8192*sizeof(char));
q=p;
/* lookup the long printer driver name in the file description */
@@ -809,8 +810,8 @@ static BOOL api_DosPrintQGetInfo(connection_struct *conn,
print_queue_struct *queue=NULL;
print_status_struct status;
- bzero(&status,sizeof(status));
- bzero(&desc,sizeof(desc));
+ memset((char *)&status,'\0',sizeof(status));
+ memset((char *)&desc,'\0',sizeof(desc));
p = skip_string(p,1);
uLevel = SVAL(p,0);
@@ -823,7 +824,20 @@ static BOOL api_DosPrintQGetInfo(connection_struct *conn,
/* check it's a supported varient */
if (!prefix_ok(str1,"zWrLh")) return False;
- if (!check_printq_info(&desc,uLevel,str2,str3)) return False;
+ if (!check_printq_info(&desc,uLevel,str2,str3)) {
+ /*
+ * Patch from Scott Moomaw <scott@bridgewater.edu>
+ * to return the 'invalid info level' error if an
+ * unknown level was requested.
+ */
+ *rdata_len = 0;
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,0);
+ return(True);
+ }
snum = lp_servicenumber(QueueName);
if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
@@ -908,13 +922,26 @@ static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param,
int* subcntarr = NULL;
int queuecnt, subcnt=0, succnt=0;
- bzero(&desc,sizeof(desc));
+ memset((char *)&desc,'\0',sizeof(desc));
DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
if (!prefix_ok(param_format,"WrLeh")) return False;
- if (!check_printq_info(&desc,uLevel,output_format1,output_format2))
- return False;
+ if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) {
+ /*
+ * Patch from Scott Moomaw <scott@bridgewater.edu>
+ * to return the 'invalid info level' error if an
+ * unknown level was requested.
+ */
+ *rdata_len = 0;
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
+ SSVALS(*rparam,0,ERROR_INVALID_LEVEL);
+ SSVAL(*rparam,2,0);
+ SSVAL(*rparam,4,0);
+ return(True);
+ }
+
queuecnt = 0;
for (i = 0; i < services; i++)
if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
@@ -1057,7 +1084,7 @@ static int get_server_info(uint32 servertype,
(*servers) = (struct srv_info_struct *)
Realloc(*servers,sizeof(**servers)*alloced);
if (!(*servers)) return(0);
- bzero((char *)((*servers)+count),sizeof(**servers)*(alloced-count));
+ memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
}
s = &(*servers)[count];
@@ -1297,7 +1324,7 @@ static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param
*rdata_len = fixed_len + string_len;
*rdata = REALLOC(*rdata,*rdata_len);
- bzero(*rdata,*rdata_len);
+ memset(*rdata,'\0',*rdata_len);
p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
p = *rdata;
@@ -1355,7 +1382,6 @@ static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *pa
if (!prefix_ok(str1,"zWrLeh")) return False;
*rdata_len = 0;
- *rdata = NULL;
*rparam_len = 8;
*rparam = REALLOC(*rparam,*rparam_len);
@@ -1650,6 +1676,8 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param
p = skip_string(p,1);
+ memset(pass1,'\0',sizeof(pass1));
+ memset(pass2,'\0',sizeof(pass2));
memcpy(pass1,p,16);
memcpy(pass2,p+16,16);
@@ -1680,7 +1708,7 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param
* Older versions of Windows seem to do this.
*/
- if (password_ok(user, pass1,strlen(pass1),NULL, NULL) &&
+ if (password_ok(user, pass1,strlen(pass1),NULL) &&
chgpasswd(user,pass1,pass2,False))
{
SSVAL(*rparam,0,NERR_Success);
@@ -1703,8 +1731,8 @@ static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param
}
}
- bzero(pass1,sizeof(fstring));
- bzero(pass2,sizeof(fstring));
+ memset((char *)pass1,'\0',sizeof(fstring));
+ memset((char *)pass2,'\0',sizeof(fstring));
return(True);
}
@@ -2005,7 +2033,7 @@ static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,cha
!become_service(fconn,True))
break;
- if (conn->vfs_ops.rename(dos_to_unix(fsp->fsp_name,False),name) == 0) {
+ if (dos_rename(fsp->fsp_name,name) == 0) {
string_set(&fsp->fsp_name,name);
}
break;
@@ -2091,7 +2119,7 @@ static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *par
pstring comment;
uint32 servertype= lp_default_server_announce();
- pstrcpy(comment,lp_serverstring());
+ pstrcpy(comment,string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
for (i=0;i<count;i++)
@@ -2450,7 +2478,7 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param
SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
SIVALS(p,usri11_password_age,-1); /* password age */
SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
- pstrcpy(p2, lp_logon_path());
+ pstrcpy(p2, lp_logon_home());
p2 = skip_string(p2,1);
SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
pstrcpy(p2,"");
@@ -2486,12 +2514,15 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param
SSVAL(p,42,
conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
- pstrcpy(p2,lp_logon_path());
+ pstrcpy(p2,lp_logon_home());
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 */
+ SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */
+ pstrcpy(p2,lp_logon_script());
+ standard_sub( conn, p2 );
+ p2 = skip_string(p2,1);
if (uLevel == 2)
{
SIVAL(p,60,0); /* auth_flags */
@@ -2590,12 +2621,11 @@ static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param
int uLevel;
struct pack_desc desc;
char* name;
- char* logon_script;
uLevel = SVAL(p,0);
name = p + 2;
- bzero(&desc,sizeof(desc));
+ memset((char *)&desc,'\0',sizeof(desc));
DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
@@ -2636,9 +2666,12 @@ static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param
/* 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();
- standard_sub( conn, logon_script );
- PACKS(&desc,"z", logon_script); /* script path */
+ {
+ pstring logon_script;
+ pstrcpy(logon_script,lp_logon_script());
+ standard_sub( conn, logon_script );
+ PACKS(&desc,"z", logon_script); /* script path */
+ }
/* End of JHT mods */
PACKI(&desc,"D",0x00000000); /* reserved */
@@ -2706,8 +2739,8 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para
uLevel = SVAL(p,2);
- bzero(&desc,sizeof(desc));
- bzero(&status,sizeof(status));
+ memset((char *)&desc,'\0',sizeof(desc));
+ memset((char *)&status,'\0',sizeof(status));
DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
@@ -2767,8 +2800,8 @@ static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *pa
print_queue_struct *queue=NULL;
print_status_struct status;
- bzero(&desc,sizeof(desc));
- bzero(&status,sizeof(status));
+ memset((char *)&desc,'\0',sizeof(desc));
+ memset((char *)&status,'\0',sizeof(status));
p = skip_string(p,1);
uLevel = SVAL(p,0);
@@ -2880,7 +2913,7 @@ static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *par
struct pack_desc desc;
int snum;
- bzero(&desc,sizeof(desc));
+ memset((char *)&desc,'\0',sizeof(desc));
p = skip_string(p,1);
uLevel = SVAL(p,0);
@@ -2939,7 +2972,7 @@ static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,
struct pack_desc desc;
int services = lp_numservices();
- bzero(&desc,sizeof(desc));
+ memset((char *)&desc,'\0',sizeof(desc));
uLevel = SVAL(p,0);
@@ -2994,7 +3027,7 @@ static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *para
int succnt;
struct pack_desc desc;
- bzero(&desc,sizeof(desc));
+ memset((char *)&desc,'\0',sizeof(desc));
uLevel = SVAL(p,0);
@@ -3038,7 +3071,7 @@ static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param
int succnt;
struct pack_desc desc;
- bzero(&desc,sizeof(desc));
+ memset((char *)&desc,'\0',sizeof(desc));
uLevel = SVAL(p,0);
@@ -3083,7 +3116,7 @@ static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,
int succnt;
struct pack_desc desc;
- bzero(&desc,sizeof(desc));
+ memset((char *)&desc,'\0',sizeof(desc));
uLevel = SVAL(p,0);
@@ -3094,7 +3127,7 @@ static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,
if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- bzero(&desc,sizeof(desc));
+ memset((char *)&desc,'\0',sizeof(desc));
desc.base = *rdata;
desc.buflen = mdrcnt;
desc.format = str2;
@@ -3117,35 +3150,48 @@ static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,
return(True);
}
-static void api_rpc_trans_reply(char *outbuf,
- pipes_struct *p)
+/****************************************************************************
+ Start the first part of an RPC reply which began with an SMBtrans request.
+****************************************************************************/
+
+static BOOL api_rpc_trans_reply(char *outbuf, pipes_struct *p)
{
- send_trans_reply(outbuf, p->rsmb_pdu.data, NULL, NULL, 0, p->file_offset);
+ char *rdata = malloc(p->max_trans_reply);
+ int data_len;
- if (mem_buf_len(p->rsmb_pdu.data) <= p->file_offset)
- {
- /* all of data was sent: no need to wait for SMBreadX calls */
- mem_free_data(p->rsmb_pdu.data);
+ if(rdata == NULL) {
+ DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
+ return False;
}
+
+ if((data_len = read_from_pipe( p, rdata, p->max_trans_reply)) < 0) {
+ free(rdata);
+ return False;
+ }
+
+ send_trans_reply(outbuf, NULL, 0, rdata, data_len, (int)prs_offset(&p->rdata) > data_len);
+
+ free(rdata);
+ return True;
}
/****************************************************************************
WaitNamedPipeHandleState
****************************************************************************/
-static BOOL api_WNPHS(char *outbuf, pipes_struct *p, char *param)
+
+static BOOL api_WNPHS(char *outbuf, pipes_struct *p, char *param, int param_len)
{
uint16 priority;
- if (!param) return False;
+ if (!param || param_len < 2)
+ return False;
- priority = param[0] + (param[1] << 8);
+ priority = SVAL(param,0);
DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority));
- if (wait_rpc_pipe_hnd_state(p, priority))
- {
+ if (wait_rpc_pipe_hnd_state(p, priority)) {
/* now send the reply */
- send_trans_reply(outbuf, NULL, NULL, NULL, 0, p->file_offset);
-
+ send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
return True;
}
return False;
@@ -3155,20 +3201,20 @@ static BOOL api_WNPHS(char *outbuf, pipes_struct *p, char *param)
/****************************************************************************
SetNamedPipeHandleState
****************************************************************************/
-static BOOL api_SNPHS(char *outbuf, pipes_struct *p, char *param)
+
+static BOOL api_SNPHS(char *outbuf, pipes_struct *p, char *param, int param_len)
{
uint16 id;
- if (!param) return False;
+ if (!param || param_len < 2)
+ return False;
- id = param[0] + (param[1] << 8);
+ id = SVAL(param,0);
DEBUG(4,("SetNamedPipeHandleState to code %x\n", id));
- if (set_rpc_pipe_hnd_state(p, id))
- {
+ if (set_rpc_pipe_hnd_state(p, id)) {
/* now send the reply */
- send_trans_reply(outbuf, NULL, NULL, NULL, 0, p->file_offset);
-
+ send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
return True;
}
return False;
@@ -3176,111 +3222,93 @@ static BOOL api_SNPHS(char *outbuf, pipes_struct *p, char *param)
/****************************************************************************
- when no reply is generated, indicate unsupported.
+ 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;
+ char rparam[4];
/* unsupported */
- SSVAL(rparam.data,0,NERR_notsupported);
- SSVAL(rparam.data,2,0); /* converter word */
+ SSVAL(rparam,0,NERR_notsupported);
+ SSVAL(rparam,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);
+ send_trans_reply(outbuf, rparam, 4, NULL, 0, False);
- return(-1);
+ return -1;
}
/****************************************************************************
- handle remote api calls delivered to a named pipe already opened.
- ****************************************************************************/
+ Handle remote api calls delivered to a named pipe already opened.
+ ****************************************************************************/
+
static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
uint16 *setup,char *data,char *params,
int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
{
- BOOL reply = False;
-
- uint16 pnum;
- uint16 subcommand;
+ BOOL reply = False;
pipes_struct *p = NULL;
+ int pnum;
+ int subcommand;
DEBUG(5,("api_fd_reply\n"));
/* First find out the name of this file. */
- if (suwcnt != 2)
- {
+ 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];
- p = get_rpc_pipe(pnum);
+ /*
+ * NB. The setup array has already been transformed
+ * via SVAL and so is in gost byte order.
+ */
+ pnum = ((int)setup[1]) & 0xFFFF;
+ subcommand = ((int)setup[0]) & 0xFFFF;
- if (p != NULL)
- {
- DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)",
- subcommand, p->name, pnum));
+ if(!(p = get_rpc_pipe(pnum))) {
+ DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
+ return api_no_reply(outbuf, mdrcnt);
+ }
- /* record maximum data length that can be transmitted in an SMBtrans */
- p->file_offset = mdrcnt;
- p->prev_pdu_file_offset = 0;
+ DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)", subcommand, p->name, pnum));
- DEBUG(10,("api_fd_reply: p:%p file_offset: %d\n",
- p, p->file_offset));
+ /* record maximum data length that can be transmitted in an SMBtrans */
+ p->max_trans_reply = mdrcnt;
- switch (subcommand)
- {
- case 0x26:
- {
- reply = rpc_to_smb(p, data, tdscnt);
- if (reply)
- {
- api_rpc_trans_reply(outbuf, p);
- }
- break;
- }
- case 0x53:
- {
- /* Wait Named Pipe Handle state */
- reply = api_WNPHS(outbuf, p, params);
- break;
- }
- 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));
+ DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p, p->max_trans_reply));
+
+ switch (subcommand) {
+ case 0x26:
+ /* dce/rpc command */
+ reply = rpc_command(p, data, tdscnt);
+ if (reply)
+ reply = api_rpc_trans_reply(outbuf, p);
+ break;
+ case 0x53:
+ /* Wait Named Pipe Handle state */
+ reply = api_WNPHS(outbuf, p, params, tpscnt);
+ break;
+ case 0x01:
+ /* Set Named Pipe Handle state */
+ reply = api_SNPHS(outbuf, p, params, tpscnt);
+ break;
}
if (!reply)
- {
return api_no_reply(outbuf, mdrcnt);
- }
+
return -1;
}
/****************************************************************************
- the buffer was too small
- ****************************************************************************/
+ The buffer was too small
+ ****************************************************************************/
+
static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
@@ -3300,8 +3328,9 @@ static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *
/****************************************************************************
- the request is not supported
- ****************************************************************************/
+ The request is not supported
+ ****************************************************************************/
+
static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
@@ -3364,14 +3393,13 @@ struct
/****************************************************************************
- handle remote api calls
- ****************************************************************************/
+ Handle remote api calls
+ ****************************************************************************/
+
static int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
{
int api_command;
- struct mem_buf rdata_buf;
- struct mem_buf rparam_buf;
char *rdata = NULL;
char *rparam = NULL;
int rdata_len = 0;
@@ -3379,7 +3407,10 @@ static int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data
BOOL reply=False;
int i;
- SMB_ASSERT(params != 0);
+ if (!params) {
+ DEBUG(0,("ERROR: NULL params in api_reply()\n"));
+ return 0;
+ }
api_command = SVAL(params,0);
@@ -3389,15 +3420,20 @@ static int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data
skip_string(params+2,1),
tdscnt,tpscnt,mdrcnt,mprcnt));
- for (i=0;api_commands[i].name;i++)
- if (api_commands[i].id == api_command && api_commands[i].fn)
- {
+ for (i=0;api_commands[i].name;i++) {
+ if (api_commands[i].id == api_command && api_commands[i].fn) {
DEBUG(3,("Doing %s\n",api_commands[i].name));
break;
- }
+ }
+ }
- rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024);
- rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
+ rdata = (char *)malloc(1024);
+ if (rdata)
+ memset(rdata,'\0',1024);
+
+ rparam = (char *)malloc(1024);
+ if (rparam)
+ memset(rparam,'\0',1024);
if(!rdata || !rparam) {
DEBUG(0,("api_reply: malloc fail !\n"));
@@ -3409,29 +3445,24 @@ static int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data
if (rdata_len > mdrcnt ||
- rparam_len > mprcnt)
- {
+ rparam_len > mprcnt) {
reply = api_TooSmall(conn,vuid,params,data,mdrcnt,mprcnt,
&rdata,&rparam,&rdata_len,&rparam_len);
- }
-
+ }
/* if we get False back then it's actually unsupported */
if (!reply)
api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
&rdata,&rparam,&rdata_len,&rparam_len);
-
- mem_create(&rdata_buf , rdata , 0, rdata_len , 0, False);
- mem_create(&rparam_buf, rparam, 0, rparam_len, 0, False);
-
- /* now send the reply */
- send_trans_reply(outbuf, &rdata_buf, &rparam_buf, NULL, 0, 0);
+ send_trans_reply(outbuf, rparam, rparam_len, rdata, rdata_len, False);
- if (rdata ) free(rdata);
- if (rparam) free(rparam);
+ if (rdata )
+ free(rdata);
+ if (rparam)
+ free(rparam);
- return(-1);
+ return -1;
}
/****************************************************************************
@@ -3445,9 +3476,7 @@ static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *na
DEBUG(3,("named pipe command on <%s> name\n", name));
if (strequal(name,"LANMAN"))
- {
return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
- }
if (strequal(name,"WKSSVC") ||
strequal(name,"SRVSVC") ||
@@ -3460,26 +3489,23 @@ static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *na
}
if (strlen(name) < 1)
- {
return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
- }
if (setup)
- {
DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
- }
return 0;
}
/****************************************************************************
- reply to a SMBtrans
- ****************************************************************************/
+ Reply to a SMBtrans.
+ ****************************************************************************/
+
int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
{
fstring name;
- int name_offset = 0;
+ int name_offset = 0;
char *data=NULL,*params=NULL;
uint16 *setup=NULL;
int outsize = 0;
@@ -3497,7 +3523,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
int dsoff = SVAL(inbuf,smb_vwv12);
int suwcnt = CVAL(inbuf,smb_vwv13);
- bzero(name, sizeof(name));
+ memset(name, '\0',sizeof(name));
fstrcpy(name,smb_buf(inbuf));
if (dscnt > tdscnt || pscnt > tpscnt) {
@@ -3523,7 +3549,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
if (suwcnt) {
int i;
if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) {
- DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", suwcnt * sizeof(uint16)));
+ DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", (int)(suwcnt * sizeof(uint16))));
return(ERROR(ERRDOS,ERRnomem));
}
for (i=0;i<suwcnt;i++)
@@ -3546,16 +3572,19 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
- if ((ret && (CVAL(inbuf, smb_com) != SMBtrans)) || !ret) {
+ if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !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);
+ if (params)
+ free(params);
+ if (data)
+ free(data);
+ if (setup)
+ free(setup);
return(ERROR(ERRSRV,ERRerror));
}
@@ -3589,14 +3618,13 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",
name,tdscnt,tpscnt,suwcnt));
- /*
- * WinCE wierdness....
- */
+ /*
+ * WinCE wierdness....
+ */
- if (name[0] == '\\' && (StrnCaseCmp(&name[1],local_machine,
- strlen(local_machine)) == 0)) {
- name_offset = strlen(local_machine)+1;
- }
+ if (name[0] == '\\' && (StrnCaseCmp(&name[1],local_machine, strlen(local_machine)) == 0) &&
+ (name[strlen(local_machine)+1] == '\\'))
+ name_offset = strlen(local_machine)+1;
if (strncmp(&name[name_offset],"\\PIPE\\",strlen("\\PIPE\\")) == 0) {
DEBUG(5,("calling named_pipe\n"));
@@ -3609,9 +3637,12 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
}
- if (data) free(data);
- if (params) free(params);
- if (setup) free(setup);
+ if (data)
+ free(data);
+ if (params)
+ free(params);
+ if (setup)
+ free(setup);
if (close_on_completion)
close_cnum(conn,vuid);
diff --git a/source3/smbd/mangle.c b/source3/smbd/mangle.c
index b829746a32..48e16e5332 100644
--- a/source3/smbd/mangle.c
+++ b/source3/smbd/mangle.c
@@ -63,11 +63,13 @@ extern BOOL case_mangle; /* If true, all chars in 8.3 should be same case. */
* global. There is a call to lp_magicchar() in server.c
* that is used to override the initial value.
*
- * basechars - The set of 36 characters used for name mangling. This
+ * MANGLE_BASE - This is the number of characters we use for name mangling.
+ *
+ * basechars - The set characters used for name mangling. This
* is static (scope is this file only).
*
- * base36() - Macro used to select a character from basechars (i.e.,
- * base36(n) will return the nth digit, modulo 36).
+ * mangle() - Macro used to select a character from basechars (i.e.,
+ * mangle(n) will return the nth digit, modulo MANGLE_BASE).
*
* chartest - array 0..255. The index range is the set of all possible
* values of a byte. For each byte value, the content is a
@@ -110,12 +112,13 @@ extern BOOL case_mangle; /* If true, all chars in 8.3 should be same case. */
char magic_char = '~';
-static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
+#define MANGLE_BASE (sizeof(basechars)/sizeof(char)-1)
static unsigned char chartest[256] = { 0 };
static BOOL ct_initialized = False;
-#define base36(V) ((char)(basechars[(V) % 36]))
+#define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
#define BASECHAR_MASK 0xf0
#define ILLEGAL_MASK 0x0f
#define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
@@ -148,7 +151,7 @@ static void init_chartest( void )
char *illegalchars = "*\\/?<>|\":";
unsigned char *s;
- bzero( (char *)chartest, 256 );
+ memset( (char *)chartest, '\0', 256 );
for( s = (unsigned char *)illegalchars; *s; s++ )
chartest[*s] = ILLEGAL_MASK;
@@ -514,7 +517,7 @@ void reset_mangled_cache( void )
*
* If the extension of the raw name maps directly to the
* extension of the mangled name, then we'll store both names
- * *without* extensions. That way, we can provide consistant
+ * *without* extensions. That way, we can provide consistent
* reverse mangling for all names that match. The test here is
* a bit more careful than the one done in earlier versions of
* mangle.c:
@@ -533,9 +536,9 @@ static void cache_mangled_name( char *mangled_name, char *raw_name )
ubi_cacheEntryPtr new_entry;
char *s1;
char *s2;
- int mangled_len;
- int raw_len;
- int i;
+ size_t mangled_len;
+ size_t raw_len;
+ size_t i;
/* If the cache isn't initialized, give up. */
if( !mc_initialized )
@@ -561,7 +564,7 @@ static void cache_mangled_name( char *mangled_name, char *raw_name )
}
}
- /* Allocate a new cache entry. If the allcoation fails, just return. */
+ /* Allocate a new cache entry. If the allocation fails, just return. */
i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2;
new_entry = malloc( i );
if( !new_entry )
@@ -589,11 +592,13 @@ static void cache_mangled_name( char *mangled_name, char *raw_name )
*
* ************************************************************************** **
*/
+
BOOL check_mangled_cache( char *s )
- {
+{
ubi_cacheEntryPtr FoundPtr;
char *ext_start = NULL;
char *found_name;
+ char *saved_ext = NULL;
/* If the cache isn't initialized, give up. */
if( !mc_initialized )
@@ -603,19 +608,34 @@ BOOL check_mangled_cache( char *s )
/* If we didn't find the name *with* the extension, try without. */
if( !FoundPtr )
- {
+ {
ext_start = strrchr( s, '.' );
if( ext_start )
- {
+ {
+ if((saved_ext = strdup(ext_start)) == NULL)
+ return False;
+
*ext_start = '\0';
FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
- *ext_start = '.';
- }
+ /*
+ * At this point s is the name without the
+ * extension. We re-add the extension if saved_ext
+ * is not null, before freeing saved_ext.
+ */
}
+ }
/* Okay, if we haven't found it we're done. */
if( !FoundPtr )
+ {
+ if(saved_ext)
+ {
+ /* Replace the saved_ext as it was truncated. */
+ (void)pstrcat( s, saved_ext );
+ free(saved_ext);
+ }
return( False );
+ }
/* If we *did* find it, we need to copy it into the string buffer. */
found_name = (char *)(FoundPtr + 1);
@@ -624,13 +644,17 @@ BOOL check_mangled_cache( char *s )
DEBUG( 3, ("Found %s on mangled stack ", s) );
(void)pstrcpy( s, found_name );
- if( ext_start )
- (void)pstrcat( s, ext_start );
+ if( saved_ext )
+ {
+ /* Replace the saved_ext as it was truncated. */
+ (void)pstrcat( s, saved_ext );
+ free(saved_ext);
+ }
DEBUG( 3, ("as %s\n", s) );
return( True );
- } /* check_mangled_cache */
+} /* check_mangled_cache */
/* ************************************************************************** **
@@ -652,6 +676,12 @@ static char *map_filename( char *s, /* This is null terminated */
pstrcpy( matching_bit, "" ); /* Match but no star gets this. */
pp = pat; /* Initialize the pointers. */
sp = s;
+
+ if( strequal(s, ".") || strequal(s, ".."))
+ {
+ return NULL; /* Do not map '.' and '..' */
+ }
+
if( (len == 1) && (*pattern == '*') )
{
return NULL; /* Impossible, too ambiguous for */
@@ -807,7 +837,7 @@ static void do_fwd_mangled_map(char *s, char *MangledMap)
*/
void mangle_name_83( char *s)
{
- int csum = str_checksum(s);
+ int csum;
char *p;
char extension[4];
char base[9];
@@ -829,7 +859,11 @@ void mangle_name_83( char *s)
csum = str_checksum( s );
*p = '.';
}
+ else
+ csum = str_checksum(s);
}
+ else
+ csum = str_checksum(s);
strupper( s );
@@ -855,7 +889,7 @@ void mangle_name_83( char *s)
}
else
{
- extension[extlen++] = base36( (unsigned char)*p );
+ extension[extlen++] = mangle( (unsigned char)*p );
}
p += 2;
break;
@@ -889,7 +923,7 @@ void mangle_name_83( char *s)
}
else
{
- base[baselen++] = base36( (unsigned char)*p );
+ base[baselen++] = mangle( (unsigned char)*p );
}
p += 2;
break;
@@ -906,10 +940,10 @@ void mangle_name_83( char *s)
}
base[baselen] = 0;
- csum = csum % (36*36);
+ csum = csum % (MANGLE_BASE*MANGLE_BASE);
(void)slprintf(s, 12, "%s%c%c%c",
- base, magic_char, base36( csum/36 ), base36( csum ) );
+ base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) );
if( *extension )
{
@@ -935,6 +969,11 @@ void mangle_name_83( char *s)
* signal that a client does not require name mangling,
* thus skipping the name mangling even on shares which
* have name-mangling turned on.
+ * cache83 - If False, the mangled name cache will not be updated.
+ * This is usually used to prevent that we overwrite
+ * a conflicting cache entry prematurely, i.e. before
+ * we know whether the client is really interested in the
+ * current name. (See PR#13758). UKD.
* snum - Share number. This identifies the share in which the
* name exists.
*
@@ -943,11 +982,11 @@ void mangle_name_83( char *s)
*
* ****************************************************************************
*/
-BOOL name_map_mangle(char *OutName, BOOL need83, int snum)
+BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum)
{
char *map;
- DEBUG(5,("name_map_mangle( %s, %s, %d )\n",
- OutName, need83?"TRUE":"FALSE", snum));
+ DEBUG(5,("name_map_mangle( %s, need83 = %s, cache83 = %s, %d )\n", OutName,
+ need83 ? "TRUE" : "FALSE", cache83 ? "TRUE" : "FALSE", snum));
#ifdef MANGLE_LONG_FILENAMES
if( !need83 && is_illegal_name(OutName) )
@@ -963,17 +1002,19 @@ BOOL name_map_mangle(char *OutName, BOOL need83, int snum)
/* check if it's already in 8.3 format */
if (need83 && !is_8_3(OutName, True)) {
- char *tmp;
+ char *tmp = NULL;
if (!lp_manglednames(snum)) {
return(False);
}
/* mangle it into 8.3 */
- tmp = strdup(OutName);
+ if (cache83)
+ tmp = strdup(OutName);
+
mangle_name_83(OutName);
- if(tmp) {
+ if(tmp != NULL) {
cache_mangled_name(OutName, tmp);
free(tmp);
}
diff --git a/source3/smbd/message.c b/source3/smbd/message.c
index d13dfda1e0..2f94bdf111 100644
--- a/source3/smbd/message.c
+++ b/source3/smbd/message.c
@@ -54,7 +54,7 @@ static void msg_deliver(void)
/* put it in a temporary file */
slprintf(s,sizeof(s)-1, "%s/msg.XXXXXX",tmpdir());
- fstrcpy(name,(char *)mktemp(s));
+ fstrcpy(name,(char *)smbd_mktemp(s));
fd = sys_open(name,O_WRONLY|O_CREAT|O_TRUNC|O_EXCL,0600);
if (fd == -1) {
@@ -74,10 +74,13 @@ static void msg_deliver(void)
/* run the command */
if (*lp_msg_command())
{
+ fstring alpha_msgfrom;
+ fstring alpha_msgto;
+
pstrcpy(s,lp_msg_command());
- string_sub(s,"%s",name);
- string_sub(s,"%f",msgfrom);
- string_sub(s,"%t",msgto);
+ pstring_sub(s,"%s",name);
+ pstring_sub(s,"%f",alpha_strcpy(alpha_msgfrom,msgfrom,sizeof(alpha_msgfrom)));
+ pstring_sub(s,"%t",alpha_strcpy(alpha_msgto,msgto,sizeof(alpha_msgto)));
standard_sub_basic(s);
smbrun(s,NULL,False);
}
@@ -99,7 +102,6 @@ int reply_sends(connection_struct *conn,
msgpos = 0;
-
if (! (*lp_msg_command()))
return(ERROR(ERRSRV,ERRmsgoff));
@@ -113,7 +115,9 @@ int reply_sends(connection_struct *conn,
fstrcpy(msgto,dest);
len = SVAL(msg,0);
- len = MIN(len,1600-msgpos);
+ len = MIN(len,sizeof(msgbuf)-msgpos);
+
+ memset(msgbuf,'\0',sizeof(msgbuf));
memcpy(&msgbuf[msgpos],msg+2,len);
msgpos += len;
@@ -140,6 +144,7 @@ int reply_sendstrt(connection_struct *conn,
outsize = set_message(outbuf,1,0,True);
+ memset(msgbuf,'\0',sizeof(msgbuf));
msgpos = 0;
orig = smb_buf(inbuf)+1;
@@ -172,7 +177,7 @@ int reply_sendtxt(connection_struct *conn,
msg = smb_buf(inbuf) + 1;
len = SVAL(msg,0);
- len = MIN(len,1600-msgpos);
+ len = MIN(len,sizeof(msgbuf)-msgpos);
memcpy(&msgbuf[msgpos],msg+2,len);
msgpos += len;
@@ -202,4 +207,3 @@ int reply_sendend(connection_struct *conn,
return(outsize);
}
-
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
index 0b48b0e2b2..b2366b0a37 100644
--- a/source3/smbd/negprot.c
+++ b/source3/smbd/negprot.c
@@ -26,8 +26,6 @@ extern int Protocol;
extern int max_recv;
extern fstring global_myworkgroup;
extern fstring remote_machine;
-extern pstring myhostname;
-extern dfs_internal dfs_struct;
/****************************************************************************
reply for the core protocol
@@ -160,6 +158,16 @@ reply for the nt protocol
static int reply_nt1(char *outbuf)
{
/* dual names + lock_and_read + nt SMBs + remote API calls */
+ int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
+ (lp_nt_smb_support() ? CAP_NT_SMBS | CAP_RPC_REMOTE_APIS : 0) |
+ (SMB_OFF_T_BITS == 64 ? CAP_LARGE_FILES : 0);
+
+
+/*
+ other valid capabilities which we may support at some time...
+ CAP_LARGE_READX|CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
+ */
+
int secword=0;
BOOL doencrypt = SMBENCRYPT();
time_t t = time(NULL);
@@ -168,32 +176,9 @@ static int reply_nt1(char *outbuf)
char cryptkey[8];
char crypt_len = 0;
- int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ;
-
- if (lp_nt_smb_support())
- {
- capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS;
- }
-
- if (SMB_OFF_T_BITS == 64)
- {
- capabilities |= CAP_LARGE_FILES;
- }
-
- if (dfs_struct.ready==True)
- {
- capabilities |= CAP_DFS;
- }
-
-/*
- other valid capabilities which we may support at some time...
- CAP_LARGE_READX|CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
- */
-
- if (lp_security() == SEC_SERVER)
- {
- cli = server_cryptkey();
- }
+ if (lp_security() == SEC_SERVER) {
+ cli = server_cryptkey();
+ }
if (cli) {
DEBUG(3,("using password server validation\n"));
@@ -218,13 +203,12 @@ static int reply_nt1(char *outbuf)
if (doencrypt) secword |= 2;
/* decide where (if) to put the encryption challenge, and
- follow it with the OEM'd domain name in Unicode.
+ follow it with the OEM'd domain name
*/
- data_len = crypt_len + (strlen(global_myworkgroup)+1)*2;
+ data_len = crypt_len + strlen(global_myworkgroup) + 1;
set_message(outbuf,17,data_len,True);
- ascii_to_unibuf(smb_buf(outbuf)+crypt_len, global_myworkgroup,
- (strlen(global_myworkgroup)+1)*2);
+ pstrcpy(smb_buf(outbuf)+crypt_len, global_myworkgroup);
CVAL(outbuf,smb_vwv1) = secword;
SSVALS(outbuf,smb_vwv16+1,crypt_len);
@@ -268,6 +252,14 @@ protocol [LM1.2X002]
protocol [LANMAN2.1]
protocol [NT LM 0.12]
+Win2K:
+protocol [PC NETWORK PROGRAM 1.0]
+protocol [LANMAN1.0]
+protocol [Windows for Workgroups 3.1a]
+protocol [LM1.2X002]
+protocol [LANMAN2.1]
+protocol [NT LM 0.12]
+
OS/2:
protocol [PC NETWORK PROGRAM 1.0]
protocol [XENIX CORE]
@@ -281,29 +273,31 @@ protocol [LANMAN2.1]
*
* This appears to be the matrix of which protocol is used by which
* MS product.
- Protocol WfWg Win95 WinNT OS/2
- PC NETWORK PROGRAM 1.0 1 1 1 1
- XENIX CORE 2 2
+ Protocol WfWg Win95 WinNT Win2K OS/2
+ PC NETWORK PROGRAM 1.0 1 1 1 1 1
+ XENIX CORE 2 2
MICROSOFT NETWORKS 3.0 2 2
DOS LM1.2X002 3 3
MICROSOFT NETWORKS 1.03 3
DOS LANMAN2.1 4 4
- LANMAN1.0 4 3
- Windows for Workgroups 3.1a 5 5 5
- LM1.2X002 6 4
- LANMAN2.1 7 5
- NT LM 0.12 6 8
+ LANMAN1.0 4 2 3
+ Windows for Workgroups 3.1a 5 5 5 3
+ LM1.2X002 6 4 4
+ LANMAN2.1 7 5 5
+ NT LM 0.12 6 8 6
*
* tim@fsg.com 09/29/95
+ * Win2K added by matty 17/7/99
*/
#define ARCH_WFWG 0x3 /* This is a fudge because WfWg is like Win95 */
#define ARCH_WIN95 0x2
-#define ARCH_OS2 0xC /* Again OS/2 is like NT */
-#define ARCH_WINNT 0x8
-#define ARCH_SAMBA 0x10
+#define ARCH_WINNT 0x4
+#define ARCH_WIN2K 0xC /* Win2K is like NT */
+#define ARCH_OS2 0x14 /* Again OS/2 is like NT */
+#define ARCH_SAMBA 0x20
-#define ARCH_ALL 0x1F
+#define ARCH_ALL 0x3F
/* List of supported protocols, most desired first */
static struct {
@@ -346,17 +340,17 @@ int reply_negprot(connection_struct *conn,
Index++;
DEBUG(3,("Requested protocol [%s]\n",p));
if (strcsequal(p,"Windows for Workgroups 3.1a"))
- arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT );
+ arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
else if (strcsequal(p,"DOS LM1.2X002"))
arch &= ( ARCH_WFWG | ARCH_WIN95 );
else if (strcsequal(p,"DOS LANMAN2.1"))
arch &= ( ARCH_WFWG | ARCH_WIN95 );
else if (strcsequal(p,"NT LM 0.12"))
- arch &= ( ARCH_WIN95 | ARCH_WINNT );
+ arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
else if (strcsequal(p,"LANMAN2.1"))
- arch &= ( ARCH_WINNT | ARCH_OS2 );
+ arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
else if (strcsequal(p,"LM1.2X002"))
- arch &= ( ARCH_WINNT | ARCH_OS2 );
+ arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
arch &= ARCH_WINNT;
else if (strcsequal(p,"XENIX CORE"))
@@ -382,6 +376,9 @@ int reply_negprot(connection_struct *conn,
case ARCH_WINNT:
set_remote_arch(RA_WINNT);
break;
+ case ARCH_WIN2K:
+ set_remote_arch(RA_WIN2K);
+ break;
case ARCH_OS2:
set_remote_arch(RA_OS2);
break;
@@ -394,7 +391,7 @@ int reply_negprot(connection_struct *conn,
reload_services(True);
/* a special case to stop password server loops */
- if (Index == 1 && strequal(remote_machine,myhostname) &&
+ if (Index == 1 && strequal(remote_machine,myhostname()) &&
(lp_security()==SEC_SERVER || lp_security()==SEC_DOMAIN))
exit_server("Password server loop!");
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 70023e2407..9615c5ada2 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -37,17 +37,14 @@ static void remove_pending_change_notify_requests_by_mid(int mid);
static char *known_nt_pipes[] = {
"\\LANMAN",
"\\srvsvc",
- "\\svcctl",
"\\samr",
"\\wkssvc",
- "\\browser",
"\\NETLOGON",
"\\ntlsa",
"\\ntsvcs",
"\\lsass",
"\\lsarpc",
"\\winreg",
- "\\spoolss",
NULL
};
@@ -58,7 +55,7 @@ static char *known_nt_pipes[] = {
HACK ! Always assumes smb_setup field is zero.
****************************************************************************/
-static int send_nt_replies(char *outbuf, int bufsize, char *params,
+static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, uint32 nt_error, char *params,
int paramsize, char *pdata, int datasize)
{
extern int max_send;
@@ -78,6 +75,13 @@ static int send_nt_replies(char *outbuf, int bufsize, char *params,
set_message(outbuf,18,0,True);
+ if(nt_error != 0) {
+ /* NT Error. */
+ SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
+
+ ERROR(0,nt_error);
+ }
+
/*
* If there genuinely are no parameters or data to send just send
* the empty packet.
@@ -355,18 +359,25 @@ static int map_create_disposition( uint32 create_disposition)
Utility function to map share modes.
****************************************************************************/
-static int map_share_mode( char *fname, uint32 desired_access, uint32 share_access, uint32 file_attributes)
+static int map_share_mode( BOOL *pstat_open_only, 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) ) {
+ *pstat_open_only = False;
+
+ switch( desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA) ) {
case FILE_READ_DATA:
smb_open_mode = DOS_OPEN_RDONLY;
break;
case FILE_WRITE_DATA:
+ case FILE_APPEND_DATA:
+ case FILE_WRITE_DATA|FILE_APPEND_DATA:
smb_open_mode = DOS_OPEN_WRONLY;
break;
case FILE_READ_DATA|FILE_WRITE_DATA:
+ case FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA:
+ case FILE_READ_DATA|FILE_APPEND_DATA:
smb_open_mode = DOS_OPEN_RDWR;
break;
}
@@ -386,8 +397,12 @@ static int map_share_mode( char *fname, uint32 desired_access, uint32 share_acce
*/
if (smb_open_mode == -1) {
+ if(desired_access == WRITE_DAC_ACCESS || desired_access == READ_CONTROL_ACCESS)
+ *pstat_open_only = True;
+
if(desired_access & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|
FILE_EXECUTE|FILE_READ_ATTRIBUTES|
+ FILE_READ_EA|FILE_WRITE_EA|SYSTEM_SECURITY_ACCESS|
FILE_WRITE_ATTRIBUTES|READ_CONTROL_ACCESS))
smb_open_mode = DOS_OPEN_RDONLY;
else {
@@ -464,11 +479,40 @@ static time_t fail_time;
void fail_next_srvsvc_open(void)
{
+ /* Check client is WinNT proper; Win2K doesn't like Jeremy's hack - matty */
+ if (get_remote_arch() != RA_WINNT)
+ return;
+
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"));
}
+/*
+ * HACK alert.... see above - JRA.
+ */
+
+BOOL should_fail_next_srvsvc_open(const char *pipename)
+{
+
+ DEBUG(10,("should_fail_next_srvsvc_open: fail = %d, pipe = %s\n",
+ (int)fail_next_srvsvc, pipename));
+
+ if(fail_next_srvsvc && (time(NULL) > fail_time + HACK_FAIL_TIME)) {
+ fail_next_srvsvc = False;
+ fail_time = (time_t)0;
+ DEBUG(10,("should_fail_next_srvsvc_open: End of timeout close of \\srvsvc pipe for print fix.\n"));
+ }
+
+ if(fail_next_srvsvc && strequal(pipename, "srvsvc")) {
+ fail_next_srvsvc = False;
+ DEBUG(10,("should_fail_next_srvsvc_open: Deliberately failing open of \\srvsvc pipe for print fix.\n"));
+ return True;
+ }
+ return False;
+}
+
+
/****************************************************************************
Reply to an NT create and X call on a pipe.
****************************************************************************/
@@ -487,32 +531,15 @@ static int nt_open_pipe(char *fname, connection_struct *conn,
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));
/* Strip \\ off the name. */
fname++;
+ if(should_fail_next_srvsvc_open(fname))
+ return (ERROR(ERRSRV,ERRaccess));
+
DEBUG(3,("nt_open_pipe: Known pipe %s opening.\n", fname));
p = open_rpc_pipe_p(fname, conn, vuid);
@@ -547,7 +574,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
/* Breakout the oplock request bits so we can set the
reply bits separately. */
int oplock_request = 0;
- mode_t unixmode;
+ mode_t unixmode;
int pnum = -1;
int fmode=0,rmode=0;
SMB_OFF_T file_len = 0;
@@ -556,6 +583,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
BOOL bad_path = False;
files_struct *fsp=NULL;
char *p = NULL;
+ BOOL stat_open_only = False;
/*
* We need to construct the open_and_X ofun value from the
@@ -576,8 +604,23 @@ int reply_ntcreate_and_X(connection_struct *conn,
files_struct *dir_fsp = file_fsp(inbuf,smb_ntcreate_RootDirectoryFid);
size_t dir_name_len;
- if(!dir_fsp || !dir_fsp->is_directory)
+ if(!dir_fsp)
+ return(ERROR(ERRDOS,ERRbadfid));
+
+ if(!dir_fsp->is_directory) {
+ /*
+ * Check to see if this is a mac fork of some kind.
+ */
+
+ get_filename(&fname[0], inbuf, smb_buf(inbuf)-inbuf,
+ smb_buflen(inbuf),fname_len);
+
+ if( fname[0] == ':') {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_OBJECT_PATH_NOT_FOUND));
+ }
return(ERROR(ERRDOS,ERRbadfid));
+ }
/*
* Copy in the base directory name.
@@ -600,26 +643,17 @@ int reply_ntcreate_and_X(connection_struct *conn,
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) && lp_nt_pipe_support() && lp_security() != SEC_SHARE)
- {
+ if (IS_IPC(conn) && lp_nt_pipe_support()) {
+
int ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum);
if(ret != 0)
return ret;
@@ -654,11 +688,13 @@ int reply_ntcreate_and_X(connection_struct *conn,
* desired access and the share access.
*/
- if((smb_open_mode = map_share_mode(fname, desired_access,
+ if((smb_open_mode = map_share_mode(&stat_open_only, fname, desired_access,
share_access,
- file_attributes)) == -1) {
+ file_attributes)) == -1)
return(ERROR(ERRDOS,ERRbadaccess));
- }
+
+ oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+ oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
/*
* Ordinary file or directory.
@@ -670,11 +706,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
set_posix_case_semantics(file_attributes);
- if (!unix_dfs_convert(fname,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(fname,conn,0,&bad_path,NULL);
fsp = file_new();
if (!fsp) {
@@ -696,9 +728,6 @@ int reply_ntcreate_and_X(connection_struct *conn,
unixmode = unix_mode(conn,smb_attr | aARCH);
- oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
- oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
-
/*
* If it's a request for a directory open, deal with it separately.
*/
@@ -706,8 +735,8 @@ int reply_ntcreate_and_X(connection_struct *conn,
if(create_options & FILE_DIRECTORY_FILE) {
oplock_request = 0;
- open_directory(fsp, conn, fname, smb_ofun, unixmode,
- &smb_action);
+ open_directory(fsp, conn, fname, smb_ofun,
+ unixmode, &smb_action);
restore_case_semantics(file_attributes);
@@ -733,13 +762,12 @@ int reply_ntcreate_and_X(connection_struct *conn,
* before issuing an oplock break request to
* our client. JRA. */
- open_file_shared(fsp,conn,fname,smb_open_mode,
- smb_ofun,unixmode,
- oplock_request,&rmode,&smb_action);
+ open_file_shared(fsp,conn,fname,smb_open_mode,
+ smb_ofun,unixmode, oplock_request,&rmode,&smb_action);
if (!fsp->open) {
- /* We cheat here. The only case we
- * care about is a directory rename,
+ /* We cheat here. There are two cases we
+ * care about. One is a directory rename,
* where the NT client will attempt to
* open the source directory for
* DELETE access. Note that when the
@@ -752,21 +780,54 @@ int reply_ntcreate_and_X(connection_struct *conn,
* will generate an EISDIR error, so
* we can catch this here and open a
* pseudo handle that is flagged as a
- * directory. JRA. */
+ * directory. The second is an open
+ * for a permissions read only, which
+ * we handle in the open_file_stat case. JRA.
+ */
if(errno == EISDIR) {
+
+ /*
+ * Fail the open if it was explicitly a non-directory file.
+ */
+
+ if (create_options & FILE_NON_DIRECTORY_FILE) {
+ file_free(fsp);
+ restore_case_semantics(file_attributes);
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_FILE_IS_A_DIRECTORY));
+ }
+
oplock_request = 0;
-
- open_directory(fsp, conn, fname,
- smb_ofun, unixmode,
- &smb_action);
+ open_directory(fsp, conn, fname, smb_ofun, unixmode, &smb_action);
if(!fsp->open) {
file_free(fsp);
restore_case_semantics(file_attributes);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
+#ifdef EROFS
+ } else if (((errno == EACCES) || (errno == EROFS)) && stat_open_only) {
+#else /* !EROFS */
+ } else if (errno == EACCES && stat_open_only) {
+#endif
+ /*
+ * We couldn't open normally and all we want
+ * are the permissions. Try and do a stat open.
+ */
+
+ oplock_request = 0;
+
+ open_file_stat(fsp,conn,fname,smb_open_mode,&sbuf,&smb_action);
+
+ if(!fsp->open) {
+ file_free(fsp);
+ restore_case_semantics(file_attributes);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
} else {
+
if((errno == ENOENT) && bad_path) {
unix_ERR_class = ERRDOS;
unix_ERR_code = ERRbadpath;
@@ -782,15 +843,13 @@ int reply_ntcreate_and_X(connection_struct *conn,
}
if(fsp->is_directory) {
- if(fsp->conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name, False),
- &sbuf) != 0) {
- close_directory(fsp);
+ if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
+ close_file(fsp,True);
restore_case_semantics(file_attributes);
return(ERROR(ERRDOS,ERRnoaccess));
}
} else {
- if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf)
- != 0) {
+ if (!fsp->stat_open && sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
close_file(fsp,False);
restore_case_semantics(file_attributes);
return(ERROR(ERRDOS,ERRnoaccess));
@@ -817,9 +876,9 @@ int reply_ntcreate_and_X(connection_struct *conn,
if (oplock_request && lp_fake_oplocks(SNUM(conn)))
smb_action |= EXTENDED_OPLOCK_GRANTED;
- if(oplock_request && fsp->granted_oplock)
+ if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
smb_action |= EXTENDED_OPLOCK_GRANTED;
-
+
set_message(outbuf,34,0,True);
p = outbuf + smb_vwv2;
@@ -828,8 +887,14 @@ int reply_ntcreate_and_X(connection_struct *conn,
* Currently as we don't support level II oplocks we just report
* exclusive & batch here.
*/
+
+ if (smb_action & EXTENDED_OPLOCK_GRANTED)
+ SCVAL(p,0, BATCH_OPLOCK_RETURN);
+ else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
+ else
+ SCVAL(p,0,NO_OPLOCK_RETURN);
- SCVAL(p,0, (smb_action & EXTENDED_OPLOCK_GRANTED ? 1 : 0));
p++;
SSVAL(p,0,fsp->fnum);
p += 2;
@@ -861,6 +926,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
/****************************************************************************
Reply to a NT_TRANSACT_CREATE call (needs to process SD's).
****************************************************************************/
+
static int call_nt_transact_create(connection_struct *conn,
char *inbuf, char *outbuf, int length,
int bufsize,
@@ -893,6 +959,7 @@ static int call_nt_transact_create(connection_struct *conn,
BOOL bad_path = False;
files_struct *fsp = NULL;
char *p = NULL;
+ BOOL stat_open_only = False;
/*
* We need to construct the open_and_X ofun value from the
@@ -914,8 +981,24 @@ static int call_nt_transact_create(connection_struct *conn,
files_struct *dir_fsp = file_fsp(params,4);
size_t dir_name_len;
- if(!dir_fsp || !dir_fsp->is_directory)
+ if(!dir_fsp)
+ return(ERROR(ERRDOS,ERRbadfid));
+
+ if(!dir_fsp->is_directory) {
+ /*
+ * Check to see if this is a mac fork of some kind.
+ */
+
+ StrnCpy(fname,params+53,fname_len);
+ fname[fname_len] = '\0';
+
+ if( fname[0] == ':') {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_OBJECT_PATH_NOT_FOUND));
+ }
+
return(ERROR(ERRDOS,ERRbadfid));
+ }
/*
* Copy in the base directory name.
@@ -951,17 +1034,26 @@ static int call_nt_transact_create(connection_struct *conn,
return ret;
smb_action = FILE_WAS_OPENED;
} else {
+
+ /*
+ * Now contruct the smb_open_mode value from the desired access
+ * and the share access.
+ */
+
+ if((smb_open_mode = map_share_mode( &stat_open_only, fname, desired_access,
+ share_access, file_attributes)) == -1)
+ return(ERROR(ERRDOS,ERRbadaccess));
+
+ oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+ oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+
/*
* Check if POSIX semantics are wanted.
*/
set_posix_case_semantics(file_attributes);
- if (!unix_dfs_convert(fname,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(fname,conn,0,&bad_path,NULL);
fsp = file_new();
if (!fsp) {
@@ -983,17 +1075,6 @@ static int call_nt_transact_create(connection_struct *conn,
unixmode = unix_mode(conn,smb_attr | aARCH);
- 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.
*/
@@ -1012,37 +1093,96 @@ static int call_nt_transact_create(connection_struct *conn,
if(!fsp->open) {
file_free(fsp);
+ restore_case_semantics(file_attributes);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
+
+ if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
+ close_file(fsp,True);
+ restore_case_semantics(file_attributes);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+
} else {
/*
* Ordinary file case.
*/
- open_file_shared(fsp,conn,fname,smb_open_mode,smb_ofun,
- unixmode,oplock_request,&rmode,&smb_action);
+ open_file_shared(fsp,conn,fname,smb_open_mode,smb_ofun,unixmode,
+ oplock_request,&rmode,&smb_action);
if (!fsp->open) {
- if((errno == ENOENT) && bad_path) {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- file_free(fsp);
- restore_case_semantics(file_attributes);
+ if(errno == EISDIR) {
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
- close_file(fsp,False);
+ /*
+ * Fail the open if it was explicitly a non-directory file.
+ */
- restore_case_semantics(file_attributes);
+ if (create_options & FILE_NON_DIRECTORY_FILE) {
+ file_free(fsp);
+ restore_case_semantics(file_attributes);
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_FILE_IS_A_DIRECTORY));
+ }
+
+ oplock_request = 0;
+ open_directory(fsp, conn, fname, smb_ofun, unixmode, &smb_action);
+
+ if(!fsp->open) {
+ file_free(fsp);
+ restore_case_semantics(file_attributes);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+#ifdef EROFS
+ } else if (((errno == EACCES) || (errno == EROFS)) && stat_open_only) {
+#else /* !EROFS */
+ } else if (errno == EACCES && stat_open_only) {
+#endif
- return(ERROR(ERRDOS,ERRnoaccess));
+ /*
+ * We couldn't open normally and all we want
+ * are the permissions. Try and do a stat open.
+ */
+
+ oplock_request = 0;
+
+ open_file_stat(fsp,conn,fname,smb_open_mode,&sbuf,&smb_action);
+
+ if(!fsp->open) {
+ file_free(fsp);
+ restore_case_semantics(file_attributes);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
+
+ restore_case_semantics(file_attributes);
+
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
}
+ if(fsp->is_directory) {
+ if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
+ close_file(fsp,True);
+ restore_case_semantics(file_attributes);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+ if (!fsp->stat_open && sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ close_file(fsp,False);
+ restore_case_semantics(file_attributes);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+
file_len = sbuf.st_size;
fmode = dos_mode(conn,fname,&sbuf);
if(fmode == 0)
@@ -1063,7 +1203,7 @@ static int call_nt_transact_create(connection_struct *conn,
if (oplock_request && lp_fake_oplocks(SNUM(conn)))
smb_action |= EXTENDED_OPLOCK_GRANTED;
- if(oplock_request && fsp->granted_oplock)
+ if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
smb_action |= EXTENDED_OPLOCK_GRANTED;
}
}
@@ -1075,8 +1215,16 @@ static int call_nt_transact_create(connection_struct *conn,
if(params == NULL)
return(ERROR(ERRDOS,ERRnomem));
+ memset((char *)params,'\0',69);
+
p = params;
- SCVAL(p,0, (smb_action & EXTENDED_OPLOCK_GRANTED ? 1 : 0));
+ if (smb_action & EXTENDED_OPLOCK_GRANTED)
+ SCVAL(p,0, BATCH_OPLOCK_RETURN);
+ else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
+ else
+ SCVAL(p,0,NO_OPLOCK_RETURN);
+
p += 2;
if (IS_IPC(conn)) {
SSVAL(p,0,pnum);
@@ -1119,7 +1267,7 @@ static int call_nt_transact_create(connection_struct *conn,
}
/* Send the required number of replies */
- send_nt_replies(outbuf, bufsize, params, 69, *ppdata, 0);
+ send_nt_replies(inbuf, outbuf, bufsize, 0, params, 69, *ppdata, 0);
return -1;
}
@@ -1156,6 +1304,7 @@ int reply_nttranss(connection_struct *conn,
/****************************************************************************
Reply to an NT transact rename command.
****************************************************************************/
+
static int call_nt_transact_rename(connection_struct *conn,
char *inbuf, char *outbuf, int length,
int bufsize,
@@ -1179,7 +1328,7 @@ static int call_nt_transact_rename(connection_struct *conn,
/*
* Rename was successful.
*/
- send_nt_replies(outbuf, bufsize, NULL, 0, NULL, 0);
+ send_nt_replies(inbuf, outbuf, bufsize, 0, NULL, 0, NULL, 0);
DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n",
fsp->fsp_name, new_name));
@@ -1191,6 +1340,18 @@ static int call_nt_transact_rename(connection_struct *conn,
}
/****************************************************************************
+ This is the structure to keep the information needed to
+ determine if a directory has changed.
+*****************************************************************************/
+
+typedef struct {
+ time_t modify_time; /* Info from the directory we're monitoring. */
+ time_t status_time; /* Info from the directory we're monitoring. */
+ time_t total_time; /* Total time of all directory entries - don't care if it wraps. */
+ unsigned int num_entries; /* Zero or the number of files in the directory. */
+} change_hash_data;
+
+/****************************************************************************
This is the structure to queue to implement NT change
notify. It consists of smb_size bytes stored from the
transact command (to keep the mid, tid etc around).
@@ -1201,9 +1362,9 @@ typedef struct {
ubi_slNode msg_next;
files_struct *fsp;
connection_struct *conn;
+ uint32 flags;
time_t next_check_time;
- time_t modify_time; /* Info from the directory we're monitoring. */
- time_t status_time; /* Info from the directory we're monitoring. */
+ change_hash_data change_data;
char request_buf[smb_size];
} change_notify_buf;
@@ -1244,8 +1405,92 @@ static void change_notify_reply_packet(char *inbuf, int error_class, uint32 erro
}
/****************************************************************************
+ Create the hash we will use to determine if the contents changed.
+*****************************************************************************/
+
+static BOOL create_directory_notify_hash( change_notify_buf *cnbp, change_hash_data *change_data)
+{
+ SMB_STRUCT_STAT st;
+ files_struct *fsp = cnbp->fsp;
+
+ memset((char *)change_data, '\0', sizeof(change_data));
+
+ /*
+ * Store the current timestamp on the directory we are monitoring.
+ */
+
+ if(dos_stat(fsp->fsp_name, &st) < 0) {
+ DEBUG(0,("create_directory_notify_hash: Unable to stat name = %s. \
+Error was %s\n", fsp->fsp_name, strerror(errno) ));
+ return False;
+ }
+
+ change_data->modify_time = st.st_mtime;
+ change_data->status_time = st.st_ctime;
+
+ /*
+ * If we are to watch for changes that are only stored
+ * in inodes of files, not in the directory inode, we must
+ * scan the directory and produce a unique identifier with
+ * which we can determine if anything changed. We use the
+ * modify and change times from all the files in the
+ * directory, added together (ignoring wrapping if it's
+ * larger than the max time_t value).
+ */
+
+ if(cnbp->flags & (FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE)) {
+ pstring full_name;
+ char *p;
+ char *fname;
+ size_t remaining_len;
+ size_t fullname_len;
+ void *dp = OpenDir(cnbp->conn, fsp->fsp_name, True);
+
+ if(dp == NULL) {
+ DEBUG(0,("create_directory_notify_hash: Unable to open directory = %s. \
+Error was %s\n", fsp->fsp_name, strerror(errno) ));
+ return False;
+ }
+
+ change_data->num_entries = 0;
+
+ pstrcpy(full_name, fsp->fsp_name);
+ pstrcat(full_name, "/");
+
+ fullname_len = strlen(full_name);
+ remaining_len = sizeof(full_name) - fullname_len - 1;
+ p = &full_name[fullname_len];
+
+ while ((fname = ReadDirName(dp))) {
+ if(strequal(fname, ".") || strequal(fname, ".."))
+ continue;
+
+ change_data->num_entries++;
+ safe_strcpy( p, fname, remaining_len);
+
+ memset(&st, '\0', sizeof(st));
+
+ /*
+ * Do the stat - but ignore errors.
+ */
+
+ if(dos_stat(full_name, &st) < 0) {
+ DEBUG(5,("create_directory_notify_hash: Unable to stat content file = %s. \
+Error was %s\n", fsp->fsp_name, strerror(errno) ));
+ }
+ change_data->total_time += (st.st_mtime + st.st_ctime);
+ }
+
+ CloseDir(dp);
+ }
+
+ return True;
+}
+
+/****************************************************************************
Delete entries by fnum from the change notify pending queue.
*****************************************************************************/
+
void remove_pending_change_notify_requests_by_fid(files_struct *fsp)
{
change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
@@ -1274,7 +1519,34 @@ static void remove_pending_change_notify_requests_by_mid(int mid)
while(cnbp != NULL) {
if(SVAL(cnbp->request_buf,smb_mid) == mid) {
- change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_CANCELLED);
+ change_notify_reply_packet(cnbp->request_buf,0,0xC0000000 |NT_STATUS_CANCELLED);
+ free((char *)ubi_slRemNext( &change_notify_queue, prev));
+ cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+ continue;
+ }
+
+ prev = cnbp;
+ cnbp = (change_notify_buf *)ubi_slNext(cnbp);
+ }
+}
+
+/****************************************************************************
+ Delete entries by filename and cnum from the change notify pending queue.
+ Always send reply.
+*****************************************************************************/
+
+void remove_pending_change_notify_requests_by_filename(files_struct *fsp)
+{
+ change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
+ change_notify_buf *prev = NULL;
+
+ while(cnbp != NULL) {
+ /*
+ * We know it refers to the same directory if the connection number and
+ * the filename are identical.
+ */
+ if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) {
+ change_notify_reply_packet(cnbp->request_buf,0,0xC0000000 |NT_STATUS_CANCELLED);
free((char *)ubi_slRemNext( &change_notify_queue, prev));
cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
continue;
@@ -1287,18 +1559,20 @@ static void remove_pending_change_notify_requests_by_mid(int mid)
/****************************************************************************
Process the change notify queue. Note that this is only called as root.
+ Returns True if there are still outstanding change notify requests on the
+ queue.
*****************************************************************************/
-void process_pending_change_notify_queue(time_t t)
+BOOL process_pending_change_notify_queue(time_t t)
{
change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
change_notify_buf *prev = NULL;
if(cnbp == NULL)
- return;
+ return False;
if(cnbp->next_check_time >= t)
- return;
+ return True;
/*
* It's time to check. Go through the queue and see if
@@ -1306,8 +1580,7 @@ void process_pending_change_notify_queue(time_t t)
*/
while((cnbp != NULL) && (cnbp->next_check_time <= t)) {
- SMB_STRUCT_STAT st;
- files_struct *fsp = cnbp->fsp;
+ change_hash_data change_data;
connection_struct *conn = cnbp->conn;
uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID :
SVAL(cnbp->request_buf,smb_uid);
@@ -1343,9 +1616,9 @@ void process_pending_change_notify_queue(time_t t)
continue;
}
- if(fsp->conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name, False), &st) < 0) {
- DEBUG(0,("process_pending_change_notify_queue: Unable to stat directory %s. \
-Error was %s.\n", fsp->fsp_name, strerror(errno) ));
+ if(!create_directory_notify_hash( cnbp, &change_data)) {
+ DEBUG(0,("process_pending_change_notify_queue: Unable to create change data for \
+directory %s\n", cnbp->fsp->fsp_name ));
/*
* Remove the entry and return an error to the client.
*/
@@ -1356,13 +1629,12 @@ Error was %s.\n", fsp->fsp_name, strerror(errno) ));
continue;
}
- if(cnbp->modify_time != st.st_mtime ||
- cnbp->status_time != st.st_ctime) {
+ if(memcmp( (char *)&cnbp->change_data, (char *)&change_data, sizeof(change_data))) {
/*
* Remove the entry and return a change notify to the client.
*/
- DEBUG(5,("process_pending_change_notify_queue: directory name = %s changed\n",
- fsp->fsp_name ));
+ DEBUG(5,("process_pending_change_notify_queue: directory name = %s changed.\n",
+ cnbp->fsp->fsp_name ));
change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR);
free((char *)ubi_slRemNext( &change_notify_queue, prev));
cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
@@ -1378,22 +1650,34 @@ Error was %s.\n", fsp->fsp_name, strerror(errno) ));
prev = cnbp;
cnbp = (change_notify_buf *)ubi_slNext(cnbp);
}
+
+ return (cnbp != NULL);
+}
+
+/****************************************************************************
+ Return true if there are pending change notifies.
+****************************************************************************/
+
+BOOL change_notifies_pending(void)
+{
+ change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
+ return (cnbp != NULL);
}
/****************************************************************************
Reply to a notify change - queue the request and
don't allow a directory to be opened.
****************************************************************************/
+
static int call_nt_transact_notify_change(connection_struct *conn,
- char *inbuf, char *outbuf, int length,
+ char *inbuf, char *outbuf, int length,
int bufsize,
char **ppsetup,
- char **ppparams, char **ppdata)
+ char **ppparams, char **ppdata)
{
char *setup = *ppsetup;
files_struct *fsp;
change_notify_buf *cnbp;
- SMB_STRUCT_STAT st;
fsp = file_fsp(setup,4);
@@ -1414,28 +1698,22 @@ static int call_nt_transact_notify_change(connection_struct *conn,
*/
if((cnbp = (change_notify_buf *)malloc(sizeof(change_notify_buf))) == NULL) {
- DEBUG(0,("call_nt_transact_notify_change: Malloc fail (2) !\n" ));
+ DEBUG(0,("call_nt_transact_notify_change: malloc fail !\n" ));
return -1;
}
- /*
- * Store the current timestamp on the directory we are monitoring.
- */
+ memset((char *)cnbp, '\0', sizeof(change_notify_buf));
- if(fsp->conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name, False), &st) < 0) {
- DEBUG(0,("call_nt_transact_notify_change: Unable to stat name = %s. \
-Error was %s\n", fsp->fsp_name, strerror(errno) ));
- free((char *)cnbp);
- return(UNIXERROR(ERRDOS,ERRbadfid));
- }
-
memcpy(cnbp->request_buf, inbuf, smb_size);
cnbp->fsp = fsp;
cnbp->conn = conn;
- cnbp->modify_time = st.st_mtime;
- cnbp->status_time = st.st_ctime;
-
cnbp->next_check_time = time(NULL) + lp_change_notify_timeout();
+ cnbp->flags = IVAL(setup, 0);
+
+ if(!create_directory_notify_hash( cnbp, &cnbp->change_data )) {
+ free((char *)cnbp);
+ return(UNIXERROR(ERRDOS,ERRbadfid));
+ }
/*
* Adding to the tail enables us to check only
@@ -1452,43 +1730,661 @@ name = %s\n", fsp->fsp_name ));
}
/****************************************************************************
+ Map unix perms to NT.
+****************************************************************************/
+
+static SEC_ACCESS map_unix_perms( int *pacl_type, mode_t perm, int r_mask, int w_mask, int x_mask, BOOL is_directory)
+{
+ SEC_ACCESS sa;
+ uint32 nt_mask = 0;
+
+ *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+
+ if((perm & (r_mask|w_mask|x_mask)) == (r_mask|w_mask|x_mask)) {
+ nt_mask = UNIX_ACCESS_RWX;
+ } else if((perm & (r_mask|w_mask|x_mask)) == 0) {
+ nt_mask = UNIX_ACCESS_NONE;
+ } else {
+ nt_mask |= (perm & r_mask) ? UNIX_ACCESS_R : 0;
+ if(is_directory)
+ nt_mask |= (perm & w_mask) ? UNIX_ACCESS_W : 0;
+ else
+ nt_mask |= (perm & w_mask) ? UNIX_ACCESS_W : 0;
+ nt_mask |= (perm & x_mask) ? UNIX_ACCESS_X : 0;
+ }
+ init_sec_access(&sa,nt_mask);
+ return sa;
+}
+
+/****************************************************************************
+ Reply to query a security descriptor from an fsp. If it succeeds it allocates
+ the space for the return elements and returns True.
+****************************************************************************/
+
+static size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
+{
+ extern DOM_SID global_sam_sid;
+ extern DOM_SID global_sid_World;
+ SMB_STRUCT_STAT sbuf;
+ SEC_ACE ace_list[6];
+ DOM_SID owner_sid;
+ DOM_SID group_sid;
+ size_t sec_desc_size;
+ SEC_ACL *psa = NULL;
+ SEC_ACCESS owner_access;
+ int owner_acl_type;
+ SEC_ACCESS group_access;
+ int grp_acl_type;
+ SEC_ACCESS other_access;
+ int other_acl_type;
+ int num_acls = 0;
+
+ *ppdesc = NULL;
+
+ if(!lp_nt_acl_support()) {
+ sid_copy( &owner_sid, &global_sid_World);
+ sid_copy( &group_sid, &global_sid_World);
+ } else {
+
+ if(fsp->is_directory || fsp->fd_ptr == NULL) {
+ if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
+ return 0;
+ }
+ } else {
+ if(sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ return 0;
+ }
+ }
+
+ /*
+ * Get the owner, group and world SIDs.
+ */
+
+ sid_copy(&owner_sid, &global_sam_sid);
+ sid_copy(&group_sid, &global_sam_sid);
+ sid_append_rid(&owner_sid, pdb_uid_to_user_rid(sbuf.st_uid));
+ sid_append_rid(&group_sid, pdb_gid_to_group_rid(sbuf.st_gid));
+
+ /*
+ * Create the generic 3 element UNIX acl.
+ */
+
+ owner_access = map_unix_perms(&owner_acl_type, sbuf.st_mode,
+ S_IRUSR, S_IWUSR, S_IXUSR, fsp->is_directory);
+ group_access = map_unix_perms(&grp_acl_type, sbuf.st_mode,
+ S_IRGRP, S_IWGRP, S_IXGRP, fsp->is_directory);
+ other_access = map_unix_perms(&other_acl_type, sbuf.st_mode,
+ S_IROTH, S_IWOTH, S_IXOTH, fsp->is_directory);
+
+ if(owner_access.mask)
+ init_sec_ace(&ace_list[num_acls++], &owner_sid, owner_acl_type,
+ owner_access, 0);
+
+ if(group_access.mask)
+ init_sec_ace(&ace_list[num_acls++], &group_sid, grp_acl_type,
+ group_access, 0);
+
+ if(other_access.mask)
+ init_sec_ace(&ace_list[num_acls++], &global_sid_World, other_acl_type,
+ other_access, 0);
+
+ if(fsp->is_directory) {
+ /*
+ * For directory ACLs we also add in the inherited permissions
+ * ACE entries. These are the permissions a file would get when
+ * being created in the directory.
+ */
+ mode_t mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE);
+
+ owner_access = map_unix_perms(&owner_acl_type, mode,
+ S_IRUSR, S_IWUSR, S_IXUSR, fsp->is_directory);
+ group_access = map_unix_perms(&grp_acl_type, mode,
+ S_IRGRP, S_IWGRP, S_IXGRP, fsp->is_directory);
+ other_access = map_unix_perms(&other_acl_type, mode,
+ S_IROTH, S_IWOTH, S_IXOTH, fsp->is_directory);
+
+ if(owner_access.mask)
+ init_sec_ace(&ace_list[num_acls++], &owner_sid, owner_acl_type,
+ owner_access, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
+
+ if(group_access.mask)
+ init_sec_ace(&ace_list[num_acls++], &group_sid, grp_acl_type,
+ group_access, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
+
+ if(other_access.mask)
+ init_sec_ace(&ace_list[num_acls++], &global_sid_World, other_acl_type,
+ other_access, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
+ }
+
+ if(num_acls)
+ if((psa = make_sec_acl( 3, num_acls, ace_list)) == NULL) {
+ DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
+ return 0;
+ }
+ }
+
+ *ppdesc = make_standard_sec_desc( &owner_sid, &group_sid, psa, &sec_desc_size);
+
+ if(!*ppdesc) {
+ DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
+ sec_desc_size = 0;
+ }
+
+ free_sec_acl(&psa);
+
+ return sec_desc_size;
+}
+
+/****************************************************************************
Reply to query a security descriptor - currently this is not implemented (it
- is planned to be though).
+ is planned to be though). Right now it just returns the same thing NT would
+ when queried on a FAT filesystem. JRA.
****************************************************************************/
+
static int call_nt_transact_query_security_desc(connection_struct *conn,
- char *inbuf, char *outbuf,
- int length,
- int bufsize,
+ char *inbuf, char *outbuf,
+ int length, int bufsize,
char **ppsetup, char **ppparams, char **ppdata)
{
- static BOOL logged_message = False;
+ uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
+ char *params = *ppparams;
+ char *data = *ppdata;
+ prs_struct pd;
+ SEC_DESC *psd;
+ size_t sec_desc_size;
- if(!logged_message) {
- DEBUG(0,("call_nt_transact_query_security_desc: Currently not implemented.\n"));
- logged_message = True; /* Only print this once... */
+ files_struct *fsp = file_fsp(params,0);
+
+ if(!fsp)
+ return(ERROR(ERRDOS,ERRbadfid));
+
+ DEBUG(3,("call_nt_transact_query_security_desc: file = %s\n", fsp->fsp_name ));
+
+ params = *ppparams = Realloc(*ppparams, 4);
+ if(params == NULL)
+ return(ERROR(ERRDOS,ERRnomem));
+
+ /*
+ * Get the permissions to return.
+ */
+
+ if((sec_desc_size = get_nt_acl(fsp, &psd)) == 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ DEBUG(3,("call_nt_transact_query_security_desc: sec_desc_size = %d.\n",(int)sec_desc_size));
+
+ SIVAL(params,0,(uint32)sec_desc_size);
+
+ if(max_data_count < sec_desc_size) {
+
+ free_sec_desc(&psd);
+
+ send_nt_replies(inbuf, outbuf, bufsize, 0xC0000000|NT_STATUS_BUFFER_TOO_SMALL,
+ params, 4, *ppdata, 0);
+ return -1;
}
- return(ERROR(ERRSRV,ERRnosupport));
+ /*
+ * Allocate the data we will point this at.
+ */
+
+ data = *ppdata = Realloc(*ppdata, sec_desc_size);
+ if(data == NULL) {
+ free_sec_desc(&psd);
+ return(ERROR(ERRDOS,ERRnomem));
+ }
+
+ memset(data, '\0', sec_desc_size);
+
+ /*
+ * Init the parse struct we will marshall into.
+ */
+
+ prs_init(&pd, 0, 4, MARSHALL);
+
+ /*
+ * Setup the prs_struct to point at the memory we just
+ * allocated.
+ */
+
+ prs_give_memory( &pd, data, (uint32)sec_desc_size, False);
+
+ /*
+ * Finally, linearize into the outgoing buffer.
+ */
+
+ if(!sec_io_desc( "sd data", &psd, &pd, 1)) {
+ free_sec_desc(&psd);
+ DEBUG(0,("call_nt_transact_query_security_desc: Error in marshalling \
+security descriptor.\n"));
+ /*
+ * Return access denied for want of a better error message..
+ */
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ /*
+ * Now we can delete the security descriptor.
+ */
+
+ free_sec_desc(&psd);
+
+ send_nt_replies(inbuf, outbuf, bufsize, 0, params, 4, data, (int)sec_desc_size);
+ return -1;
}
-
+
+/****************************************************************************
+ Validate a SID.
+****************************************************************************/
+
+static BOOL validate_unix_sid( DOM_SID *psid, uint32 *prid, DOM_SID *sd_sid)
+{
+ extern DOM_SID global_sam_sid;
+ DOM_SID sid;
+
+ if(!sd_sid) {
+ DEBUG(5,("validate_unix_sid: sid missing.\n"));
+ return False;
+ }
+
+ sid_copy(psid, sd_sid);
+ sid_copy(&sid, sd_sid);
+
+ if(!sid_split_rid(&sid, prid)) {
+ DEBUG(5,("validate_unix_sid: cannot get RID from sid.\n"));
+ return False;
+ }
+
+ if(!sid_equal( &sid, &global_sam_sid)) {
+ DEBUG(5,("validate_unix_sid: sid is not ours.\n"));
+ return False;
+ }
+
+ return True;
+}
+
/****************************************************************************
- Reply to set a security descriptor - currently this is not implemented (it
- is planned to be though).
+ Map NT perms to UNIX.
****************************************************************************/
+
+#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
+#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
+#define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
+
+static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
+{
+ mode_t mode = 0;
+
+ switch(type) {
+ case S_IRUSR:
+ if(sec_access.mask & GENERIC_ALL_ACCESS)
+ mode = S_IRUSR|S_IWUSR|S_IXUSR;
+ else {
+ mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
+ mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
+ mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
+ }
+ break;
+ case S_IRGRP:
+ if(sec_access.mask & GENERIC_ALL_ACCESS)
+ mode = S_IRGRP|S_IWGRP|S_IXGRP;
+ else {
+ mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
+ mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
+ mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
+ }
+ break;
+ case S_IROTH:
+ if(sec_access.mask & GENERIC_ALL_ACCESS)
+ mode = S_IROTH|S_IWOTH|S_IXOTH;
+ else {
+ mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
+ mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
+ mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
+ }
+ break;
+ }
+
+ return mode;
+}
+
+/****************************************************************************
+ Unpack a SEC_DESC into a owner, group and set of UNIX permissions.
+****************************************************************************/
+
+static BOOL unpack_nt_permissions(uid_t *puser, gid_t *pgrp, mode_t *pmode, uint32 security_info_sent,
+ SEC_DESC *psd, BOOL is_directory)
+{
+ extern DOM_SID global_sid_World;
+ DOM_SID owner_sid;
+ DOM_SID grp_sid;
+ uint32 owner_rid;
+ uint32 grp_rid;
+ SEC_ACL *dacl = psd->dacl;
+ int i;
+
+ *pmode = 0;
+ *puser = (uid_t)-1;
+ *pgrp = (gid_t)-1;
+
+ if(security_info_sent == 0) {
+ DEBUG(0,("unpack_unix_permissions: no security info sent !\n"));
+ return False;
+ }
+
+ /*
+ * Validate the owner and group SID's.
+ */
+
+ memset(&owner_sid, '\0', sizeof(owner_sid));
+ memset(&grp_sid, '\0', sizeof(grp_sid));
+
+ DEBUG(5,("unpack_unix_permissions: validating owner_sid.\n"));
+
+ /*
+ * Don't immediately fail if the owner sid cannot be validated.
+ * This may be a group chown only set.
+ */
+
+ if(!validate_unix_sid( &owner_sid, &owner_rid, psd->owner_sid))
+ DEBUG(3,("unpack_unix_permissions: unable to validate owner sid.\n"));
+ else if(security_info_sent & OWNER_SECURITY_INFORMATION)
+ *puser = pdb_user_rid_to_uid(owner_rid);
+
+ /*
+ * Don't immediately fail if the group sid cannot be validated.
+ * This may be an owner chown only set.
+ */
+
+ if(!validate_unix_sid( &grp_sid, &grp_rid, psd->grp_sid))
+ DEBUG(3,("unpack_unix_permissions: unable to validate group sid.\n"));
+ else if(security_info_sent & GROUP_SECURITY_INFORMATION)
+ *pgrp = pdb_user_rid_to_gid(grp_rid);
+
+ /*
+ * If no DACL then this is a chown only security descriptor.
+ */
+
+ if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl) {
+ *pmode = 0;
+ return True;
+ }
+
+ /*
+ * Now go through the DACL and ensure that
+ * any owner/group sids match.
+ */
+
+ for(i = 0; i < dacl->num_aces; i++) {
+ DOM_SID ace_sid;
+ SEC_ACE *psa = &dacl->ace_list[i];
+
+ if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) &&
+ (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
+ DEBUG(3,("unpack_unix_permissions: unable to set anything but an ALLOW or DENY ACE.\n"));
+ return False;
+ }
+
+ /*
+ * Ignore or remove bits we don't care about on a directory ACE.
+ */
+
+ if(is_directory) {
+ if(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ DEBUG(3,("unpack_unix_permissions: ignoring inherit only ACE.\n"));
+ continue;
+ }
+
+ psa->flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT);
+ }
+
+ if(psa->flags != 0) {
+ DEBUG(1,("unpack_unix_permissions: unable to set ACE flags (%x).\n",
+ (unsigned int)psa->flags));
+ return False;
+ }
+
+ /*
+ * The security mask may be UNIX_ACCESS_NONE which should map into
+ * no permissions (we overload the WRITE_OWNER bit for this) or it
+ * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
+ * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
+ */
+
+ psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
+ GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
+
+ if(psa->info.mask != UNIX_ACCESS_NONE)
+ psa->info.mask &= ~UNIX_ACCESS_NONE;
+
+ sid_copy(&ace_sid, &psa->sid);
+
+ if(sid_equal(&ace_sid, &owner_sid)) {
+ /*
+ * Map the desired permissions into owner perms.
+ */
+
+ if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
+ *pmode |= map_nt_perms( psa->info, S_IRUSR);
+ else
+ *pmode &= ~(map_nt_perms( psa->info, S_IRUSR));
+
+ } else if( sid_equal(&ace_sid, &grp_sid)) {
+ /*
+ * Map the desired permissions into group perms.
+ */
+
+ if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
+ *pmode |= map_nt_perms( psa->info, S_IRGRP);
+ else
+ *pmode &= ~(map_nt_perms( psa->info, S_IRGRP));
+
+ } else if( sid_equal(&ace_sid, &global_sid_World)) {
+ /*
+ * Map the desired permissions into other perms.
+ */
+
+ if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
+ *pmode |= map_nt_perms( psa->info, S_IROTH);
+ else
+ *pmode &= ~(map_nt_perms( psa->info, S_IROTH));
+
+ } else {
+ DEBUG(0,("unpack_unix_permissions: unknown SID used in ACL.\n"));
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Reply to set a security descriptor. Map to UNIX perms.
+****************************************************************************/
+
static int call_nt_transact_set_security_desc(connection_struct *conn,
- char *inbuf, char *outbuf,
- int length,
- int bufsize,
- char **ppsetup,
- char **ppparams, char **ppdata)
+ char *inbuf, char *outbuf, int length,
+ int bufsize, char **ppsetup,
+ char **ppparams, char **ppdata)
{
- static BOOL logged_message = False;
+ uint32 total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount);
+ char *params= *ppparams;
+ char *data = *ppdata;
+ prs_struct pd;
+ SEC_DESC *psd = NULL;
+ uint32 total_data_count = (uint32)IVAL(inbuf, smb_nts_TotalDataCount);
+ uid_t user = (uid_t)-1;
+ gid_t grp = (gid_t)-1;
+ mode_t perms = 0;
+ SMB_STRUCT_STAT sbuf;
+ files_struct *fsp = NULL;
+ uint32 security_info_sent = 0;
+ BOOL got_dacl = False;
- if(!logged_message) {
- DEBUG(0,("call_nt_transact_set_security_desc: Currently not implemented.\n"));
- logged_message = True; /* Only print this once... */
+ if(!lp_nt_acl_support())
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ if(total_parameter_count < 8)
+ return(ERROR(ERRDOS,ERRbadfunc));
+
+ if((fsp = file_fsp(params,0)) == NULL)
+ return(ERROR(ERRDOS,ERRbadfid));
+
+ security_info_sent = IVAL(params,4);
+
+ DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", fsp->fsp_name,
+ (unsigned int)security_info_sent ));
+
+ /*
+ * Init the parse struct we will unmarshall from.
+ */
+
+ prs_init(&pd, 0, 4, UNMARSHALL);
+
+ /*
+ * Setup the prs_struct to point at the memory we just
+ * allocated.
+ */
+
+ prs_give_memory( &pd, data, total_data_count, False);
+
+ /*
+ * Finally, unmarshall from the data buffer.
+ */
+
+ if(!sec_io_desc( "sd data", &psd, &pd, 1)) {
+ free_sec_desc(&psd);
+ DEBUG(0,("call_nt_transact_set_security_desc: Error in unmarshalling \
+security descriptor.\n"));
+ /*
+ * Return access denied for want of a better error message..
+ */
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
}
- return(ERROR(ERRSRV,ERRnosupport));
+
+ /*
+ * Unpack the user/group/world id's and permissions.
+ */
+
+ if(!unpack_nt_permissions( &user, &grp, &perms, security_info_sent, psd, fsp->is_directory)) {
+ free_sec_desc(&psd);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ if (psd->dacl != NULL)
+ got_dacl = True;
+
+ free_sec_desc(&psd);
+
+ /*
+ * Get the current state of the file.
+ */
+
+ if(fsp->is_directory) {
+ if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+
+ int ret;
+
+ if(fsp->fd_ptr == NULL)
+ ret = dos_stat(fsp->fsp_name, &sbuf);
+ else
+ ret = sys_fstat(fsp->fd_ptr->fd,&sbuf);
+
+ if(ret != 0) {
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+
+ /*
+ * Do we need to chown ?
+ */
+
+ if((user != (uid_t)-1 || grp != (uid_t)-1) && (sbuf.st_uid != user || sbuf.st_gid != grp)) {
+
+ DEBUG(3,("call_nt_transact_set_security_desc: chown %s. uid = %u, gid = %u.\n",
+ fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
+
+ if(dos_chown( fsp->fsp_name, user, grp) == -1) {
+ DEBUG(3,("call_nt_transact_set_security_desc: chown %s, %u, %u failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ /*
+ * Recheck the current state of the file, which may have changed.
+ * (suid/sgid bits, for instance)
+ */
+
+ if(fsp->is_directory) {
+ if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+
+ int ret;
+
+ if(fsp->fd_ptr == NULL)
+ ret = dos_stat(fsp->fsp_name, &sbuf);
+ else
+ ret = sys_fstat(fsp->fd_ptr->fd,&sbuf);
+
+ if(ret != 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+
+ /*
+ * Only change security if we got a DACL.
+ */
+
+ if((security_info_sent & DACL_SECURITY_INFORMATION) && got_dacl) {
+
+ /*
+ * Check to see if we need to change anything.
+ * Enforce limits on modified bits *only*. Don't enforce masks
+ * on bits not changed by the user.
+ */
+
+ if(fsp->is_directory) {
+
+ perms &= (lp_dir_security_mask(SNUM(conn)) | sbuf.st_mode);
+ perms |= (lp_force_dir_security_mode(SNUM(conn)) & ( perms ^ sbuf.st_mode ));
+
+ } else {
+
+ perms &= (lp_security_mask(SNUM(conn)) | sbuf.st_mode);
+ perms |= (lp_force_security_mode(SNUM(conn)) & ( perms ^ sbuf.st_mode ));
+
+ }
+
+ /*
+ * Preserve special bits.
+ */
+
+ perms |= (sbuf.st_mode & ~0777);
+
+ /*
+ * Do we need to chmod ?
+ */
+
+ if(sbuf.st_mode != perms) {
+
+ DEBUG(3,("call_nt_transact_set_security_desc: chmod %s. perms = 0%o.\n",
+ fsp->fsp_name, (unsigned int)perms ));
+
+ if(dos_chmod( fsp->fsp_name, perms) == -1) {
+ DEBUG(3,("call_nt_transact_set_security_desc: chmod %s, 0%o failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)perms, strerror(errno) ));
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+ }
+
+ send_nt_replies(inbuf, outbuf, bufsize, 0, NULL, 0, NULL, 0);
+ return -1;
}
/****************************************************************************
@@ -1675,7 +2571,6 @@ due to being in oplock break state.\n" ));
length, bufsize,
&setup, &params, &data);
break;
-
default:
/* Error in request */
DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code));
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 2c12d425b9..4491082b2c 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -25,22 +25,22 @@ extern int DEBUGLEVEL;
extern pstring sesssetup_user;
extern uint16 global_oplock_port;
-
+extern BOOL global_client_failed_oplock_break;
/****************************************************************************
fd support routines - attempt to do a dos_open
****************************************************************************/
-static int fd_attempt_open(struct connection_struct *conn, char *fname,
- int flags, mode_t mode)
+
+static int fd_attempt_open(char *fname, int flags, mode_t mode)
{
- int fd = conn->vfs_ops.open(fname,flags,mode);
+ int fd = dos_open(fname,flags,mode);
/* Fix for files ending in '.' */
if((fd == -1) && (errno == ENOENT) &&
(strchr(fname,'.')==NULL))
{
pstrcat(fname,".");
- fd = conn->vfs_ops.open(fname,flags,mode);
+ fd = dos_open(fname,flags,mode);
}
#if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF))
@@ -71,7 +71,7 @@ static int fd_attempt_open(struct connection_struct *conn, char *fname,
char tmp = p[max_len];
p[max_len] = '\0';
- if ((fd = conn->vfs_ops.open(fname,flags,mode)) == -1)
+ if ((fd = dos_open(fname,flags,mode)) == -1)
p[max_len] = tmp;
}
}
@@ -83,6 +83,7 @@ static int fd_attempt_open(struct connection_struct *conn, char *fname,
Cache a uid_t currently with this file open. This is an optimization only
used when multiple sessionsetup's have been done to one smbd.
****************************************************************************/
+
void fd_add_to_uid_cache(file_fd_struct *fd_ptr, uid_t u)
{
if(fd_ptr->uid_cache_count >= sizeof(fd_ptr->uid_users_cache)/sizeof(uid_t))
@@ -94,6 +95,7 @@ void fd_add_to_uid_cache(file_fd_struct *fd_ptr, uid_t u)
Remove a uid_t that currently has this file open. This is an optimization only
used when multiple sessionsetup's have been done to one smbd.
****************************************************************************/
+
static void fd_remove_from_uid_cache(file_fd_struct *fd_ptr, uid_t u)
{
int i;
@@ -111,6 +113,7 @@ static void fd_remove_from_uid_cache(file_fd_struct *fd_ptr, uid_t u)
Check if a uid_t that currently has this file open is present. This is an
optimization only used when multiple sessionsetup's have been done to one smbd.
****************************************************************************/
+
static BOOL fd_is_in_uid_cache(file_fd_struct *fd_ptr, uid_t u)
{
int i;
@@ -120,11 +123,11 @@ static BOOL fd_is_in_uid_cache(file_fd_struct *fd_ptr, uid_t u)
return False;
}
-
/****************************************************************************
fd support routines - attempt to re-open an already open fd as O_RDWR.
Save the already open fd (we cannot close due to POSIX file locking braindamage.
****************************************************************************/
+
static void fd_attempt_reopen(char *fname, mode_t mode, file_fd_struct *fd_ptr)
{
int fd = dos_open( fname, O_RDWR, mode);
@@ -145,17 +148,13 @@ static void fd_attempt_reopen(char *fname, mode_t mode, file_fd_struct *fd_ptr)
fd support routines - attempt to close the file referenced by this fd.
Decrements the ref_count and returns it.
****************************************************************************/
-uint16 fd_attempt_close(files_struct *fsp)
+
+uint16 fd_attempt_close(file_fd_struct *fd_ptr, int *err_ret)
{
extern struct current_user current_user;
- file_fd_struct *fd_ptr = fsp->fd_ptr;
- uint16 ret_ref;
+ uint16 ret_ref = fd_ptr->ref_count;
- if (fd_ptr != NULL) {
- ret_ref = fd_ptr->ref_count;
- } else {
- return 0;
- }
+ *err_ret = 0;
DEBUG(3,("fd_attempt_close fd = %d, dev = %x, inode = %.0f, open_flags = %d, ref_count = %d.\n",
fd_ptr->fd, (unsigned int)fd_ptr->dev, (double)fd_ptr->inode,
@@ -168,12 +167,26 @@ uint16 fd_attempt_close(files_struct *fsp)
ret_ref = fd_ptr->ref_count;
if(fd_ptr->ref_count == 0) {
- if(fd_ptr->fd != -1)
- fsp->conn->vfs_ops.close(fd_ptr->fd);
- if(fd_ptr->fd_readonly != -1)
- fsp->conn->vfs_ops.close(fd_ptr->fd_readonly);
- if(fd_ptr->fd_writeonly != -1)
- fsp->conn->vfs_ops.close(fd_ptr->fd_writeonly);
+
+ if(fd_ptr->fd != -1) {
+ if(close(fd_ptr->fd) < 0)
+ *err_ret = errno;
+ }
+
+ if(fd_ptr->fd_readonly != -1) {
+ if(close(fd_ptr->fd_readonly) < 0) {
+ if(*err_ret == 0)
+ *err_ret = errno;
+ }
+ }
+
+ if(fd_ptr->fd_writeonly != -1) {
+ if( close(fd_ptr->fd_writeonly) < 0) {
+ if(*err_ret == 0)
+ *err_ret = errno;
+ }
+ }
+
/*
* Delete this fd_ptr.
*/
@@ -182,7 +195,7 @@ uint16 fd_attempt_close(files_struct *fsp)
fd_remove_from_uid_cache(fd_ptr, (uid_t)current_user.uid);
}
- return ret_ref;
+ return ret_ref;
}
/****************************************************************************
@@ -192,14 +205,21 @@ This is really ugly code, as due to POSIX locking braindamage we must
fork and then attempt to open the file, and return success or failure
via an exit code.
****************************************************************************/
-static BOOL check_access_allowed_for_current_user(struct connection_struct
- *conn, char *fname,
- int accmode )
+
+static BOOL check_access_allowed_for_current_user( char *fname, int accmode )
{
pid_t child_pid;
+ /*
+ * We need to temporarily stop CatchChild from eating
+ * SIGCLD signals as it also eats the exit status code. JRA.
+ */
+
+ CatchChildLeaveStatus();
+
if((child_pid = fork()) < 0) {
DEBUG(0,("check_access_allowed_for_current_user: fork failed.\n"));
+ CatchChild();
return False;
}
@@ -209,11 +229,23 @@ static BOOL check_access_allowed_for_current_user(struct connection_struct
*/
pid_t wpid;
int status_code;
- if ((wpid = sys_waitpid(child_pid, &status_code, 0)) < 0) {
- DEBUG(0,("check_access_allowed_for_current_user: The process is no longer waiting!\n"));
+
+ while ((wpid = sys_waitpid(child_pid, &status_code, 0)) < 0) {
+ if(errno == EINTR) {
+ errno = 0;
+ continue;
+ }
+ DEBUG(0,("check_access_allowed_for_current_user: The process \
+is no longer waiting ! Error = %s\n", strerror(errno) ));
+ CatchChild();
return(False);
}
+ /*
+ * Go back to ignoring children.
+ */
+ CatchChild();
+
if (child_pid != wpid) {
DEBUG(0,("check_access_allowed_for_current_user: We were waiting for the wrong process ID\n"));
return(False);
@@ -245,7 +277,7 @@ static BOOL check_access_allowed_for_current_user(struct connection_struct
*/
int fd;
DEBUG(9,("check_access_allowed_for_current_user: Child - attempting to open %s with mode %d.\n", fname, accmode ));
- if((fd = fd_attempt_open(conn, fname, accmode, 0)) < 0) {
+ if((fd = fd_attempt_open( fname, accmode, 0)) < 0) {
/* Access denied. */
_exit(EACCES);
}
@@ -260,11 +292,12 @@ static BOOL check_access_allowed_for_current_user(struct connection_struct
/****************************************************************************
check a filename for the pipe string
****************************************************************************/
+
static void check_for_pipe(char *fname)
{
/* special case of pipe opens */
char s[10];
- StrnCpy(s,fname,9);
+ StrnCpy(s,fname,sizeof(s)-1);
strlower(s);
if (strstr(s,"pipe/")) {
DEBUG(3,("Rejecting named pipe open for %s\n",fname));
@@ -276,6 +309,7 @@ static void check_for_pipe(char *fname)
/****************************************************************************
open a file
****************************************************************************/
+
static void open_file(files_struct *fsp,connection_struct *conn,
char *fname1,int flags,mode_t mode, SMB_STRUCT_STAT *sbuf)
{
@@ -287,7 +321,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
fsp->open = False;
fsp->fd_ptr = 0;
- fsp->granted_oplock = False;
+ fsp->oplock_type = NO_OPLOCK;
errno = EPERM;
pstrcpy(fname,fname1);
@@ -304,7 +338,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
* JRA.
*/
- if (conn->read_only && !conn->printer) {
+ if (!CAN_WRITE(conn) && !conn->printer) {
/* It's a read-only share - fail if we wanted to write. */
if(accmode != O_RDONLY) {
DEBUG(3,("Permission denied opening %s\n",fname));
@@ -335,7 +369,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
* open fd table.
*/
if(sbuf == 0) {
- if(conn->vfs_ops.stat(dos_to_unix(fname,False), &statbuf) < 0) {
+ if(dos_stat(fname, &statbuf) < 0) {
if(errno != ENOENT) {
DEBUG(3,("Error doing stat on file %s (%s)\n",
fname,strerror(errno)));
@@ -376,7 +410,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
*/
if(!fd_is_in_uid_cache(fd_ptr, (uid_t)current_user.uid)) {
- if(!check_access_allowed_for_current_user(conn, fname, accmode )) {
+ if(!check_access_allowed_for_current_user( fname, accmode )) {
/* Error - permission denied. */
DEBUG(3,("Permission denied opening file %s (flags=%d, accmode = %d)\n",
fname, flags, accmode));
@@ -433,7 +467,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
fd_ptr->real_open_flags = O_RDWR;
/* Set the flags as needed without the read/write modes. */
open_flags = flags & ~(O_RDWR|O_WRONLY|O_RDONLY);
- fd_ptr->fd = fd_attempt_open(conn, fname, open_flags|O_RDWR, mode);
+ fd_ptr->fd = fd_attempt_open(fname, open_flags|O_RDWR, mode);
/*
* On some systems opening a file for R/W access on a read only
* filesystems sets errno to EROFS.
@@ -444,7 +478,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
if((fd_ptr->fd == -1) && (errno == EACCES)) {
#endif /* EROFS */
if(accmode != O_RDWR) {
- fd_ptr->fd = fd_attempt_open(conn, fname, open_flags|accmode, mode);
+ fd_ptr->fd = fd_attempt_open(fname, open_flags|accmode, mode);
fd_ptr->real_open_flags = accmode;
}
}
@@ -458,10 +492,10 @@ static void open_file(files_struct *fsp,connection_struct *conn,
pstrcpy(dname,fname);
p = strrchr(dname,'/');
if (p) *p = 0;
- if (conn->vfs_ops.disk_free(dname,&dum1,&dum2,&dum3) <
- (SMB_BIG_UINT)lp_minprintspace(SNUM(conn))) {
- if(fd_attempt_close(fsp) == 0)
- conn->vfs_ops.unlink(fname);
+ if (sys_disk_free(dname,False,&dum1,&dum2,&dum3) < (SMB_BIG_UINT)lp_minprintspace(SNUM(conn))) {
+ int err;
+ if(fd_attempt_close(fd_ptr, &err) == 0)
+ dos_unlink(fname);
fsp->fd_ptr = 0;
errno = ENOSPC;
return;
@@ -470,10 +504,11 @@ static void open_file(files_struct *fsp,connection_struct *conn,
if (fd_ptr->fd < 0)
{
+ int err;
DEBUG(3,("Error opening file %s (%s) (flags=%d)\n",
fname,strerror(errno),flags));
/* Ensure the ref_count is decremented. */
- fd_attempt_close(fsp);
+ fd_attempt_close(fd_ptr,&err);
check_for_pipe(fname);
return;
}
@@ -482,12 +517,13 @@ static void open_file(files_struct *fsp,connection_struct *conn,
{
if(sbuf == 0) {
/* Do the fstat */
- if(conn->vfs_ops.fstat(fd_ptr->fd, &statbuf) == -1) {
+ if(sys_fstat(fd_ptr->fd, &statbuf) == -1) {
+ int err;
/* Error - backout !! */
DEBUG(3,("Error doing fstat on fd %d, file %s (%s)\n",
fd_ptr->fd, fname,strerror(errno)));
/* Ensure the ref_count is decremented. */
- fd_attempt_close(fsp);
+ fd_attempt_close(fd_ptr,&err);
return;
}
sbuf = &statbuf;
@@ -505,17 +541,17 @@ static void open_file(files_struct *fsp,connection_struct *conn,
fsp->size = 0;
fsp->pos = -1;
fsp->open = True;
- fsp->mmap_ptr = NULL;
- fsp->mmap_size = 0;
fsp->can_lock = True;
fsp->can_read = ((flags & O_WRONLY)==0);
fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
fsp->share_mode = 0;
fsp->print_file = conn->printer;
fsp->modified = False;
- fsp->granted_oplock = False;
- fsp->sent_oplock_break = False;
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->is_directory = False;
+ fsp->stat_open = False;
+ fsp->directory_delete_on_close = False;
fsp->conn = conn;
/*
* Note that the file name here is the *untranslated* name
@@ -526,6 +562,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
*/
string_set(&fsp->fsp_name,fname);
fsp->wbmpx_ptr = NULL;
+ fsp->wcp = NULL; /* Write cache pointer. */
/*
* If the printer is marked as postscript output a leading
@@ -536,7 +573,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
*/
if (fsp->print_file && lp_postscript(SNUM(conn)) && fsp->can_write) {
DEBUG(3,("Writing postscript line\n"));
- conn->vfs_ops.write(fsp->fd_ptr->fd,"%!\n",3);
+ write_file(fsp,"%!\n",-1,3);
}
DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
@@ -548,39 +585,11 @@ static void open_file(files_struct *fsp,connection_struct *conn,
}
/****************************************************************************
- If it's a read-only file, and we were compiled with mmap enabled,
- try and mmap the file. This is split out from open_file() above
- as mmap'ing the file can cause the kernel reference count to
- be incremented, which can cause kernel oplocks to be refused.
- Splitting this call off allows the kernel oplock to be granted, then
- the file mmap'ed.
-****************************************************************************/
-
-static void mmap_open_file(files_struct *fsp)
-{
-#if WITH_MMAP
- /* mmap it if read-only */
- if (!fsp->can_write) {
- fsp->mmap_size = dos_file_size(fsp->fsp_name);
- if (fsp->mmap_size < MAX_MMAP_SIZE) {
- fsp->mmap_ptr = (char *)sys_mmap(NULL,fsp->mmap_size,
- PROT_READ,MAP_SHARED,fsp->fd_ptr->fd,(SMB_OFF_T)0);
-
- if (fsp->mmap_ptr == (char *)-1 || !fsp->mmap_ptr) {
- DEBUG(3,("Failed to mmap() %s - %s\n",
- fsp->fsp_name,strerror(errno)));
- fsp->mmap_ptr = NULL;
- }
- }
- }
-#endif
-}
-
-/****************************************************************************
C. Hoch 11/22/95
Helper for open_file_shared.
Truncate a file after checking locking; close file if locked.
**************************************************************************/
+
static void truncate_unless_locked(files_struct *fsp, connection_struct *conn, int token,
BOOL *share_locked)
{
@@ -606,19 +615,19 @@ static void truncate_unless_locked(files_struct *fsp, connection_struct *conn, i
}
}
-
enum {AFAIL,AREAD,AWRITE,AALL};
/*******************************************************************
reproduce the share mode access table
********************************************************************/
+
static int access_table(int new_deny,int old_deny,int old_mode,
- int share_pid,char *fname)
+ pid_t share_pid,char *fname)
{
if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL);
if (new_deny == DENY_DOS || old_deny == DENY_DOS) {
- int pid = getpid();
+ pid_t pid = getpid();
if (old_deny == new_deny && share_pid == pid)
return(AALL);
@@ -660,10 +669,10 @@ static int access_table(int new_deny,int old_deny,int old_mode,
return(AFAIL);
}
-
/****************************************************************************
check if we can open a file with a share mode
****************************************************************************/
+
static int check_share_mode( share_mode_entry *share, int deny_mode,
char *fname,
BOOL fcbopen, int *flags)
@@ -707,7 +716,7 @@ static int check_share_mode( share_mode_entry *share, int deny_mode,
{
DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s,fcbopen = %d, flags = %d) = %d\n",
deny_mode,old_deny_mode,old_open_mode,
- share->pid,fname, fcbopen, *flags, access_allowed));
+ (int)share->pid,fname, fcbopen, *flags, access_allowed));
unix_ERR_class = ERRDOS;
unix_ERR_code = ERRbadshare;
@@ -726,34 +735,39 @@ static int check_share_mode( share_mode_entry *share, int deny_mode,
return True;
}
-
/****************************************************************************
open a file with a share mode
****************************************************************************/
-void open_file_shared(files_struct *fsp, connection_struct *conn,
- char *fname, int share_mode, int ofun,
- mode_t mode, int oplock_request, int *Access,
- int *action)
+
+void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int share_mode,int ofun,
+ mode_t mode,int oplock_request, int *Access,int *action)
{
int flags=0;
int flags2=0;
int deny_mode = GET_DENY_MODE(share_mode);
BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE(share_mode);
SMB_STRUCT_STAT sbuf;
- BOOL file_existed = vfs_file_exist(conn, dos_to_unix(fname,False), &sbuf);
+ BOOL file_existed = dos_file_exist(fname,&sbuf);
BOOL share_locked = False;
BOOL fcbopen = False;
- int token;
+ int token = 0;
SMB_DEV_T dev = 0;
SMB_INO_T inode = 0;
int num_share_modes = 0;
-
+ int oplock_contention_count = 0;
+ BOOL all_current_opens_are_level_II = False;
fsp->open = False;
fsp->fd_ptr = 0;
DEBUG(10,("open_file_shared: fname = %s, share_mode = %x, ofun = %x, mode = %o, oplock request = %d\n",
fname, share_mode, ofun, (int)mode, oplock_request ));
+
+ /* ignore any oplock requests if oplocks are disabled */
+ if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break) {
+ oplock_request = 0;
+ }
+
/* this is for OS/2 EAs - try and say we don't support them */
if (strstr(fname,".+,;=[]."))
{
@@ -861,6 +875,8 @@ void open_file_shared(files_struct *fsp, connection_struct *conn,
{
broke_oplock = False;
+ all_current_opens_are_level_II = True;
+
for(i = 0; i < num_share_modes; i++)
{
share_mode_entry *share_entry = &old_shares[i];
@@ -872,7 +888,8 @@ void open_file_shared(files_struct *fsp, connection_struct *conn,
* Check if someone has an oplock on this file. If so we must break
* it before continuing.
*/
- if(share_entry->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+ if((oplock_request && EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) ||
+ (!oplock_request && (share_entry->op_type != NO_OPLOCK)))
{
DEBUG(5,("open_file_shared: breaking oplock (%x) on file %s, \
@@ -894,7 +911,10 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
}
lock_share_entry(conn, dev, inode, &token);
broke_oplock = True;
+ all_current_opens_are_level_II = False;
break;
+ } else if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
+ all_current_opens_are_level_II = False;
}
/* someone else has a share lock on it, check to see
@@ -913,6 +933,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
{
free((char *)old_shares);
num_share_modes = get_share_modes(conn, token, dev, inode, &old_shares);
+ oplock_contention_count++;
}
} while(broke_oplock);
}
@@ -921,6 +942,18 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
free((char *)old_shares);
}
+ /*
+ * Refuse to grant an oplock in case the contention limit is
+ * reached when going through the lock list multiple times.
+ */
+
+ if(oplock_contention_count >= lp_oplock_contention_limit(SNUM(conn)))
+ {
+ oplock_request = 0;
+ DEBUG(4,("open_file_shared: oplock contention = %d. Not granting oplock.\n",
+ oplock_contention_count ));
+ }
+
DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n",
flags,flags2,(int)mode));
@@ -978,18 +1011,19 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
{
uint16 port = 0;
- /* JRA. Currently this only services Exlcusive and batch
- oplocks (no other opens on this file). This needs to
- be extended to level II oplocks (multiple reader
- oplocks). */
+ /*
+ * Setup the oplock info in both the shared memory and
+ * file structs.
+ */
- if((oplock_request) && (num_share_modes == 0) && lp_oplocks(SNUM(conn)) &&
- !IS_VETO_OPLOCK_PATH(conn,fname) && set_file_oplock(fsp) )
- {
+ if(oplock_request && (num_share_modes == 0) &&
+ !IS_VETO_OPLOCK_PATH(conn,fname) && set_file_oplock(fsp, oplock_request) ) {
port = global_oplock_port;
- }
- else
- {
+ } else if (oplock_request && all_current_opens_are_level_II) {
+ port = global_oplock_port;
+ oplock_request = LEVEL_II_OPLOCK;
+ set_file_oplock(fsp, oplock_request);
+ } else {
port = 0;
oplock_request = 0;
}
@@ -999,13 +1033,6 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
if ((flags2&O_TRUNC) && file_existed)
truncate_unless_locked(fsp,conn,token,&share_locked);
-
- /*
- * Attempt to mmap a read only file.
- * Moved until after a kernel oplock may
- * be granted due to reference count issues. JRA.
- */
- mmap_open_file(fsp);
}
if (share_locked && lp_share_modes(SNUM(conn)))
@@ -1013,6 +1040,69 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
}
/****************************************************************************
+ Open a file for permissions read only. Return a pseudo file entry
+ with the 'stat_open' flag set and a fd_ptr of NULL.
+****************************************************************************/
+
+int open_file_stat(files_struct *fsp,connection_struct *conn,
+ char *fname, int smb_ofun, SMB_STRUCT_STAT *pst, int *action)
+{
+ extern struct current_user current_user;
+
+ if(dos_stat(fname, pst) < 0) {
+ DEBUG(0,("open_file_stat: unable to stat name = %s. Error was %s\n",
+ fname, strerror(errno) ));
+ return -1;
+ }
+
+ if(S_ISDIR(pst->st_mode)) {
+ DEBUG(0,("open_file_stat: %s is a directory !\n", fname ));
+ return -1;
+ }
+
+ *action = FILE_WAS_OPENED;
+
+ DEBUG(5,("open_file_stat: opening file %s as a stat entry\n", fname));
+
+ /*
+ * Setup the files_struct for it.
+ */
+
+ fsp->fd_ptr = NULL;
+ conn->num_files_open++;
+ fsp->mode = 0;
+ GetTimeOfDay(&fsp->open_time);
+ fsp->vuid = current_user.vuid;
+ fsp->size = 0;
+ fsp->pos = -1;
+ fsp->open = True;
+ fsp->can_lock = False;
+ fsp->can_read = False;
+ fsp->can_write = False;
+ fsp->share_mode = 0;
+ fsp->print_file = False;
+ fsp->modified = False;
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+ fsp->is_directory = False;
+ fsp->stat_open = True;
+ fsp->directory_delete_on_close = False;
+ fsp->conn = conn;
+ /*
+ * Note that the file name here is the *untranslated* name
+ * ie. it is still in the DOS codepage sent from the client.
+ * All use of this filename will pass though the sys_xxxx
+ * functions which will do the dos_to_unix translation before
+ * mapping into a UNIX filename. JRA.
+ */
+ string_set(&fsp->fsp_name,fname);
+ fsp->wbmpx_ptr = NULL;
+ fsp->wcp = NULL; /* Write cache pointer. */
+
+ return 0;
+}
+
+/****************************************************************************
Open a directory from an NT SMB call.
****************************************************************************/
@@ -1021,26 +1111,55 @@ int open_directory(files_struct *fsp,connection_struct *conn,
{
extern struct current_user current_user;
SMB_STRUCT_STAT st;
+ BOOL got_stat = False;
- if (smb_ofun & 0x10) {
- /*
- * Create the directory.
- */
+ if(dos_stat(fname, &st) == 0) {
+ got_stat = True;
+ }
- if(conn->vfs_ops.mkdir(dos_to_unix(fname,False),
- unix_mode(conn,aDIR)) < 0) {
- DEBUG(0,("open_directory: unable to create %s. Error was %s\n",
- fname, strerror(errno) ));
- return -1;
- }
+ if (got_stat && (GET_FILE_OPEN_DISPOSITION(smb_ofun) == FILE_EXISTS_FAIL)) {
+ errno = EEXIST; /* Setup so correct error is returned to client. */
+ return -1;
+ }
+
+ if (GET_FILE_CREATE_DISPOSITION(smb_ofun) == FILE_CREATE_IF_NOT_EXIST) {
+
+ if (got_stat) {
+
+ if(!S_ISDIR(st.st_mode)) {
+ DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
+ errno = EACCES;
+ return -1;
+ }
+ *action = FILE_WAS_OPENED;
+
+ } else {
+
+ /*
+ * Try and create the directory.
+ */
+
+ if(!CAN_WRITE(conn)) {
+ DEBUG(2,("open_directory: failing create on read-only share\n"));
+ errno = EACCES;
+ return -1;
+ }
- *action = FILE_WAS_CREATED;
+ if(dos_mkdir(fname, unix_mode(conn,aDIR)) < 0) {
+ DEBUG(0,("open_directory: unable to create %s. Error was %s\n",
+ fname, strerror(errno) ));
+ return -1;
+ }
+ *action = FILE_WAS_CREATED;
+
+ }
} else {
+
/*
- * Check that it *was* a directory.
+ * Don't create - just check that it *was* a directory.
*/
- if(conn->vfs_ops.stat(dos_to_unix(fname,False), &st) < 0) {
+ if(!got_stat) {
DEBUG(0,("open_directory: unable to stat name = %s. Error was %s\n",
fname, strerror(errno) ));
return -1;
@@ -1050,6 +1169,7 @@ int open_directory(files_struct *fsp,connection_struct *conn,
DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
return -1;
}
+
*action = FILE_WAS_OPENED;
}
@@ -1068,17 +1188,16 @@ int open_directory(files_struct *fsp,connection_struct *conn,
fsp->size = 0;
fsp->pos = -1;
fsp->open = True;
- fsp->mmap_ptr = NULL;
- fsp->mmap_size = 0;
fsp->can_lock = True;
fsp->can_read = False;
fsp->can_write = False;
fsp->share_mode = 0;
fsp->print_file = False;
fsp->modified = False;
- fsp->granted_oplock = False;
- fsp->sent_oplock_break = False;
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->is_directory = True;
+ fsp->directory_delete_on_close = False;
fsp->conn = conn;
/*
* Note that the file name here is the *untranslated* name
@@ -1093,10 +1212,9 @@ int open_directory(files_struct *fsp,connection_struct *conn,
return 0;
}
-
/*******************************************************************
-check if the share mode on a file allows it to be deleted or unlinked
-return True if sharing doesn't prevent the operation
+ Check if the share mode on a file allows it to be deleted or unlinked.
+ Return True if sharing doesn't prevent the operation.
********************************************************************/
BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)
@@ -1107,14 +1225,14 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)
int num_share_modes;
SMB_STRUCT_STAT sbuf;
int token;
- int pid = getpid();
+ pid_t pid = getpid();
SMB_DEV_T dev;
SMB_INO_T inode;
if(!lp_share_modes(SNUM(conn)))
return True;
- if (conn->vfs_ops.stat(dos_to_unix(fname,False),&sbuf) == -1) return(True);
+ if (dos_stat(fname,&sbuf) == -1) return(True);
dev = sbuf.st_dev;
inode = sbuf.st_ino;
@@ -1144,9 +1262,16 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)
* Check if someone has an oplock on this file. If so we must
* break it before continuing.
*/
- if(share_entry->op_type & BATCH_OPLOCK)
+ if(BATCH_OPLOCK_TYPE(share_entry->op_type))
{
+#if 0
+
+/* JRA. Try removing this code to see if the new oplock changes
+ fix the problem. I'm dubious, but Andrew is recommending we
+ try this....
+*/
+
/*
* It appears that the NT redirector may have a bug, in that
* it tries to do an SMBmv on a file that it has open with a
@@ -1176,6 +1301,7 @@ batch oplocked file %s, dev = %x, inode = %.0f\n", fname, (unsigned int)dev, (do
continue;
}
else
+#endif /* 0 */
{
DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 99fe7a69fa..a64dd2d0ef 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -26,18 +26,30 @@ extern int DEBUGLEVEL;
/* Oplock ipc UDP socket. */
static int oplock_sock = -1;
uint16 global_oplock_port = 0;
-#if defined(HAVE_KERNEL_OPLOCKS)
static int oplock_pipe_read = -1;
+
+#if defined(HAVE_KERNEL_OPLOCKS)
static int oplock_pipe_write = -1;
-#endif /* HAVE_KERNEL_OPLOCKS */
+#endif
/* Current number of oplocks we have outstanding. */
-int32 global_oplocks_open = 0;
+static int32 exclusive_oplocks_open = 0;
+static int32 level_II_oplocks_open = 0;
+BOOL global_client_failed_oplock_break = False;
BOOL global_oplock_break = False;
extern int smb_read_error;
-static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval);
+static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, BOOL local);
+
+/****************************************************************************
+ Get the number of current exclusive oplocks.
+****************************************************************************/
+
+int32 get_number_of_exclusive_open_oplocks(void)
+{
+ return exclusive_oplocks_open;
+}
/****************************************************************************
Setup the kernel level oplock backchannel for this process.
@@ -63,8 +75,9 @@ BOOL setup_kernel_oplock_pipe(void)
}
/****************************************************************************
- open the oplock IPC socket communication
+ Open the oplock IPC socket communication.
****************************************************************************/
+
BOOL open_oplock_ipc(void)
{
struct sockaddr_in sock_name;
@@ -73,7 +86,7 @@ BOOL open_oplock_ipc(void)
DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n"));
/* Open a lookback UDP socket on a random port. */
- oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0, htonl(INADDR_LOOPBACK));
+ oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0, htonl(INADDR_LOOPBACK),False);
if (oplock_sock == -1)
{
DEBUG(0,("open_oplock_ipc: Failed to get local UDP socket for \
@@ -127,15 +140,13 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou
int selrtn;
int maxfd = oplock_sock;
-#if defined(HAVE_KERNEL_OPLOCKS)
- if(lp_kernel_oplocks())
+ if(lp_kernel_oplocks() && (oplock_pipe_read != -1))
maxfd = MAX(maxfd, oplock_pipe_read);
-#endif /* HAVE_KERNEL_OPLOCKS */
to.tv_sec = timeout / 1000;
to.tv_usec = (timeout % 1000) * 1000;
- selrtn = sys_select(maxfd+1,fds,NULL, &to);
+ selrtn = sys_select(maxfd+1,fds,&to);
/* Check if error */
if(selrtn == -1) {
@@ -196,7 +207,7 @@ Error was %s.\n", strerror(errno) ));
}
dev = (SMB_DEV_T)os.os_dev;
- inode = (SMB_DEV_T)os.os_ino;
+ inode = (SMB_INO_T)os.os_ino;
DEBUG(5,("receive_local_message: kernel oplock break request received for \
dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
@@ -212,14 +223,9 @@ dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
buffer += OPBRK_CMD_HEADER_LEN;
SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD);
- SIVAL(buffer,KERNEL_OPLOCK_BREAK_DEV_OFFSET,dev);
-#ifdef LARGE_SMB_INO_T
- SIVAL(buffer,KERNEL_OPLOCK_BREAK_INODE_OFFSET,inode & 0xFFFFFFFF);
- SIVAL(buffer,KERNEL_OPLOCK_BREAK_INODE_OFFSET+4, (inode >> 32 ) & 0xFFFFFFFF );
-#else /* LARGE_SMB_INO_T */
- SIVAL(buffer,KERNEL_OPLOCK_BREAK_INODE_OFFSET,inode);
-#endif /* LARGE_SMB_INO_T */
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&dev, sizeof(dev));
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&inode, sizeof(inode));
return True;
}
@@ -265,11 +271,11 @@ dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
}
/****************************************************************************
- Attempt to set an oplock on a file. Always succeeds if kernel oplocks are
- disabled (just sets flags). Returns True if oplock set.
+ Attempt to set an kernel oplock on a file. Always returns True if kernel
+ oplocks not available.
****************************************************************************/
-BOOL set_file_oplock(files_struct *fsp)
+static BOOL set_kernel_oplock(files_struct *fsp, int oplock_type)
{
#if defined(HAVE_KERNEL_OPLOCKS)
if(lp_kernel_oplocks()) {
@@ -293,23 +299,38 @@ inode = %.0f. Another process had the file open.\n",
}
#endif /* HAVE_KERNEL_OPLOCKS */
+ return True;
+}
- DEBUG(5,("set_file_oplock: granted oplock on file %s, dev = %x, inode = %.0f\n",
- fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev, (double)fsp->fd_ptr->inode));
+/****************************************************************************
+ Attempt to set an oplock on a file. Always succeeds if kernel oplocks are
+ disabled (just sets flags). Returns True if oplock set.
+****************************************************************************/
- fsp->granted_oplock = True;
- fsp->sent_oplock_break = False;
- global_oplocks_open++;
+BOOL set_file_oplock(files_struct *fsp, int oplock_type)
+{
+ if (!set_kernel_oplock(fsp, oplock_type))
+ return False;
+
+ fsp->oplock_type = oplock_type;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+ if ( oplock_type == LEVEL_II_OPLOCK)
+ level_II_oplocks_open++;
+ else
+ exclusive_oplocks_open++;
+
+ DEBUG(5,("set_file_oplock: granted oplock on file %s, dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
+ fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev, (double)fsp->fd_ptr->inode,
+ (int)fsp->open_time.tv_sec, (int)fsp->open_time.tv_usec ));
return True;
}
/****************************************************************************
- Attempt to release an oplock on a file. Always succeeds if kernel oplocks are
- disabled (just clears flags).
+ Release a kernel oplock on a file.
****************************************************************************/
-static void release_file_oplock(files_struct *fsp)
+static void release_kernel_oplock(files_struct *fsp)
{
#if defined(HAVE_KERNEL_OPLOCKS)
@@ -322,20 +343,20 @@ static void release_file_oplock(files_struct *fsp)
* oplock state of this file.
*/
int state = fcntl(fsp->fd_ptr->fd, F_OPLKACK, -1);
- dbgtext("release_file_oplock: file %s, dev = %x, inode = %.0f has kernel \
+ dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f has kernel \
oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev,
(double)fsp->fd_ptr->inode, state );
}
/*
- * Remote the kernel oplock on this file.
+ * Remove the kernel oplock on this file.
*/
if(fcntl(fsp->fd_ptr->fd, F_OPLKACK, OP_REVOKE) < 0)
{
if( DEBUGLVL( 0 ))
{
- dbgtext("release_file_oplock: Error when removing kernel oplock on file " );
+ dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " );
dbgtext("%s, dev = %x, inode = %.0f. Error was %s\n",
fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev,
(double)fsp->fd_ptr->inode, strerror(errno) );
@@ -343,10 +364,91 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev,
}
}
#endif /* HAVE_KERNEL_OPLOCKS */
+}
+
+
+/****************************************************************************
+ Attempt to release an oplock on a file. Decrements oplock count.
+****************************************************************************/
+
+void release_file_oplock(files_struct *fsp)
+{
+ release_kernel_oplock(fsp);
+
+ if (fsp->oplock_type == LEVEL_II_OPLOCK)
+ level_II_oplocks_open--;
+ else
+ exclusive_oplocks_open--;
+
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+
+ flush_write_cache(fsp, OPLOCK_RELEASE_FLUSH);
+}
+
+/****************************************************************************
+ Attempt to downgrade an oplock on a file. Doesn't decrement oplock count.
+****************************************************************************/
+
+static void downgrade_file_oplock(files_struct *fsp)
+{
+ release_kernel_oplock(fsp);
+ fsp->oplock_type = LEVEL_II_OPLOCK;
+ exclusive_oplocks_open--;
+ level_II_oplocks_open++;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+}
+
+/****************************************************************************
+ Remove a file oplock. Copes with level II and exclusive.
+ Locks then unlocks the share mode lock.
+****************************************************************************/
+
+BOOL remove_oplock(files_struct *fsp)
+{
+ int token;
+ SMB_DEV_T dev = fsp->fd_ptr->dev;
+ SMB_INO_T inode = fsp->fd_ptr->inode;
+ BOOL ret = True;
+
+ /* Remove the oplock flag from the sharemode. */
+ if (lock_share_entry(fsp->conn, dev, inode, &token) == False) {
+ DEBUG(0,("remove_oplock: failed to lock share entry for file %s\n",
+ fsp->fsp_name ));
+ ret = False;
+ }
+
+ if (fsp->sent_oplock_break == EXCLUSIVE_BREAK_SENT) {
+
+ /*
+ * Deal with a reply when a break-to-none was sent.
+ */
+
+ if(remove_share_oplock(token, fsp)==False) {
+ DEBUG(0,("remove_oplock: failed to remove share oplock for file %s fnum %d, \
+dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode));
+ ret = False;
+ }
+
+ release_file_oplock(fsp);
+
+ } else {
+
+ /*
+ * Deal with a reply when a break-to-level II was sent.
+ */
+
+ if(downgrade_share_oplock(token, fsp)==False) {
+ DEBUG(0,("remove_oplock: failed to downgrade share oplock for file %s fnum %d, \
+dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode));
+ ret = False;
+ }
- fsp->granted_oplock = False;
- fsp->sent_oplock_break = False;
- global_oplocks_open--;
+ downgrade_file_oplock(fsp);
+ }
+
+ unlock_share_entry(fsp->conn, dev, inode, token);
+ return ret;
}
/****************************************************************************
@@ -358,14 +460,16 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev,
int setup_oplock_select_set( fd_set *fds)
{
int maxfd = oplock_sock;
+
+ if(oplock_sock == -1)
+ return 0;
+
FD_SET(oplock_sock,fds);
-#if defined(HAVE_KERNEL_OPLOCKS)
- if(lp_kernel_oplocks()) {
+ if(lp_kernel_oplocks() && (oplock_pipe_read != -1)) {
FD_SET(oplock_pipe_read,fds);
maxfd = MAX(maxfd,oplock_pipe_read);
}
-#endif /* HAVE_KERNEL_OPLOCKS */
return maxfd;
}
@@ -382,9 +486,10 @@ BOOL process_local_message(char *buffer, int buf_size)
char *msg_start;
SMB_DEV_T dev;
SMB_INO_T inode;
- uint32 remotepid;
+ pid_t remotepid;
struct timeval tval;
struct timeval *ptval = NULL;
+ uint16 break_cmd_type;
msg_len = IVAL(buffer,OPBRK_CMD_LEN_OFFSET);
from_port = SVAL(buffer,OPBRK_CMD_PORT_OFFSET);
@@ -398,7 +503,9 @@ BOOL process_local_message(char *buffer, int buf_size)
* Pull the info out of the requesting packet.
*/
- switch(SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET))
+ break_cmd_type = SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET);
+
+ switch(break_cmd_type)
{
#if defined(HAVE_KERNEL_OPLOCKS)
case KERNEL_OPLOCK_BREAK_CMD:
@@ -410,18 +517,8 @@ should be %d).\n", msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
return False;
}
{
- /*
- * Warning - beware of SMB_INO_T <> 4 bytes. !!
- */
-#ifdef LARGE_SMB_INO_T
- SMB_INO_T inode_low = IVAL(msg_start, KERNEL_OPLOCK_BREAK_INODE_OFFSET);
- SMB_INO_T inode_high = IVAL(msg_start, KERNEL_OPLOCK_BREAK_INODE_OFFSET + 4);
- inode = inode_low | (inode_high << 32);
-#else /* LARGE_SMB_INO_T */
- inode = IVAL(msg_start, KERNEL_OPLOCK_BREAK_INODE_OFFSET);
-#endif /* LARGE_SMB_INO_T */
-
- dev = IVAL(msg_start,KERNEL_OPLOCK_BREAK_DEV_OFFSET);
+ memcpy((char *)&inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(inode));
+ memcpy((char *)&dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(dev));
ptval = NULL;
@@ -432,36 +529,34 @@ file dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode));
#endif /* HAVE_KERNEL_OPLOCKS */
case OPLOCK_BREAK_CMD:
+ case LEVEL_II_OPLOCK_BREAK_CMD:
+
/* Ensure that the msg length is correct. */
if(msg_len != OPLOCK_BREAK_MSG_LEN)
{
- DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, \
-should be %d).\n", msg_len, OPLOCK_BREAK_MSG_LEN));
+ DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, should be %d).\n",
+ (int)msg_len, (int)OPLOCK_BREAK_MSG_LEN));
return False;
}
{
- /*
- * Warning - beware of SMB_INO_T <> 4 bytes. !!
- */
-#ifdef LARGE_SMB_INO_T
- SMB_INO_T inode_low = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
- SMB_INO_T inode_high = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET + 4);
- inode = inode_low | (inode_high << 32);
-#else /* LARGE_SMB_INO_T */
- inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
-#endif /* LARGE_SMB_INO_T */
+ long usec;
+ time_t sec;
- dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
-
- tval.tv_sec = (time_t)IVAL(msg_start, OPLOCK_BREAK_SEC_OFFSET);
- tval.tv_usec = (long)IVAL(msg_start, OPLOCK_BREAK_USEC_OFFSET);
+ memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode));
+ memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev));
+ memcpy((char *)&sec, msg_start+OPLOCK_BREAK_SEC_OFFSET,sizeof(sec));
+ tval.tv_sec = sec;
+ memcpy((char *)&usec, msg_start+OPLOCK_BREAK_USEC_OFFSET, sizeof(usec));
+ tval.tv_usec = usec;
ptval = &tval;
- remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
+ memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid));
- DEBUG(5,("process_local_message: oplock break request from \
-pid %d, port %d, dev = %x, inode = %.0f\n", remotepid, from_port, (unsigned int)dev, (double)inode));
+ DEBUG(5,("process_local_message: (%s) oplock break request from \
+pid %d, port %d, dev = %x, inode = %.0f\n",
+ (break_cmd_type == OPLOCK_BREAK_CMD) ? "exclusive" : "level II",
+ (int)remotepid, from_port, (unsigned int)dev, (double)inode));
}
break;
@@ -475,27 +570,17 @@ reply - dumping info.\n"));
if(msg_len != OPLOCK_BREAK_MSG_LEN)
{
DEBUG(0,("process_local_message: ubr: incorrect length for reply \
-(was %d, should be %d).\n", msg_len, OPLOCK_BREAK_MSG_LEN));
+(was %d, should be %d).\n", (int)msg_len, (int)OPLOCK_BREAK_MSG_LEN));
return False;
}
{
- /*
- * Warning - beware of SMB_INO_T <> 4 bytes. !!
- */
-#ifdef LARGE_SMB_INO_T
- SMB_INO_T inode_low = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
- SMB_INO_T inode_high = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET + 4);
- inode = inode_low | (inode_high << 32);
-#else /* LARGE_SMB_INO_T */
- inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
-#endif /* LARGE_SMB_INO_T */
-
- remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
- dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
+ memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode));
+ memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid));
+ memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev));
DEBUG(0,("process_local_message: unsolicited oplock break reply from \
-pid %d, port %d, dev = %x, inode = %.0f\n", remotepid, from_port, (unsigned int)dev, (double)inode));
+pid %d, port %d, dev = %x, inode = %.0f\n", (int)remotepid, from_port, (unsigned int)dev, (double)inode));
}
return False;
@@ -510,9 +595,9 @@ pid %d, port %d, dev = %x, inode = %.0f\n", remotepid, from_port, (unsigned int)
* Now actually process the break request.
*/
- if(global_oplocks_open != 0)
+ if((exclusive_oplocks_open + level_II_oplocks_open) != 0)
{
- if(oplock_break(dev, inode, ptval) == False)
+ if (oplock_break(dev, inode, ptval, False) == False)
{
DEBUG(0,("process_local_message: oplock break failed.\n"));
return False;
@@ -531,7 +616,7 @@ oplocks. Returning success.\n"));
}
/*
- * Do the appropriate reply - none in the kernel case.
+ * Do the appropriate reply - none in the kernel or level II case.
*/
if(SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET) == OPLOCK_BREAK_CMD)
@@ -541,7 +626,7 @@ oplocks. Returning success.\n"));
/* Send the message back after OR'ing in the 'REPLY' bit. */
SSVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD | CMD_REPLY);
- bzero((char *)&toaddr,sizeof(toaddr));
+ memset((char *)&toaddr,'\0',sizeof(toaddr));
toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
toaddr.sin_port = htons(from_port);
toaddr.sin_family = AF_INET;
@@ -550,40 +635,77 @@ oplocks. Returning success.\n"));
(struct sockaddr *)&toaddr, sizeof(toaddr)) < 0)
{
DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n",
- remotepid, strerror(errno)));
+ (int)remotepid, strerror(errno)));
return False;
}
DEBUG(5,("process_local_message: oplock break reply sent to \
pid %d, port %d, for file dev = %x, inode = %.0f\n",
- remotepid, from_port, (unsigned int)dev, (double)inode));
+ (int)remotepid, from_port, (unsigned int)dev, (double)inode));
}
return True;
}
/****************************************************************************
- Process an oplock break directly.
+ Set up an oplock break message.
****************************************************************************/
-static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
+static void prepare_break_message(char *outbuf, files_struct *fsp, BOOL level2)
+{
+ memset(outbuf,'\0',smb_size);
+ set_message(outbuf,8,0,True);
+
+ SCVAL(outbuf,smb_com,SMBlockingX);
+ SSVAL(outbuf,smb_tid,fsp->conn->cnum);
+ SSVAL(outbuf,smb_pid,0xFFFF);
+ SSVAL(outbuf,smb_uid,0);
+ SSVAL(outbuf,smb_mid,0xFFFF);
+ SCVAL(outbuf,smb_vwv0,0xFF);
+ SSVAL(outbuf,smb_vwv2,fsp->fnum);
+ SCVAL(outbuf,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE);
+ SCVAL(outbuf,smb_vwv3+1,level2 ? OPLOCKLEVEL_II : OPLOCKLEVEL_NONE);
+}
+
+/****************************************************************************
+ Function to do the waiting before sending a local break.
+****************************************************************************/
+
+static void wait_before_sending_break(BOOL local_request)
+{
+ extern struct timeval smb_last_time;
+
+ if(local_request) {
+ struct timeval cur_tv;
+ long wait_left = (long)lp_oplock_break_wait_time();
+
+ GetTimeOfDay(&cur_tv);
+
+ wait_left -= ((cur_tv.tv_sec - smb_last_time.tv_sec)*1000) +
+ ((cur_tv.tv_usec - smb_last_time.tv_usec)/1000);
+
+ if(wait_left > 0) {
+ wait_left = MIN(wait_left, 1000);
+ sys_usleep(wait_left * 1000);
+ }
+ }
+}
+
+/****************************************************************************
+ Ensure that we have a valid oplock.
+****************************************************************************/
+
+static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
{
- extern struct current_user current_user;
- extern int Client;
- char *inbuf = NULL;
- char *outbuf = NULL;
files_struct *fsp = NULL;
- time_t start_time;
- BOOL shutdown_server = False;
- connection_struct *saved_conn;
- int saved_vuid;
- pstring saved_dir;
- int break_counter = OPLOCK_BREAK_RESENDS;
if( DEBUGLVL( 3 ) )
{
- dbgtext( "oplock_break: called for dev = %x, inode = %.0f.\n", (unsigned int)dev, (double)inode );
- dbgtext( "Current global_oplocks_open = %d\n", global_oplocks_open );
+ dbgtext( "initial_break_processing: called for dev = %x, inode = %.0f tv_sec = %x, tv_usec = %x.\n",
+ (unsigned int)dev, (double)inode, tval ? (int)tval->tv_sec : 0,
+ tval ? (int)tval->tv_usec : 0);
+ dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n",
+ exclusive_oplocks_open, level_II_oplocks_open );
}
/* We need to search the file open table for the
@@ -594,13 +716,13 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
if(fsp == NULL)
{
/* The file could have been closed in the meantime - return success. */
- if( DEBUGLVL( 0 ) )
+ if( DEBUGLVL( 3 ) )
{
- dbgtext( "oplock_break: cannot find open file with " );
+ dbgtext( "initial_break_processing: cannot find open file with " );
dbgtext( "dev = %x, inode = %.0f ", (unsigned int)dev, (double)inode);
dbgtext( "allowing break to succeed.\n" );
}
- return True;
+ return NULL;
}
/* Ensure we have an oplock on the file */
@@ -612,18 +734,130 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
as we may have just freed it.
*/
- if(!fsp->granted_oplock)
+ if(fsp->oplock_type == NO_OPLOCK)
{
- if( DEBUGLVL( 0 ) )
+ if( DEBUGLVL( 3 ) )
{
- dbgtext( "oplock_break: file %s ", fsp->fsp_name );
+ dbgtext( "initial_break_processing: file %s ", fsp->fsp_name );
dbgtext( "(dev = %x, inode = %.0f) has no oplock.\n", (unsigned int)dev, (double)inode );
dbgtext( "Allowing break to succeed regardless.\n" );
}
- return True;
+ return NULL;
}
- /* mark the oplock break as sent - we don't want to send twice! */
+ return fsp;
+}
+
+/****************************************************************************
+ Process a level II oplock break directly.
+****************************************************************************/
+
+BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token)
+{
+ extern int Client;
+ extern uint32 global_client_caps;
+ char outbuf[128];
+ BOOL got_lock = False;
+ SMB_DEV_T dev = fsp->fd_ptr->dev;
+ SMB_INO_T inode = fsp->fd_ptr->inode;
+
+ /*
+ * We can have a level II oplock even if the client is not
+ * level II oplock aware. In this case just remove the
+ * flags and don't send the break-to-none message to
+ * the client.
+ */
+
+ if (global_client_caps & CAP_LEVEL_II_OPLOCKS) {
+ /*
+ * If we are sending an oplock break due to an SMB sent
+ * by our own client we ensure that we wait at leat
+ * lp_oplock_break_wait_time() milliseconds before sending
+ * the packet. Sending the packet sooner can break Win9x
+ * and has reported to cause problems on NT. JRA.
+ */
+
+ wait_before_sending_break(local_request);
+
+ /* Prepare the SMBlockingX message. */
+
+ prepare_break_message( outbuf, fsp, False);
+ send_smb(Client, outbuf);
+ }
+
+ /*
+ * Now we must update the shared memory structure to tell
+ * everyone else we no longer have a level II oplock on
+ * this open file. If local_request is true then token is
+ * the existing lock on the shared memory area.
+ */
+
+ if(!local_request && lock_share_entry(fsp->conn, dev, inode, &token) == False) {
+ DEBUG(0,("oplock_break_level2: unable to lock share entry for file %s\n", fsp->fsp_name ));
+ } else {
+ got_lock = True;
+ }
+
+ if(remove_share_oplock(token, fsp)==False) {
+ DEBUG(0,("oplock_break_level2: unable to remove level II oplock for file %s\n", fsp->fsp_name ));
+ }
+
+ if (!local_request && got_lock)
+ unlock_share_entry(fsp->conn, dev, inode, token);
+
+ fsp->oplock_type = NO_OPLOCK;
+ level_II_oplocks_open--;
+
+ if(level_II_oplocks_open < 0)
+ {
+ DEBUG(0,("oplock_break_level2: level_II_oplocks_open < 0 (%d). PANIC ERROR\n",
+ level_II_oplocks_open));
+ abort();
+ }
+
+ if( DEBUGLVL( 3 ) )
+ {
+ dbgtext( "oplock_break_level2: returning success for " );
+ dbgtext( "dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
+ dbgtext( "Current level II oplocks_open = %d\n", level_II_oplocks_open );
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Process an oplock break directly.
+****************************************************************************/
+
+static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, BOOL local_request)
+{
+ extern uint32 global_client_caps;
+ extern struct current_user current_user;
+ extern int Client;
+ char *inbuf = NULL;
+ char *outbuf = NULL;
+ files_struct *fsp = NULL;
+ time_t start_time;
+ BOOL shutdown_server = False;
+ BOOL oplock_timeout = False;
+ connection_struct *saved_conn;
+ int saved_vuid;
+ pstring saved_dir;
+ int timeout = (OPLOCK_BREAK_TIMEOUT * 1000);
+ pstring file_name;
+ BOOL using_levelII;
+
+ if((fsp = initial_break_processing(dev, inode, tval)) == NULL)
+ return True;
+
+ /*
+ * Deal with a level II oplock going break to none separately.
+ */
+
+ if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ return oplock_break_level2(fsp, local_request, -1);
+
+ /* Mark the oplock break as sent - we don't want to send twice! */
if (fsp->sent_oplock_break)
{
if( DEBUGLVL( 0 ) )
@@ -641,6 +875,11 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
return False;
}
+ if(global_oplock_break) {
+ DEBUG(0,("ABORT : ABORT : recursion in oplock_break !!!!!\n"));
+ abort();
+ }
+
/* Now comes the horrid part. We must send an oplock break to the client,
and then process incoming messages until we get a close or oplock release.
At this point we know we need a new inbuf/outbuf buffer pair.
@@ -662,25 +901,30 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
return False;
}
+ /*
+ * If we are sending an oplock break due to an SMB sent
+ * by our own client we ensure that we wait at leat
+ * lp_oplock_break_wait_time() milliseconds before sending
+ * the packet. Sending the packet sooner can break Win9x
+ * and has reported to cause problems on NT. JRA.
+ */
+
+ wait_before_sending_break(local_request);
+
/* Prepare the SMBlockingX message. */
- bzero(outbuf,smb_size);
- set_message(outbuf,8,0,True);
- SCVAL(outbuf,smb_com,SMBlockingX);
- SSVAL(outbuf,smb_tid,fsp->conn->cnum);
- SSVAL(outbuf,smb_pid,0xFFFF);
- SSVAL(outbuf,smb_uid,0);
- SSVAL(outbuf,smb_mid,0xFFFF);
- SCVAL(outbuf,smb_vwv0,0xFF);
- SSVAL(outbuf,smb_vwv2,fsp->fnum);
- SCVAL(outbuf,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE);
- /* Change this when we have level II oplocks. */
- SCVAL(outbuf,smb_vwv3+1,OPLOCKLEVEL_NONE);
-
- send_smb(Client, outbuf);
+ if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && !lp_kernel_oplocks() && lp_level2_oplocks(SNUM(fsp->conn))) {
+ using_levelII = True;
+ } else {
+ using_levelII = False;
+ }
+
+ prepare_break_message( outbuf, fsp, using_levelII);
+ /* Remember if we just sent a break to level II on this file. */
+ fsp->sent_oplock_break = using_levelII?
+ LEVEL_II_BREAK_SENT:EXCLUSIVE_BREAK_SENT;
- /* Remember we just sent an oplock break on this file. */
- fsp->sent_oplock_break = True;
+ send_smb(Client, outbuf);
/* We need this in case a readraw crosses on the wire. */
global_oplock_break = True;
@@ -703,40 +947,39 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
/* Save the chain fnum. */
file_chain_save();
- while(OPEN_FSP(fsp) && fsp->granted_oplock)
- {
- if(receive_smb(Client,inbuf,
- (OPLOCK_BREAK_TIMEOUT/OPLOCK_BREAK_RESENDS) * 1000) == False)
- {
+ /*
+ * From Charles Hoch <hoch@exemplary.com>. If the break processing
+ * code closes the file (as it often does), then the fsp pointer here
+ * points to free()'d memory. We *must* revalidate fsp each time
+ * around the loop.
+ */
- /* Isaac suggestd that if a MS client doesn't respond to a
- oplock break request then we might try resending
- it. Certainly it's no worse than just dropping the
- socket! */
- if (smb_read_error == READ_TIMEOUT && break_counter--) {
- DEBUG(2, ( "oplock_break resend\n" ) );
- send_smb(Client, outbuf);
- continue;
- }
+ pstrcpy(file_name, fsp->fsp_name);
+ while((fsp = initial_break_processing(dev, inode, tval)) &&
+ OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ {
+ if(receive_smb(Client,inbuf, timeout) == False)
+ {
/*
* Die if we got an error.
*/
- if (smb_read_error == READ_EOF)
+ if (smb_read_error == READ_EOF) {
DEBUG( 0, ( "oplock_break: end of file from client\n" ) );
-
- if (smb_read_error == READ_ERROR)
+ shutdown_server = True;
+ } else if (smb_read_error == READ_ERROR) {
DEBUG( 0, ("oplock_break: receive_smb error (%s)\n", strerror(errno)) );
-
- if (smb_read_error == READ_TIMEOUT)
+ shutdown_server = True;
+ } else if (smb_read_error == READ_TIMEOUT) {
DEBUG( 0, ( "oplock_break: receive_smb timed out after %d seconds.\n",
OPLOCK_BREAK_TIMEOUT ) );
+ oplock_timeout = True;
+ }
- DEBUGADD( 0, ( "oplock_break failed for file %s ", fsp->fsp_name ) );
+ DEBUGADD( 0, ( "oplock_break failed for file %s ", file_name ) );
DEBUGADD( 0, ( "(dev = %x, inode = %.0f).\n", (unsigned int)dev, (double)inode));
- shutdown_server = True;
break;
}
@@ -758,13 +1001,13 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT)
{
if( DEBUGLVL( 0 ) )
- {
+ {
dbgtext( "oplock_break: no break received from client " );
dbgtext( "within %d seconds.\n", OPLOCK_BREAK_TIMEOUT );
dbgtext( "oplock_break failed for file %s ", fsp->fsp_name );
dbgtext( "(dev = %x, inode = %.0f).\n", (unsigned int)dev, (double)inode );
- }
- shutdown_server = True;
+ }
+ oplock_timeout = True;
break;
}
}
@@ -796,7 +1039,21 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
global_oplock_break = False;
/*
- * If the client did not respond we must die.
+ * If the client timed out then clear the oplock (or go to level II)
+ * and continue. This seems to be what NT does and is better than dropping
+ * the connection.
+ */
+
+ if(oplock_timeout && (fsp = initial_break_processing(dev, inode, tval)) &&
+ OPEN_FSP(fsp) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ {
+ DEBUG(0,("oplock_break: client failure in oplock break in file %s\n", fsp->fsp_name));
+ remove_oplock(fsp);
+ global_client_failed_oplock_break = True; /* Never grant this client an oplock again. */
+ }
+
+ /*
+ * If the client had an error we must die.
*/
if(shutdown_server)
@@ -808,27 +1065,19 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
exit_server("oplock break failure");
}
- if(OPEN_FSP(fsp))
- {
- /* The lockingX reply will have removed the oplock flag
- from the sharemode. */
- release_file_oplock(fsp);
- }
-
/* Santity check - remove this later. JRA */
- if(global_oplocks_open < 0)
+ if(exclusive_oplocks_open < 0)
{
- DEBUG(0,("oplock_break: global_oplocks_open < 0 (%d). PANIC ERROR\n",
- global_oplocks_open));
- exit_server("oplock_break: global_oplocks_open < 0");
+ DEBUG(0,("oplock_break: exclusive_oplocks_open < 0 (%d). PANIC ERROR\n",
+ exclusive_oplocks_open));
+ abort();
}
-
if( DEBUGLVL( 3 ) )
{
dbgtext( "oplock_break: returning success for " );
dbgtext( "dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
- dbgtext( "Current global_oplocks_open = %d\n", global_oplocks_open );
+ dbgtext( "Current exclusive_oplocks_open = %d\n", exclusive_oplocks_open );
}
return True;
@@ -844,9 +1093,11 @@ BOOL request_oplock_break(share_mode_entry *share_entry,
{
char op_break_msg[OPLOCK_BREAK_MSG_LEN];
struct sockaddr_in addr_out;
- int pid = getpid();
+ pid_t pid = getpid();
time_t start_time;
int time_left;
+ long usec;
+ time_t sec;
if(pid == share_entry->pid)
{
@@ -854,36 +1105,34 @@ BOOL request_oplock_break(share_mode_entry *share_entry,
if(share_entry->op_port != global_oplock_port)
{
DEBUG(0,("request_oplock_break: corrupt share mode entry - pid = %d, port = %d \
-should be %d\n", pid, share_entry->op_port, global_oplock_port));
+should be %d\n", (int)pid, share_entry->op_port, global_oplock_port));
return False;
}
DEBUG(5,("request_oplock_break: breaking our own oplock\n"));
/* Call oplock break direct. */
- return oplock_break(dev, inode, &share_entry->time);
+ return oplock_break(dev, inode, &share_entry->time, True);
}
/* We need to send a OPLOCK_BREAK_CMD message to the
port in the share mode entry. */
- SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD);
- SIVAL(op_break_msg,OPLOCK_BREAK_PID_OFFSET,pid);
- SIVAL(op_break_msg,OPLOCK_BREAK_SEC_OFFSET,(uint32)share_entry->time.tv_sec);
- SIVAL(op_break_msg,OPLOCK_BREAK_USEC_OFFSET,(uint32)share_entry->time.tv_usec);
- SIVAL(op_break_msg,OPLOCK_BREAK_DEV_OFFSET,dev);
- /*
- * WARNING - beware of SMB_INO_T <> 4 bytes.
- */
-#ifdef LARGE_SMB_INO_T
- SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET,(inode & 0xFFFFFFFFL));
- SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET+4,((inode >> 32) & 0xFFFFFFFFL));
-#else /* LARGE_SMB_INO_T */
- SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET,inode);
-#endif /* LARGE_SMB_INO_T */
+ if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
+ SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,LEVEL_II_OPLOCK_BREAK_CMD);
+ } else {
+ SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD);
+ }
+ memcpy(op_break_msg+OPLOCK_BREAK_PID_OFFSET,(char *)&pid,sizeof(pid));
+ sec = (time_t)share_entry->time.tv_sec;
+ memcpy(op_break_msg+OPLOCK_BREAK_SEC_OFFSET,(char *)&sec,sizeof(sec));
+ usec = (long)share_entry->time.tv_usec;
+ memcpy(op_break_msg+OPLOCK_BREAK_USEC_OFFSET,(char *)&usec,sizeof(usec));
+ memcpy(op_break_msg+OPLOCK_BREAK_DEV_OFFSET,(char *)&dev,sizeof(dev));
+ memcpy(op_break_msg+OPLOCK_BREAK_INODE_OFFSET,(char *)&inode,sizeof(inode));
/* set the address and port */
- bzero((char *)&addr_out,sizeof(addr_out));
+ memset((char *)&addr_out,'\0',sizeof(addr_out));
addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr_out.sin_port = htons( share_entry->op_port );
addr_out.sin_family = AF_INET;
@@ -891,8 +1140,11 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
if( DEBUGLVL( 3 ) )
{
dbgtext( "request_oplock_break: sending a oplock break message to " );
- dbgtext( "pid %d on port %d ", share_entry->pid, share_entry->op_port );
- dbgtext( "for dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
+ dbgtext( "pid %d on port %d ", (int)share_entry->pid, share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
+ (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec,
+ (int)share_entry->time.tv_usec );
+
}
if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0,
@@ -901,15 +1153,27 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
if( DEBUGLVL( 0 ) )
{
dbgtext( "request_oplock_break: failed when sending a oplock " );
- dbgtext( "break message to pid %d ", share_entry->pid );
+ dbgtext( "break message to pid %d ", (int)share_entry->pid );
dbgtext( "on port %d ", share_entry->op_port );
- dbgtext( "for dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
+ dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
+ (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec,
+ (int)share_entry->time.tv_usec );
dbgtext( "Error was %s\n", strerror(errno) );
}
return False;
}
/*
+ * If we just sent a message to a level II oplock share entry then
+ * we are done and may return.
+ */
+
+ if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
+ DEBUG(3,("request_oplock_break: sent break message to level II entry.\n"));
+ return True;
+ }
+
+ /*
* Now we must await the oplock broken message coming back
* from the target smbd process. Timeout if it fails to
* return in (OPLOCK_BREAK_TIMEOUT + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) seconds.
@@ -929,10 +1193,8 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
FD_ZERO(&fds);
FD_SET(oplock_sock,&fds);
-#if defined(HAVE_KERNEL_OPLOCKS)
- if(lp_kernel_oplocks())
+ if(lp_kernel_oplocks() && (oplock_pipe_read != -1))
FD_SET(oplock_pipe_read,&fds);
-#endif /* HAVE_KERNEL_OPLOCKS */
if(receive_local_message(&fds, op_break_reply, sizeof(op_break_reply),
time_left ? time_left * 1000 : 1) == False)
@@ -942,9 +1204,12 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
if( DEBUGLVL( 0 ) )
{
dbgtext( "request_oplock_break: no response received to oplock " );
- dbgtext( "break request to pid %d ", share_entry->pid );
+ dbgtext( "break request to pid %d ", (int)share_entry->pid );
dbgtext( "on port %d ", share_entry->op_port );
dbgtext( "for dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
+ dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
+ (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec,
+ (int)share_entry->time.tv_usec );
}
/*
@@ -960,9 +1225,11 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
if( DEBUGLVL( 0 ) )
{
dbgtext( "request_oplock_break: error in response received " );
- dbgtext( "to oplock break request to pid %d ", share_entry->pid );
+ dbgtext( "to oplock break request to pid %d ", (int)share_entry->pid );
dbgtext( "on port %d ", share_entry->op_port );
- dbgtext( "for dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
+ dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
+ (unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec,
+ (int)share_entry->time.tv_usec );
dbgtext( "Error was (%s).\n", strerror(errno) );
}
return False;
@@ -1036,16 +1303,17 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
Used as a last ditch attempt to free a space in the
file table when we have run out.
****************************************************************************/
+
BOOL attempt_close_oplocked_file(files_struct *fsp)
{
DEBUG(5,("attempt_close_oplocked_file: checking file %s.\n", fsp->fsp_name));
- if (fsp->open && fsp->granted_oplock && !fsp->sent_oplock_break && (fsp->fd_ptr != NULL)) {
+ if (fsp->open && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !fsp->sent_oplock_break && (fsp->fd_ptr != NULL)) {
/* Try and break the oplock. */
file_fd_struct *fd_ptr = fsp->fd_ptr;
- if(oplock_break( fd_ptr->dev, fd_ptr->inode, &fsp->open_time)) {
+ if(oplock_break( fd_ptr->dev, fd_ptr->inode, &fsp->open_time, True)) {
if(!fsp->open) /* Did the oplock break close the file ? */
return True;
}
diff --git a/source3/smbd/password.c b/source3/smbd/password.c
index e15e08a1af..9792c9ebc8 100644
--- a/source3/smbd/password.c
+++ b/source3/smbd/password.c
@@ -23,6 +23,7 @@
extern int DEBUGLEVEL;
extern int Protocol;
+extern struct in_addr ipzero;
/* users from session setup */
static pstring session_users="";
@@ -31,6 +32,261 @@ extern pstring scope;
extern pstring global_myname;
extern fstring global_myworkgroup;
+/* Data to do lanman1/2 password challenge. */
+static unsigned char saved_challenge[8];
+static BOOL challenge_sent=False;
+
+/*******************************************************************
+Get the next challenge value - no repeats.
+********************************************************************/
+void generate_next_challenge(char *challenge)
+{
+#if 0
+ /*
+ * Leave this ifdef'd out while we test
+ * the new crypto random number generator.
+ * JRA.
+ */
+ unsigned char buf[16];
+ static int counter = 0;
+ struct timeval tval;
+ int v1,v2;
+
+ /* get a sort-of random number */
+ GetTimeOfDay(&tval);
+ v1 = (counter++) + getpid() + tval.tv_sec;
+ v2 = (counter++) * getpid() + tval.tv_usec;
+ SIVAL(challenge,0,v1);
+ SIVAL(challenge,4,v2);
+
+ /* mash it up with md4 */
+ mdfour(buf, (unsigned char *)challenge, 8);
+#else
+ unsigned char buf[8];
+
+ generate_random_buffer(buf,8,False);
+#endif
+ memcpy(saved_challenge, buf, 8);
+ memcpy(challenge,buf,8);
+ challenge_sent = True;
+}
+
+/*******************************************************************
+set the last challenge sent, usually from a password server
+********************************************************************/
+BOOL set_challenge(unsigned char *challenge)
+{
+ memcpy(saved_challenge,challenge,8);
+ challenge_sent = True;
+ return(True);
+}
+
+/*******************************************************************
+get the last challenge sent
+********************************************************************/
+static BOOL last_challenge(unsigned char *challenge)
+{
+ if (!challenge_sent) return(False);
+ memcpy(challenge,saved_challenge,8);
+ return(True);
+}
+
+/* this holds info on user ids that are already validated for this VC */
+static user_struct *validated_users = NULL;
+static int num_validated_users = 0;
+
+/****************************************************************************
+check if a uid has been validated, and return an pointer to the user_struct
+if it has. NULL if not. vuid is biased by an offset. This allows us to
+tell random client vuid's (normally zero) from valid vuids.
+****************************************************************************/
+user_struct *get_valid_user_struct(uint16 vuid)
+{
+ if (vuid == UID_FIELD_INVALID)
+ return NULL;
+ vuid -= VUID_OFFSET;
+ if ((vuid >= (uint16)num_validated_users) ||
+ (validated_users[vuid].uid == (uid_t)-1) || (validated_users[vuid].gid == (gid_t)-1))
+ return NULL;
+ return &validated_users[vuid];
+}
+
+/****************************************************************************
+invalidate a uid
+****************************************************************************/
+void invalidate_vuid(uint16 vuid)
+{
+ user_struct *vuser = get_valid_user_struct(vuid);
+
+ if (vuser == NULL) return;
+
+ vuser->uid = (uid_t)-1;
+ vuser->gid = (gid_t)-1;
+
+ vuser->n_sids = 0;
+
+ /* same number of igroups as groups */
+ vuser->n_groups = 0;
+
+ if (vuser->groups)
+ free((char *)vuser->groups);
+
+ if (vuser->sids)
+ free((char *)vuser->sids);
+
+ vuser->sids = NULL;
+ vuser->groups = NULL;
+}
+
+
+/****************************************************************************
+return a validated username
+****************************************************************************/
+char *validated_username(uint16 vuid)
+{
+ user_struct *vuser = get_valid_user_struct(vuid);
+ if (vuser == NULL)
+ return 0;
+ return(vuser->name);
+}
+
+
+/****************************************************************************
+Setup the groups a user belongs to.
+****************************************************************************/
+int setup_groups(char *user, uid_t uid, gid_t gid, int *p_ngroups, gid_t **p_groups)
+{
+ int i,ngroups;
+ gid_t grp = 0;
+ gid_t *groups = NULL;
+
+ if (-1 == initgroups(user,gid))
+ {
+ DEBUG(0,("Unable to initgroups. Error was %s\n", strerror(errno) ));
+ if (getuid() == 0)
+ {
+ if (gid < 0 || gid > 32767 || uid < 0 || uid > 32767)
+ {
+ DEBUG(0,("This is probably a problem with the account %s\n", user));
+ }
+ }
+ return -1;
+ }
+
+ ngroups = sys_getgroups(0,&grp);
+ if (ngroups <= 0)
+ {
+ ngroups = 32;
+ }
+
+#ifdef NGROUPS_MAX
+ if((groups = (gid_t *)malloc(sizeof(gid_t)*NGROUPS_MAX)) == NULL)
+#else /* NGROUPS_MAX */
+ if((groups = (gid_t *)malloc(sizeof(gid_t)*ngroups)) == NULL)
+#endif /* NGROUPS_MAX */
+ {
+ DEBUG(0,("setup_groups malloc fail !\n"));
+ return -1;
+ }
+
+ ngroups = sys_getgroups(ngroups,groups);
+
+ (*p_ngroups) = ngroups;
+ (*p_groups) = groups;
+
+ DEBUG( 3, ( "%s is in %d groups: ", user, ngroups ) );
+ for (i = 0; i < ngroups; i++ )
+ {
+ DEBUG( 3, ( "%s%d", (i ? ", " : ""), (int)groups[i] ) );
+ }
+ DEBUG( 3, ( "\n" ) );
+
+ return 0;
+}
+
+
+/****************************************************************************
+register a uid/name pair as being valid and that a valid password
+has been given. vuid is biased by an offset. This allows us to
+tell random client vuid's (normally zero) from valid vuids.
+****************************************************************************/
+uint16 register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, BOOL guest)
+{
+ user_struct *vuser;
+ struct passwd *pwfile; /* for getting real name from passwd file */
+
+ /* Ensure no vuid gets registered in share level security. */
+ if(lp_security() == SEC_SHARE)
+ return UID_FIELD_INVALID;
+
+#if 0
+ /*
+ * After observing MS-Exchange services writing to a Samba share
+ * I belive this code is incorrect. Each service does its own
+ * sessionsetup_and_X for the same user, and as each service shuts
+ * down, it does a user_logoff_and_X. As we are consolidating multiple
+ * sessionsetup_and_X's onto the same vuid here, when the first service
+ * shuts down, it invalidates all the open files for the other services.
+ * Hence I am removing this code and forcing each sessionsetup_and_X
+ * to get a new vuid.
+ * Jeremy Allison. (jallison@whistle.com).
+ */
+
+ int i;
+ for(i = 0; i < num_validated_users; i++) {
+ vuser = &validated_users[i];
+ if ( vuser->uid == uid )
+ return (uint16)(i + VUID_OFFSET); /* User already validated */
+ }
+#endif
+
+ validated_users = (user_struct *)Realloc(validated_users,
+ sizeof(user_struct)*
+ (num_validated_users+1));
+
+ if (!validated_users)
+ {
+ DEBUG(0,("Failed to realloc users struct!\n"));
+ num_validated_users = 0;
+ return UID_FIELD_INVALID;
+ }
+
+ vuser = &validated_users[num_validated_users];
+ num_validated_users++;
+
+ vuser->uid = uid;
+ vuser->gid = gid;
+ vuser->guest = guest;
+ fstrcpy(vuser->name,unix_name);
+ fstrcpy(vuser->requested_name,requested_name);
+
+ vuser->n_sids = 0;
+ vuser->sids = NULL;
+
+ vuser->n_groups = 0;
+ vuser->groups = NULL;
+
+ /* Find all the groups this uid is in and store them.
+ Used by become_user() */
+ setup_groups(unix_name,uid,gid,
+ &vuser->n_groups,
+ &vuser->groups);
+
+ DEBUG(3,("uid %d registered to name %s\n",(int)uid,unix_name));
+
+ DEBUG(3, ("Clearing default real name\n"));
+ fstrcpy(vuser->real_name, "<Full Name>\0");
+ if (lp_unix_realname()) {
+ if ((pwfile=sys_getpwnam(vuser->name))!= NULL)
+ {
+ DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
+ fstrcpy(vuser->real_name, pwfile->pw_gecos);
+ }
+ }
+
+ return (uint16)((num_validated_users - 1) + VUID_OFFSET);
+}
+
/****************************************************************************
add a name to the session users list
@@ -71,12 +327,17 @@ static BOOL update_smbpassword_file(char *user, char *password)
DEBUG(0,("getsmbpwnam returned NULL\n"));
return False;
}
-
+
+ /*
+ * Remove the account disabled flag - we are updating the
+ * users password from a login.
+ */
+ smbpw->acct_ctrl &= ~ACB_DISABLED;
+
/* Here, the flag is one, because we want to ignore the
XXXXXXX'd out password */
ret = change_oem_password( smbpw, password, True);
- if (!ret)
- {
+ if (ret == False) {
DEBUG(3,("change_oem_password returned False\n"));
}
@@ -88,16 +349,201 @@ static BOOL update_smbpassword_file(char *user, char *password)
/****************************************************************************
+core of smb password checking routine.
+****************************************************************************/
+BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
+{
+ /* Finish the encryption of part_passwd. */
+ unsigned char p21[21];
+ unsigned char p24[24];
+
+ if (part_passwd == NULL)
+ DEBUG(10,("No password set - allowing access\n"));
+ /* No password set - always true ! */
+ if (part_passwd == NULL)
+ return 1;
+
+ memset(p21,'\0',21);
+ memcpy(p21,part_passwd,16);
+ E_P24(p21, c8, p24);
+#if DEBUG_PASSWORD
+ {
+ int i;
+ DEBUG(100,("Part password (P16) was |"));
+ for(i = 0; i < 16; i++)
+ DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
+ DEBUG(100,("|\n"));
+ DEBUG(100,("Password from client was |"));
+ for(i = 0; i < 24; i++)
+ DEBUG(100,("%X ", (unsigned char)password[i]));
+ DEBUG(100,("|\n"));
+ DEBUG(100,("Given challenge was |"));
+ for(i = 0; i < 8; i++)
+ DEBUG(100,("%X ", (unsigned char)c8[i]));
+ DEBUG(100,("|\n"));
+ DEBUG(100,("Value from encryption was |"));
+ for(i = 0; i < 24; i++)
+ DEBUG(100,("%X ", (unsigned char)p24[i]));
+ DEBUG(100,("|\n"));
+ }
+#endif
+ return (memcmp(p24, password, 24) == 0);
+}
+
+/****************************************************************************
+ Do a specific test for an smb password being correct, given a smb_password and
+ the lanman and NT responses.
+****************************************************************************/
+BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar chal[8],
+ uchar lm_pass[24], uchar nt_pass[24])
+{
+ uchar challenge[8];
+
+ if (!lm_pass || !smb_pass) return(False);
+
+ DEBUG(4,("Checking SMB password for user %s\n",
+ smb_pass->smb_name));
+
+ if(smb_pass->acct_ctrl & ACB_DISABLED) {
+ DEBUG(1,("account for user %s was disabled.\n",
+ smb_pass->smb_name));
+ return(False);
+ }
+
+ if (chal == NULL)
+ {
+ DEBUG(5,("use last SMBnegprot challenge\n"));
+ if (!last_challenge(challenge))
+ {
+ DEBUG(1,("no challenge done - password failed\n"));
+ return False;
+ }
+ }
+ else
+ {
+ DEBUG(5,("challenge received\n"));
+ memcpy(challenge, chal, 8);
+ }
+
+ if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL)) {
+ /* We have the NT MD4 hash challenge available - see if we can
+ use it (ie. does it exist in the smbpasswd file).
+ */
+ DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
+ if (smb_password_check((char *)nt_pass,
+ (uchar *)smb_pass->smb_nt_passwd,
+ challenge)) {
+ DEBUG(4,("NT MD4 password check succeeded\n"));
+ return(True);
+ }
+ DEBUG(4,("NT MD4 password check failed\n"));
+ }
+
+ /* Try against the lanman password. smb_pass->smb_passwd == NULL means
+ no password, allow access. */
+
+ DEBUG(4,("Checking LM MD4 password\n"));
+
+ if((smb_pass->smb_passwd == NULL) &&
+ (smb_pass->acct_ctrl & ACB_PWNOTREQ)) {
+ DEBUG(4,("no password required for user %s\n",
+ smb_pass->smb_name));
+ return True;
+ }
+
+ if((smb_pass->smb_passwd != NULL) &&
+ smb_password_check((char *)lm_pass,
+ (uchar *)smb_pass->smb_passwd, challenge)) {
+ DEBUG(4,("LM MD4 password check succeeded\n"));
+ return(True);
+ }
+
+ DEBUG(4,("LM MD4 password check failed\n"));
+
+ return False;
+}
+
+
+/****************************************************************************
+check if a username/password is OK assuming the password is a 24 byte
+SMB hash
+return True if the password is correct, False otherwise
+****************************************************************************/
+
+BOOL pass_check_smb(char *user, char *domain,
+ uchar *chal, uchar *lm_pwd, uchar *nt_pwd,
+ struct passwd *pwd)
+{
+ struct passwd *pass;
+ struct smb_passwd *smb_pass;
+
+ if (!lm_pwd || !nt_pwd)
+ {
+ return(False);
+ }
+
+ if (pwd != NULL && user == NULL)
+ {
+ pass = (struct passwd *) pwd;
+ user = pass->pw_name;
+ }
+ else
+ {
+ pass = Get_Pwnam(user,True);
+ }
+
+ if (pass == NULL)
+ {
+ DEBUG(1,("Couldn't find user '%s' in UNIX password database.\n",user));
+ return(False);
+ }
+
+ smb_pass = getsmbpwnam(user);
+
+ if (smb_pass == NULL)
+ {
+ DEBUG(1,("Couldn't find user '%s' in smb_passwd file.\n", user));
+ return(False);
+ }
+
+ /* Quit if the account was disabled. */
+ if(smb_pass->acct_ctrl & ACB_DISABLED) {
+ DEBUG(1,("Account for user '%s' was disabled.\n", user));
+ return(False);
+ }
+
+ /* Ensure the uid's match */
+ if (smb_pass->smb_userid != pass->pw_uid)
+ {
+ DEBUG(0,("Error : UNIX and SMB uids in password files do not match for user '%s'!\n", user));
+ return(False);
+ }
+
+ if (lm_pwd[0] == '\0' && IS_BITS_SET_ALL(smb_pass->acct_ctrl, ACB_PWNOTREQ) && lp_null_passwords())
+ {
+ DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", smb_pass->smb_name));
+ return(True);
+ }
+
+ if (smb_password_ok(smb_pass, chal, lm_pwd, nt_pwd))
+ {
+ return(True);
+ }
+
+ DEBUG(2,("pass_check_smb failed - invalid password for user [%s]\n", user));
+ return False;
+}
+
+/****************************************************************************
check if a username/password pair is OK either via the system password
database or the encrypted SMB password database
return True if the password is correct, False otherwise
****************************************************************************/
-BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd,
- uchar user_sess_key[16])
+BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd)
{
- if (pwlen >= 24 || (lp_encrypted_passwords() && (pwlen == 0) && lp_null_passwords()))
+ if (pwlen == 24 || (lp_encrypted_passwords() && (pwlen == 0) && lp_null_passwords()))
{
- /* if 24 bytes or longer assume it is an encrypted password */
+ /* if 24 bytes long assume it is an encrypted password */
uchar challenge[8];
if (!last_challenge(challenge))
@@ -106,10 +552,8 @@ BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd,
return False;
}
- return pass_check_smb(getsmbpwnam(user), global_myworkgroup,
- challenge, (uchar *)password,
- pwlen, (uchar *)password, pwlen,
- pwd, user_sess_key);
+ return pass_check_smb(user, global_myworkgroup,
+ challenge, (uchar *)password, (uchar *)password, pwd);
}
return pass_check(user, password, pwlen, pwd,
@@ -117,71 +561,84 @@ BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd,
update_smbpassword_file : NULL);
}
+/****************************************************************************
+check if a username is valid
+****************************************************************************/
+BOOL user_ok(char *user,int snum)
+{
+ pstring valid, invalid;
+ BOOL ret;
+
+ StrnCpy(valid, lp_valid_users(snum), sizeof(pstring)-1);
+ StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring)-1);
+
+ pstring_sub(valid,"%S",lp_servicename(snum));
+ pstring_sub(invalid,"%S",lp_servicename(snum));
+
+ ret = !user_in_list(user,invalid);
+
+ if (ret && valid && *valid) {
+ ret = user_in_list(user,valid);
+ }
+
+ if (ret && lp_onlyuser(snum)) {
+ char *user_list = lp_username(snum);
+ pstring_sub(user_list,"%S",lp_servicename(snum));
+ ret = user_in_list(user,user_list);
+ }
+
+ return(ret);
+}
+
/****************************************************************************
validate a group username entry. Return the username or NULL
****************************************************************************/
-static char *validate_group(char *group,char *password,int pwlen,int snum,
- uchar user_sess_key[16])
+static char *validate_group(char *group,char *password,int pwlen,int snum)
{
-#if defined(HAVE_NETGROUP) && defined(HAVE_GETNETGRENT) && defined(HAVE_SETNETGRENT) && defined(HAVE_ENDNETGRENT)
- {
- char *host, *user, *domain;
- setnetgrent(group);
- while (getnetgrent(&host, &user, &domain)) {
- if (user) {
- if (user_ok(user, snum) &&
- password_ok(user,password,pwlen,NULL, user_sess_key)) {
- endnetgrent();
- return(user);
+#ifdef HAVE_NETGROUP
+ {
+ char *host, *user, *domain;
+ setnetgrent(group);
+ while (getnetgrent(&host, &user, &domain)) {
+ if (user) {
+ if (user_ok(user, snum) &&
+ password_ok(user,password,pwlen,NULL)) {
+ endnetgrent();
+ return(user);
+ }
+ }
+ }
+ endnetgrent();
}
- }
- }
- endnetgrent();
- }
#endif
-#ifdef HAVE_GETGRNAM
- {
- struct group *gptr = (struct group *)getgrnam(group);
- char **member;
- if (gptr)
- {
- member = gptr->gr_mem;
- while (member && *member)
- {
- static fstring name;
- fstrcpy(name,*member);
- if (user_ok(name,snum) &&
- password_ok(name,password,pwlen,NULL, user_sess_key))
- return(&name[0]);
- member++;
- }
-#ifdef GROUP_CHECK_PWENT
+#ifdef HAVE_GETGRENT
{
- struct passwd *pwd;
- static fstring tm;
-
- setpwent ();
- while (pwd = getpwent ()) {
- if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
- /* This Entry have PASSWORD and same GID then check pwd */
- if (password_ok(NULL, password, pwlen, pwd, user_sess_key)) {
- fstrcpy(tm, pwd->pw_name);
- endpwent ();
- return tm;
- }
- }
- }
- endpwent ();
+ struct group *gptr;
+ char **member;
+ setgrent();
+ while ((gptr = (struct group *)getgrent())) {
+ if (!strequal(gptr->gr_name,group))
+ continue;
+ member = gptr->gr_mem;
+ while (member && *member) {
+ static fstring name;
+ fstrcpy(name,*member);
+ if (user_ok(name,snum) &&
+ password_ok(name,password,pwlen,NULL)) {
+ endgrent();
+ return(&name[0]);
+ }
+ member++;
+ }
+ }
+ endgrent();
}
-#endif /* GROUP_CHECK_PWENT */
- }
- }
#endif
- return(NULL);
+ return(NULL);
}
@@ -221,14 +678,14 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
/* check the given username and password */
if (!ok && (*user) && user_ok(user,snum)) {
- ok = password_ok(user,password, pwlen, NULL, vuser->user_sess_key);
+ ok = password_ok(user,password, pwlen, NULL);
if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
}
/* check for a previously registered guest username */
if (!ok && (vuser != 0) && vuser->guest) {
if (user_ok(vuser->name,snum) &&
- password_ok(vuser->name, password, pwlen, NULL, vuser->user_sess_key)) {
+ password_ok(vuser->name, password, pwlen, NULL)) {
fstrcpy(user, vuser->name);
vuser->guest = False;
DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
@@ -242,7 +699,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
{
char *auser;
char *user_list = strdup(session_users);
- if (!user_list) return False;
+ if (!user_list) return(False);
for (auser=strtok(user_list,LIST_SEP);
!ok && auser;
@@ -252,7 +709,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
fstrcpy(user2,auser);
if (!user_ok(user2,snum)) continue;
- if (password_ok(user2,password, pwlen, NULL, vuser->user_sess_key)) {
+ if (password_ok(user2,password, pwlen, NULL)) {
ok = True;
fstrcpy(user,user2);
DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
@@ -283,7 +740,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
pstring user_list;
StrnCpy(user_list,lp_username(snum),sizeof(pstring));
- string_sub(user_list,"%S",lp_servicename(snum));
+ pstring_sub(user_list,"%S",lp_servicename(snum));
for (auser=strtok(user_list,LIST_SEP);
auser && !ok;
@@ -291,7 +748,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
{
if (*auser == '@')
{
- auser = validate_group(auser+1,password,pwlen,snum, vuser->user_sess_key);
+ auser = validate_group(auser+1,password,pwlen,snum);
if (auser)
{
ok = True;
@@ -304,7 +761,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
fstring user2;
fstrcpy(user2,auser);
if (user_ok(user2,snum) &&
- password_ok(user2,password,pwlen,NULL, vuser->user_sess_key))
+ password_ok(user2,password,pwlen,NULL))
{
ok = True;
fstrcpy(user,user2);
@@ -454,10 +911,10 @@ BOOL check_hosts_equiv(char *user)
{
char *fname = NULL;
pstring rhostsfile;
- const struct passwd *pass = Get_Pwnam(user,True);
+ struct passwd *pass = Get_Pwnam(user,True);
if (!pass)
- return False;
+ return(False);
fname = lp_hosts_equiv();
@@ -470,7 +927,7 @@ BOOL check_hosts_equiv(char *user)
if (lp_use_rhosts())
{
- char *home = get_unixhome_dir(user);
+ char *home = get_user_home_dir(user);
if (home) {
extern int Client;
slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
@@ -479,13 +936,14 @@ BOOL check_hosts_equiv(char *user)
}
}
- return False;
+ return(False);
}
/****************************************************************************
-return the client state structure
+ Return the client state structure.
****************************************************************************/
+
struct cli_state *server_client(void)
{
static struct cli_state pw_cli;
@@ -493,20 +951,77 @@ struct cli_state *server_client(void)
}
/****************************************************************************
-support for server level security
+ Support for server level security.
****************************************************************************/
+
struct cli_state *server_cryptkey(void)
{
- if (cli_connect_serverlist(server_client(), lp_passwordserver()))
- {
- return server_client();
+ struct cli_state *cli;
+ fstring desthost;
+ struct in_addr dest_ip;
+ char *p;
+ BOOL connected_ok = False;
+
+ cli = server_client();
+
+ if (!cli_initialise(cli))
+ return NULL;
+
+ p = lp_passwordserver();
+ while(p && next_token( &p, desthost, LIST_SEP, sizeof(desthost))) {
+ standard_sub_basic(desthost);
+ strupper(desthost);
+
+ if(!resolve_name( desthost, &dest_ip, 0x20)) {
+ DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
+ continue;
+ }
+
+ if (ismyip(dest_ip)) {
+ DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
+ continue;
+ }
+
+ if (cli_connect(cli, desthost, &dest_ip)) {
+ DEBUG(3,("connected to password server %s\n",desthost));
+ connected_ok = True;
+ break;
+ }
+ }
+
+ if (!connected_ok) {
+ DEBUG(0,("password server not available\n"));
+ cli_shutdown(cli);
+ return NULL;
}
- return NULL;
+
+ if (!attempt_netbios_session_request(cli, global_myname, desthost, &dest_ip))
+ return NULL;
+
+ DEBUG(3,("got session\n"));
+
+ if (!cli_negprot(cli)) {
+ DEBUG(1,("%s rejected the negprot\n",desthost));
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ if (cli->protocol < PROTOCOL_LANMAN2 ||
+ !(cli->sec_mode & 1)) {
+ DEBUG(1,("%s isn't in user level security mode\n",desthost));
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ DEBUG(3,("password server OK\n"));
+
+ return cli;
}
/****************************************************************************
-validate a password with the password server
+ Validate a password with the password server.
****************************************************************************/
+
BOOL server_validate(char *user, char *domain,
char *pass, int passlen,
char *ntpass, int ntpasslen)
@@ -520,7 +1035,7 @@ BOOL server_validate(char *user, char *domain,
if (!cli->initialised) {
DEBUG(1,("password server %s is not connected\n", cli->desthost));
- return False;
+ return(False);
}
if(badpass[0] == 0)
@@ -541,8 +1056,7 @@ BOOL server_validate(char *user, char *domain,
*/
if(!tested_password_server) {
- if (cli_session_setup(cli, global_myname,
- user, (char *)badpass, sizeof(badpass),
+ if (cli_session_setup(cli, user, (char *)badpass, sizeof(badpass),
(char *)badpass, sizeof(badpass), domain)) {
/*
@@ -587,8 +1101,7 @@ use this machine as the password server.\n"));
* not guest enabled, we can try with the real password.
*/
- if (!cli_session_setup(cli, global_myname,
- user, pass, passlen, ntpass, ntpasslen, domain)) {
+ if (!cli_session_setup(cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
DEBUG(1,("password server %s rejected the password\n", cli->desthost));
return False;
}
@@ -597,12 +1110,365 @@ use this machine as the password server.\n"));
if ((SVAL(cli->inbuf,smb_vwv2) & 1) != 0) {
DEBUG(1,("password server %s gave us guest only\n", cli->desthost));
cli_ulogoff(cli);
- return False;
+ return(False);
}
-
cli_ulogoff(cli);
return(True);
}
+/***********************************************************************
+ Connect to a remote machine for domain security authentication
+ given a name or IP address.
+************************************************************************/
+
+static BOOL connect_to_domain_password_server(struct cli_state *pcli, char *remote_machine,
+ unsigned char *trust_passwd)
+{
+ struct in_addr dest_ip;
+
+ if(cli_initialise(pcli) == False) {
+ DEBUG(0,("connect_to_domain_password_server: unable to initialize client connection.\n"));
+ return False;
+ }
+
+ standard_sub_basic(remote_machine);
+ strupper(remote_machine);
+
+ if(!resolve_name( remote_machine, &dest_ip, 0x20)) {
+ DEBUG(1,("connect_to_domain_password_server: Can't resolve address for %s\n", remote_machine));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (ismyip(dest_ip)) {
+ DEBUG(1,("connect_to_domain_password_server: Password server loop - not using password server %s\n",
+ remote_machine));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (!cli_connect(pcli, remote_machine, &dest_ip)) {
+ DEBUG(0,("connect_to_domain_password_server: unable to connect to SMB server on \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (!attempt_netbios_session_request(pcli, global_myname, remote_machine, &dest_ip)) {
+ DEBUG(0,("connect_to_password_server: machine %s rejected the NetBIOS \
+session request. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ return False;
+ }
+
+ pcli->protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(pcli)) {
+ DEBUG(0,("connect_to_domain_password_server: machine %s rejected the negotiate protocol. \
+Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (pcli->protocol != PROTOCOL_NT1) {
+ DEBUG(0,("connect_to_domain_password_server: machine %s didn't negotiate NT protocol.\n",
+ remote_machine));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ /*
+ * Do an anonymous session setup.
+ */
+
+ if (!cli_session_setup(pcli, "", "", 0, "", 0, "")) {
+ DEBUG(0,("connect_to_domain_password_server: machine %s rejected the session setup. \
+Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (!(pcli->sec_mode & 1)) {
+ DEBUG(1,("connect_to_domain_password_server: machine %s isn't in user level security mode\n",
+ remote_machine));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (!cli_send_tconX(pcli, "IPC$", "IPC", "", 1)) {
+ DEBUG(0,("connect_to_domain_password_server: machine %s rejected the tconX on the IPC$ share. \
+Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ /*
+ * We now have an anonymous connection to IPC$ on the domain password server.
+ */
+
+ /*
+ * Even if the connect succeeds we need to setup the netlogon
+ * pipe here. We do this as we may just have changed the domain
+ * account password on the PDC and yet we may be talking to
+ * a BDC that doesn't have this replicated yet. In this case
+ * a successful connect to a DC needs to take the netlogon connect
+ * into account also. This patch from "Bjart Kvarme" <bjart.kvarme@usit.uio.no>.
+ */
+
+ if(cli_nt_session_open(pcli, PIPE_NETLOGON) == False) {
+ DEBUG(0,("connect_to_domain_password_server: unable to open the domain client session to \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
+ cli_nt_session_close(pcli);
+ cli_ulogoff(pcli);
+ cli_shutdown(pcli);
+ return False;
+ }
+
+ if (cli_nt_setup_creds(pcli, trust_passwd) == False) {
+ DEBUG(0,("connect_to_domain_password_server: unable to setup the PDC credentials to machine \
+%s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
+ cli_nt_session_close(pcli);
+ cli_ulogoff(pcli);
+ cli_shutdown(pcli);
+ return(False);
+ }
+
+ return True;
+}
+
+/***********************************************************************
+ Utility function to attempt a connection to an IP address of a DC.
+************************************************************************/
+
+static BOOL attempt_connect_to_dc(struct cli_state *pcli, struct in_addr *ip, unsigned char *trust_passwd)
+{
+ fstring dc_name;
+
+ /*
+ * Ignore addresses we have already tried.
+ */
+
+ if(ip_equal(ipzero, *ip))
+ return False;
+
+ if(!lookup_pdc_name(global_myname, lp_workgroup(), ip, dc_name))
+ return False;
+
+ return connect_to_domain_password_server(pcli, dc_name, trust_passwd);
+}
+
+/***********************************************************************
+ Do the same as security=server, but using NT Domain calls and a session
+ key from the machine password.
+************************************************************************/
+
+BOOL domain_client_validate( char *user, char *domain,
+ char *smb_apasswd, int smb_apasslen,
+ char *smb_ntpasswd, int smb_ntpasslen,
+ BOOL *user_exists)
+{
+ unsigned char local_challenge[8];
+ unsigned char local_lm_response[24];
+ unsigned char local_nt_reponse[24];
+ unsigned char trust_passwd[16];
+ fstring remote_machine;
+ char *p;
+ NET_ID_INFO_CTR ctr;
+ NET_USER_INFO_3 info3;
+ struct cli_state cli;
+ uint32 smb_uid_low;
+ BOOL connected_ok = False;
+
+ if(user_exists != NULL)
+ *user_exists = True; /* Only set false on a very specific error. */
+
+ /*
+ * Check that the requested domain is not our own machine name.
+ * If it is, we should never check the PDC here, we use our own local
+ * password file.
+ */
+
+ if(strequal( domain, global_myname)) {
+ DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
+ return False;
+ }
+
+ /*
+ * Next, check that the passwords given were encrypted.
+ */
+
+ if(((smb_apasslen != 24) && (smb_apasslen != 0)) ||
+ ((smb_ntpasslen != 24) && (smb_ntpasslen != 0))) {
+
+ /*
+ * Not encrypted - do so.
+ */
+
+ DEBUG(3,("domain_client_validate: User passwords not in encrypted format.\n"));
+ generate_random_buffer( local_challenge, 8, False);
+ SMBencrypt( (uchar *)smb_apasswd, local_challenge, local_lm_response);
+ SMBNTencrypt((uchar *)smb_ntpasswd, local_challenge, local_nt_reponse);
+ smb_apasslen = 24;
+ smb_ntpasslen = 24;
+ smb_apasswd = (char *)local_lm_response;
+ smb_ntpasswd = (char *)local_nt_reponse;
+ } else {
+
+ /*
+ * Encrypted - get the challenge we sent for these
+ * responses.
+ */
+
+ if (!last_challenge(local_challenge)) {
+ DEBUG(0,("domain_client_validate: no challenge done - password failed\n"));
+ return False;
+ }
+ }
+
+ /*
+ * Get the machine account password.
+ */
+ if (!trust_get_passwd( trust_passwd, global_myworkgroup, global_myname))
+ {
+ return False;
+ }
+
+ /*
+ * At this point, smb_apasswd points to the lanman response to
+ * the challenge in local_challenge, and smb_ntpasswd points to
+ * the NT response to the challenge in local_challenge. Ship
+ * these over the secure channel to a domain controller and
+ * see if they were valid.
+ */
+
+ ZERO_STRUCT(cli);
+
+ /*
+ * Treat each name in the 'password server =' line as a potential
+ * PDC/BDC. Contact each in turn and try and authenticate.
+ */
+
+ p = lp_passwordserver();
+ while(!connected_ok && p &&
+ next_token(&p,remote_machine,LIST_SEP,sizeof(remote_machine))) {
+ if(strequal(remote_machine, "*")) {
+
+ /*
+ * We have been asked to dynamcially determine the IP addresses of
+ * the PDC and BDC's for this DOMAIN, and query them in turn.
+ */
+
+ struct in_addr *ip_list = NULL;
+ int count = 0;
+ int i;
+
+ if(!get_dc_list(lp_workgroup(), &ip_list, &count))
+ continue;
+
+ /*
+ * Firstly try and contact a PDC/BDC who has the same
+ * network address as any of our interfaces.
+ */
+
+ for(i = 0; i < count; i++) {
+ if(!is_local_net(ip_list[i]))
+ continue;
+
+ if((connected_ok = attempt_connect_to_dc(&cli, &ip_list[i], trust_passwd)))
+ break;
+
+ ip_list[i] = ipzero; /* Tried and failed. */
+ }
+
+ /*
+ * Secondly try and contact a random PDC/BDC.
+ */
+
+ if(!connected_ok) {
+ i = (sys_random() % count);
+
+ if(!(connected_ok = attempt_connect_to_dc(&cli, &ip_list[i], trust_passwd)))
+ ip_list[i] = ipzero; /* Tried and failed. */
+ }
+
+ /*
+ * Finally go through the IP list in turn, ignoring any addresses
+ * we have already tried.
+ */
+
+ if(!connected_ok) {
+
+ /*
+ * Try and connect to any of the other IP addresses in the PDC/BDC list.
+ * Note that from a WINS server the #1 IP address is the PDC.
+ */
+
+ for(i = 0; i < count; i++) {
+ if((connected_ok = attempt_connect_to_dc(&cli, &ip_list[i], trust_passwd)))
+ break;
+ }
+ }
+
+ if(ip_list != NULL)
+ free((char *)ip_list);
+
+ } else {
+ connected_ok = connect_to_domain_password_server(&cli, remote_machine, trust_passwd);
+ }
+ }
+
+ if (!connected_ok) {
+ DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ /* We really don't care what LUID we give the user. */
+ generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
+
+ if(cli_nt_login_network(&cli, domain, user, smb_uid_low, (char *)local_challenge,
+ ((smb_apasslen != 0) ? smb_apasswd : NULL),
+ ((smb_ntpasslen != 0) ? smb_ntpasswd : NULL),
+ &ctr, &info3) == False) {
+ uint32 nt_rpc_err;
+
+ cli_error(&cli, NULL, NULL, &nt_rpc_err);
+ DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
+%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
+ cli_nt_session_close(&cli);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+
+ if((nt_rpc_err == NT_STATUS_NO_SUCH_USER) && (user_exists != NULL))
+ *user_exists = False;
+
+ return False;
+ }
+
+ /*
+ * Here, if we really want it, we have lots of info about the user in info3.
+ */
+
+#if 0
+ /*
+ * We don't actually need to do this - plus it fails currently with
+ * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
+ * send here. JRA.
+ */
+
+ if(cli_nt_logoff(&cli, &ctr) == False) {
+ DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
+%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
+ cli_nt_session_close(&cli);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+ return False;
+ }
+#endif /* 0 */
+
+ cli_nt_session_close(&cli);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+ return True;
+}
diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c
index e20d049834..15f52c0af6 100644
--- a/source3/smbd/pipes.c
+++ b/source3/smbd/pipes.c
@@ -74,10 +74,16 @@ int reply_open_pipe_and_X(connection_struct *conn,
/* Strip \PIPE\ off the name. */
pstrcpy(fname,smb_buf(inbuf) + PIPELEN);
+ /*
+ * Hack for NT printers... JRA.
+ */
+ if(should_fail_next_srvsvc_open(fname))
+ return(ERROR(ERRSRV,ERRaccess));
+
/* Known pipes arrive with DIR attribs. Remove it so a regular file */
/* can be opened and add it in after the open. */
DEBUG(3,("Known pipe %s opening.\n",fname));
- smb_ofun |= 0x10; /* Add Create it not exists flag */
+ smb_ofun |= FILE_CREATE_IF_NOT_EXIST;
p = open_rpc_pipe_p(fname, conn, vuid);
if (!p) return(ERROR(ERRSRV,ERRnofids));
@@ -105,45 +111,37 @@ int reply_open_pipe_and_X(connection_struct *conn,
}
/****************************************************************************
- reply to a write
-
- This code is basically stolen from reply_write with some
- wrinkles to handle pipes.
+ reply to a write on a pipe
****************************************************************************/
-int reply_pipe_write(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_pipe_write(char *inbuf,char *outbuf,int length,int dum_bufsize)
{
pipes_struct *p = get_rpc_pipe_p(inbuf,smb_vwv0);
size_t numtowrite = SVAL(inbuf,smb_vwv1);
- int nwritten = -1;
+ int nwritten;
+ int outsize;
char *data;
- size_t outsize;
- if (!p) return(ERROR(ERRDOS,ERRbadfid));
+ if (!p)
+ return(ERROR(ERRDOS,ERRbadfid));
data = smb_buf(inbuf) + 3;
if (numtowrite == 0)
- {
nwritten = 0;
- }
else
- {
- nwritten = write_pipe(p, data, numtowrite);
- }
+ nwritten = write_to_pipe(p, data, numtowrite);
if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0))
- {
return (UNIXERROR(ERRDOS,ERRnoaccess));
- }
outsize = set_message(outbuf,1,0,True);
SSVAL(outbuf,smb_vwv0,nwritten);
-
+
DEBUG(3,("write-IPC pnum=%04x nwritten=%d\n",
p->pnum, nwritten));
- return outsize;
+ return(outsize);
}
/****************************************************************************
@@ -160,23 +158,18 @@ int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
int smb_doff = SVAL(inbuf, smb_vwv11);
char *data;
- if (!p) return(ERROR(ERRDOS,ERRbadfid));
+ if (!p)
+ return(ERROR(ERRDOS,ERRbadfid));
data = smb_base(inbuf) + smb_doff;
if (numtowrite == 0)
- {
nwritten = 0;
- }
else
- {
- nwritten = write_pipe(p, data, numtowrite);
- }
+ nwritten = write_to_pipe(p, data, numtowrite);
if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0))
- {
return (UNIXERROR(ERRDOS,ERRnoaccess));
- }
set_message(outbuf,6,0,True);
@@ -197,18 +190,24 @@ int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
{
pipes_struct *p = get_rpc_pipe_p(inbuf,smb_vwv2);
- uint32 smb_offs = IVAL(inbuf,smb_vwv3);
int smb_maxcnt = SVAL(inbuf,smb_vwv5);
int smb_mincnt = SVAL(inbuf,smb_vwv6);
int nread = -1;
char *data;
+ /* we don't use the offset given to use for pipe reads. This
+ is deliberate, instead we always return the next lump of
+ data on the pipe */
+#if 0
+ uint32 smb_offs = IVAL(inbuf,smb_vwv3);
+#endif
- if (!p) return(ERROR(ERRDOS,ERRbadfid));
+ if (!p)
+ return(ERROR(ERRDOS,ERRbadfid));
set_message(outbuf,12,0,True);
data = smb_buf(outbuf);
- nread = read_pipe(p, data, smb_offs, smb_maxcnt);
+ nread = read_from_pipe(p, data, smb_maxcnt);
if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -231,12 +230,13 @@ int reply_pipe_close(connection_struct *conn, char *inbuf,char *outbuf)
pipes_struct *p = get_rpc_pipe_p(inbuf,smb_vwv0);
int outsize = set_message(outbuf,0,0,True);
- if (!p) return(ERROR(ERRDOS,ERRbadfid));
+ if (!p)
+ return(ERROR(ERRDOS,ERRbadfid));
DEBUG(5,("reply_pipe_close: pnum:%x\n", p->pnum));
- if (!close_rpc_pipe_hnd(p, conn)) return(ERROR(ERRDOS,ERRbadfid));
+ if (!close_rpc_pipe_hnd(p, conn))
+ return(ERROR(ERRDOS,ERRbadfid));
return(outsize);
}
-
diff --git a/source3/smbd/predict.c b/source3/smbd/predict.c
index f51e54a568..de85a4a553 100644
--- a/source3/smbd/predict.c
+++ b/source3/smbd/predict.c
@@ -37,12 +37,12 @@ static int rp_timeout = 5;
static time_t rp_time = 0;
static char *rp_buffer = NULL;
static BOOL predict_skip=False;
-extern time_t smb_last_time;
+extern struct timeval smb_last_time;
/****************************************************************************
handle read prediction on a file
****************************************************************************/
-ssize_t read_predict(files_struct *fsp, int fd,SMB_OFF_T offset,char *buf,char **ptr,size_t num)
+ssize_t read_predict(int fd,SMB_OFF_T offset,char *buf,char **ptr,size_t num)
{
ssize_t ret = 0;
ssize_t possible = rp_length - (offset - rp_offset);
@@ -53,7 +53,7 @@ ssize_t read_predict(files_struct *fsp, int fd,SMB_OFF_T offset,char *buf,char *
if (fd == rp_fd &&
offset >= rp_offset &&
possible>0 &&
- smb_last_time-rp_time < rp_timeout)
+ smb_last_time.tv_secs - rp_time < rp_timeout)
{
ret = possible;
if (buf)
@@ -70,7 +70,7 @@ ssize_t read_predict(files_struct *fsp, int fd,SMB_OFF_T offset,char *buf,char *
/* Find the end of the file - ensure we don't
read predict beyond it. */
- if(fsp->conn->vfs_ops.fstat(fd,&rp_stat) < 0)
+ if(sys_fstat(fd,&rp_stat) < 0)
{
DEBUG(0,("read-prediction failed on fstat. Error was %s\n", strerror(errno)));
predict_skip = True;
@@ -95,7 +95,7 @@ ssize_t read_predict(files_struct *fsp, int fd,SMB_OFF_T offset,char *buf,char *
/****************************************************************************
pre-read some data
****************************************************************************/
-void do_read_prediction(connection_struct *conn)
+void do_read_prediction(void)
{
static size_t readsize = 0;
@@ -134,13 +134,13 @@ void do_read_prediction(connection_struct *conn)
}
}
- if (conn->vfs_ops.lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) {
+ if (sys_lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) {
rp_fd = -1;
rp_predict_fd = -1;
return;
}
- rp_length = conn->vfs_ops.read(rp_fd,rp_buffer,rp_predict_length);
+ rp_length = read(rp_fd,rp_buffer,rp_predict_length);
rp_time = time(NULL);
if (rp_length < 0)
rp_length = 0;
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 95222d3f51..7e94ffa173 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -23,7 +23,7 @@
extern int DEBUGLEVEL;
-time_t smb_last_time=(time_t)0;
+struct timeval smb_last_time;
char *InBuffer = NULL;
char *OutBuffer = NULL;
@@ -48,7 +48,7 @@ extern char *last_inbuf;
extern char *InBuffer;
extern char *OutBuffer;
extern int smb_read_error;
-extern BOOL reload_after_sighup;
+extern VOLATILE SIG_ATOMIC_T reload_after_sighup;
extern BOOL global_machine_password_needs_changing;
extern fstring global_myworkgroup;
extern pstring global_myname;
@@ -173,7 +173,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len,
to.tv_sec = timeout / 1000;
to.tv_usec = (timeout % 1000) * 1000;
- selrtn = sys_select(MAX(maxfd,Client)+1,&fds,NULL, timeout>0?&to:NULL);
+ selrtn = sys_select(MAX(maxfd,Client)+1,&fds,timeout>0?&to:NULL);
/* Check if error */
if(selrtn == -1) {
@@ -231,6 +231,52 @@ BOOL receive_next_smb(char *inbuf, int bufsize, int timeout)
return ret;
}
+/****************************************************************************
+ We're terminating and have closed all our files/connections etc.
+ If there are any pending local messages we need to respond to them
+ before termination so that other smbds don't think we just died whilst
+ holding oplocks.
+****************************************************************************/
+
+void respond_to_all_remaining_local_messages(void)
+{
+ char buffer[1024];
+ fd_set fds;
+
+ /*
+ * Assert we have no exclusive open oplocks.
+ */
+
+ if(get_number_of_exclusive_open_oplocks()) {
+ DEBUG(0,("respond_to_all_remaining_local_messages: PANIC : we have %d exclusive oplocks.\n",
+ get_number_of_exclusive_open_oplocks() ));
+ return;
+ }
+
+ /*
+ * Setup the select read fd set.
+ */
+
+ FD_ZERO(&fds);
+ if(!setup_oplock_select_set(&fds))
+ return;
+
+ /*
+ * Keep doing receive_local_message with a 1 ms timeout until
+ * we have no more messages.
+ */
+
+ while(receive_local_message(&fds, buffer, sizeof(buffer), 1)) {
+ /* Deal with oplock break requests from other smbd's. */
+ process_local_message(buffer, sizeof(buffer));
+
+ FD_ZERO(&fds);
+ (void)setup_oplock_select_set(&fds);
+ }
+
+ return;
+}
+
/*
These flags determine some of the permissions required to do an operation
@@ -283,8 +329,8 @@ struct smb_message_struct
{SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
{SMBread,"SMBread",reply_read,AS_USER},
- {SMBwrite,"SMBwrite",reply_write,AS_USER | CAN_IPC},
- {SMBclose,"SMBclose",reply_close,AS_USER | CAN_IPC},
+ {SMBwrite,"SMBwrite",reply_write,AS_USER | CAN_IPC },
+ {SMBclose,"SMBclose",reply_close,AS_USER | CAN_IPC },
{SMBmkdir,"SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
{SMBrmdir,"SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
{SMBdskattr,"SMBdskattr",reply_dskattr,AS_USER},
@@ -319,9 +365,9 @@ struct smb_message_struct
{SMBwriteBmpx,"SMBwriteBmpx",reply_writebmpx,AS_USER},
{SMBwriteBs,"SMBwriteBs",reply_writebs,AS_USER},
{SMBwritec,"SMBwritec",NULL,AS_USER},
- {SMBsetattrE,"SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE},
- {SMBgetattrE,"SMBgetattrE",reply_getattrE,AS_USER},
- {SMBtrans,"SMBtrans",reply_trans,AS_USER | CAN_IPC},
+ {SMBsetattrE,"SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
+ {SMBgetattrE,"SMBgetattrE",reply_getattrE,AS_USER },
+ {SMBtrans,"SMBtrans",reply_trans,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK},
{SMBtranss,"SMBtranss",NULL,AS_USER | CAN_IPC},
{SMBioctls,"SMBioctls",NULL,AS_USER},
{SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
@@ -330,7 +376,7 @@ struct smb_message_struct
{SMBopenX,"SMBopenX",reply_open_and_X,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
{SMBreadX,"SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
{SMBwriteX,"SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
- {SMBlockingX,"SMBlockingX",reply_lockingX,AS_USER},
+ {SMBlockingX,"SMBlockingX",reply_lockingX,AS_USER },
{SMBffirst,"SMBffirst",reply_search,AS_USER},
{SMBfunique,"SMBfunique",reply_search,AS_USER},
@@ -339,14 +385,14 @@ struct smb_message_struct
/* LANMAN2.0 PROTOCOL FOLLOWS */
{SMBfindnclose, "SMBfindnclose", reply_findnclose, AS_USER},
{SMBfindclose, "SMBfindclose", reply_findclose,AS_USER},
- {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER | CAN_IPC},
+ {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER | QUEUE_IN_OPLOCK },
{SMBtranss2, "SMBtranss2", reply_transs2, AS_USER},
/* NT PROTOCOL FOLLOWS */
{SMBntcreateX, "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
- {SMBnttrans, "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
+ {SMBnttrans, "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK},
{SMBnttranss, "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
- {SMBntcancel, "SMBntcancel", reply_ntcancel, AS_USER },
+ {SMBntcancel, "SMBntcancel", reply_ntcancel, 0 },
/* messaging routines */
{SMBsends,"SMBsends",reply_sends,AS_GUEST},
@@ -368,14 +414,14 @@ do a switch on the message type, and return the response size
****************************************************************************/
static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize)
{
- static int pid= -1;
+ static pid_t pid= (pid_t)-1;
int outsize = 0;
static int num_smb_messages =
sizeof(smb_messages) / sizeof(struct smb_message_struct);
int match;
extern int Client;
- if (pid == -1)
+ if (pid == (pid_t)-1)
pid = getpid();
errno = 0;
@@ -399,21 +445,25 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
}
else
{
- DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,pid));
+ DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,(int)pid));
- if(global_oplock_break && (smb_messages[match].flags & QUEUE_IN_OPLOCK))
+ if(global_oplock_break)
{
- /*
- * Queue this message as we are the process of an oplock break.
- */
+ int flags = smb_messages[match].flags;
- DEBUG( 2, ( "switch_message: queueing message due to being in " ) );
- DEBUGADD( 2, ( "oplock break state.\n" ) );
+ if(flags & QUEUE_IN_OPLOCK)
+ {
+ /*
+ * Queue this message as we are the process of an oplock break.
+ */
- push_oplock_pending_smb_message( inbuf, size );
- return -1;
- }
+ DEBUG( 2, ( "switch_message: queueing message due to being in " ) );
+ DEBUGADD( 2, ( "oplock break state.\n" ) );
+ push_oplock_pending_smb_message( inbuf, size );
+ return -1;
+ }
+ }
if (smb_messages[match].fn)
{
int flags = smb_messages[match].flags;
@@ -508,7 +558,7 @@ static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
int msg_type = CVAL(inbuf,0);
extern int chain_size;
- smb_last_time = time(NULL);
+ GetTimeOfDay(&smb_last_time);
chain_size = 0;
file_chain_reset();
@@ -640,7 +690,7 @@ char *smb_fn_name(int type)
void construct_reply_common(char *inbuf,char *outbuf)
{
- bzero(outbuf,smb_size);
+ memset(outbuf,'\0',smb_size);
set_message(outbuf,0,0,True);
CVAL(outbuf,smb_com) = CVAL(inbuf,smb_com);
@@ -687,6 +737,14 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
orig_outbuf = outbuf;
}
+ /*
+ * The original Win95 redirector dies on a reply to
+ * a lockingX and read chain unless the chain reply is
+ * 4 byte aligned. JRA.
+ */
+
+ outsize = (outsize + 3) & ~3;
+
/* we need to tell the client where the next part of the reply will be */
SSVAL(outbuf,smb_vwv1,smb_offset(outbuf+outsize,outbuf));
CVAL(outbuf,smb_vwv0) = smb_com2;
@@ -741,234 +799,271 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
}
/****************************************************************************
- process commands from the client
+ Setup the needed select timeout.
****************************************************************************/
-void smbd_process(void)
+
+static int setup_select_timeout(void)
{
- extern int Client;
- extern int ClientPort;
+ int change_notify_timeout = lp_change_notify_timeout() * 1000;
+ int select_timeout;
- InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- if ((InBuffer == NULL) || (OutBuffer == NULL))
- return;
+ /*
+ * Increase the select timeout back to SMBD_SELECT_TIMEOUT if we
+ * have removed any blocking locks. JRA.
+ */
- InBuffer += SMB_ALIGNMENT;
- OutBuffer += SMB_ALIGNMENT;
+ select_timeout = blocking_locks_pending() ? SMBD_SELECT_TIMEOUT_WITH_PENDING_LOCKS*1000 :
+ SMBD_SELECT_TIMEOUT*1000;
+
+ if (change_notifies_pending())
+ select_timeout = MIN(select_timeout, change_notify_timeout);
+
+ return select_timeout;
+}
+
+/****************************************************************************
+ Check if services need reloading.
+****************************************************************************/
+
+void check_reload(int t)
+{
+ static time_t last_smb_conf_reload_time = 0;
+
+ if(last_smb_conf_reload_time == 0)
+ last_smb_conf_reload_time = t;
-#if PRIME_NMBD
- DEBUG(3,("priming nmbd\n"));
+ if (reload_after_sighup || (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK))
{
- struct in_addr ip;
- ip = *interpret_addr2("localhost");
- if (zero_ip(ip)) ip = *interpret_addr2("127.0.0.1");
- *OutBuffer = 0;
- send_one_packet(OutBuffer,1,ip,NMB_PORT,SOCK_DGRAM);
+ reload_services(True);
+ reload_after_sighup = False;
+ last_smb_conf_reload_time = t;
}
-#endif
+}
+/****************************************************************************
+ Process any timeout housekeeping. Return False if the caler should exit.
+****************************************************************************/
- max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
+static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_timeout_processing_time)
+{
+ extern int Client;
+ static time_t last_keepalive_sent_time = 0;
+ static time_t last_idle_closed_check = 0;
+ time_t t;
+ BOOL allidle = True;
+ extern int keepalive;
- /* re-initialise the timezone */
- TimeInit();
+ if (smb_read_error == READ_EOF)
+ {
+ DEBUG(3,("end of file from client\n"));
+ return False;
+ }
- /* if connection on port 445, fake session setup... */
- if(ClientPort == 445)
+ if (smb_read_error == READ_ERROR)
{
- extern fstring remote_machine;
- extern fstring local_machine;
+ DEBUG(3,("receive_smb error (%s) exiting\n",
+ strerror(errno)));
+ return False;
+ }
- fstrcpy(remote_machine, dns_to_netbios_name(client_name(Client)));
- fstrcpy(local_machine, global_myname);
- remote_machine[15] = 0;
- local_machine[15] = 0;
- strlower(remote_machine);
- strlower(local_machine);
+ *last_timeout_processing_time = t = time(NULL);
- DEBUG(2, ("smbd_process(): faking session setup\n"
- "client_name: %s my_name: %s\n", remote_machine, local_machine));
+ if(last_keepalive_sent_time == 0)
+ last_keepalive_sent_time = t;
- add_session_user(remote_machine);
+ if(last_idle_closed_check == 0)
+ last_idle_closed_check = t;
- reload_services(True);
- reopen_logs();
+ /* become root again if waiting */
+ unbecome_user();
- if(lp_status(-1)) {
- claim_connection(NULL,"STATUS.",MAXSTATUS,True);
- }
+ /* check if we need to reload services */
+ check_reload(t);
+
+ /* automatic timeout if all connections are closed */
+ if (conn_num_open()==0 && (t - last_idle_closed_check) >= IDLE_CLOSED_TIMEOUT)
+ {
+ DEBUG( 2, ( "Closing idle connection\n" ) );
+ return False;
}
+ else
+ last_idle_closed_check = t;
- while (True)
+ if (keepalive && (t - last_keepalive_sent_time)>keepalive)
{
- int deadtime = lp_deadtime()*60;
- int counter;
- int last_keepalive=0;
- int service_load_counter = 0;
- BOOL got_smb = False;
+ struct cli_state *cli = server_client();
+ if (!send_keepalive(Client)) {
+ DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
+ return False;
+ }
+ /* also send a keepalive to the password server if its still
+ connected */
+ if (cli && cli->initialised)
+ send_keepalive(cli->fd);
+ last_keepalive_sent_time = t;
+ }
- if (deadtime <= 0)
- deadtime = DEFAULT_SMBD_TIMEOUT;
+ /* check for connection timeouts */
+ allidle = conn_idle_all(t, deadtime);
-#if USE_READ_PREDICTION
- if (lp_readprediction())
- do_read_prediction();
-#endif
+ if (allidle && conn_num_open()>0) {
+ DEBUG(2,("Closing idle connection 2.\n"));
+ return False;
+ }
- errno = 0;
+ if(global_machine_password_needs_changing)
+ {
+ unsigned char trust_passwd_hash[16];
+ time_t lct;
+ pstring remote_machine_list;
+
+ /*
+ * We're in domain level security, and the code that
+ * read the machine password flagged that the machine
+ * password needs changing.
+ */
+
+ /*
+ * First, open the machine password file with an exclusive lock.
+ */
+
+ if(!trust_password_lock( global_myworkgroup, global_myname, True)) {
+ DEBUG(0,("process: unable to open the machine account password file for \
+machine %s in domain %s.\n", global_myname, global_myworkgroup ));
+ return True;
+ }
- for (counter=SMBD_SELECT_LOOP;
- !receive_message_or_smb(InBuffer,BUFFER_SIZE,
- SMBD_SELECT_LOOP*1000,&got_smb);
- counter += SMBD_SELECT_LOOP)
- {
- time_t t;
- BOOL allidle = True;
- extern int keepalive;
+ if(!get_trust_account_password( trust_passwd_hash, &lct)) {
+ DEBUG(0,("process: unable to read the machine account password for \
+machine %s in domain %s.\n", global_myname, global_myworkgroup ));
+ trust_password_unlock();
+ return True;
+ }
- if (counter > 365 * 3600) /* big number of seconds. */
- {
- counter = 0;
- service_load_counter = 0;
- }
+ /*
+ * Make sure someone else hasn't already done this.
+ */
- if (smb_read_error == READ_EOF)
- {
- DEBUG(3,("end of file from client\n"));
- return;
- }
+ if(t < lct + lp_machine_password_timeout()) {
+ trust_password_unlock();
+ global_machine_password_needs_changing = False;
+ return True;
+ }
- if (smb_read_error == READ_ERROR)
- {
- DEBUG(3,("receive_smb error (%s) exiting\n",
- strerror(errno)));
- return;
- }
+ pstrcpy(remote_machine_list, lp_passwordserver());
- t = time(NULL);
+ change_trust_account_password( global_myworkgroup, remote_machine_list);
+ trust_password_unlock();
+ global_machine_password_needs_changing = False;
+ }
- /* become root again if waiting */
- unbecome_user();
+ /*
+ * Check to see if we have any blocking locks
+ * outstanding on the queue.
+ */
+ process_blocking_lock_queue(t);
- /* check for smb.conf reload */
- if (counter >= service_load_counter + SMBD_RELOAD_CHECK)
- {
- service_load_counter = counter;
+ /*
+ * Check to see if we have any change notifies
+ * outstanding on the queue.
+ */
+ process_pending_change_notify_queue(t);
- /* reload services, if files have changed. */
- reload_services(True);
- }
+ /*
+ * Modify the select timeout depending upon
+ * what we have remaining in our queues.
+ */
- /*
- * If reload_after_sighup == True then we got a SIGHUP
- * and are being asked to reload. Fix from <branko.cibej@hermes.si>
- */
+ *select_timeout = setup_select_timeout();
- if (reload_after_sighup)
- {
- DEBUG(0,("Reloading services after SIGHUP\n"));
- reload_services(False);
- reload_after_sighup = False;
- /*
- * Use this as an excuse to print some stats.
- */
- print_stat_cache_statistics();
- }
+ return True;
+}
- /* automatic timeout if all connections are closed */
- if (conn_num_open()==0 && counter >= IDLE_CLOSED_TIMEOUT)
- {
- DEBUG( 2, ( "Closing idle connection\n" ) );
- return;
- }
+/****************************************************************************
+ process commands from the client
+****************************************************************************/
- if (keepalive && (counter-last_keepalive)>keepalive)
- {
- struct cli_state *cli = server_client();
- if (!send_keepalive(Client)) {
- DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
- return;
- }
- /* also send a keepalive to the password server if its still
- connected */
- if (cli && cli->initialised)
- send_keepalive(cli->fd);
- last_keepalive = counter;
- }
+void smbd_process(void)
+{
+ extern int smb_echo_count;
+ time_t last_timeout_processing_time = time(NULL);
+ unsigned int num_smbs = 0;
+
+ InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ if ((InBuffer == NULL) || (OutBuffer == NULL))
+ return;
- /* check for connection timeouts */
- allidle = conn_idle_all(t, deadtime);
+ InBuffer += SMB_ALIGNMENT;
+ OutBuffer += SMB_ALIGNMENT;
- if (allidle && conn_num_open()>0) {
- DEBUG(2,("Closing idle connection 2.\n"));
- return;
- }
+ max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
- if(global_machine_password_needs_changing)
- {
- unsigned char trust_passwd_hash[16];
- time_t lct;
- pstring remote_machine_list;
- int sec_chan = SEC_CHAN_WKSTA;
-
- /*
- * We're in domain level security, and the code that
- * read the machine password flagged that the machine
- * password needs changing.
- */
+ /* re-initialise the timezone */
+ TimeInit();
- /*
- * First, open the machine password file with an exclusive lock.
- */
+ while (True)
+ {
+ int deadtime = lp_deadtime()*60;
+ BOOL got_smb = False;
+ int select_timeout = setup_select_timeout();
- if(!trust_password_lock( global_myworkgroup, global_myname, True)) {
- DEBUG(0,("process: unable to open the machine account password file for \
-machine %s in domain %s.\n", global_myname, global_myworkgroup ));
- continue;
- }
+ if (deadtime <= 0)
+ deadtime = DEFAULT_SMBD_TIMEOUT;
- if(!get_trust_account_password( trust_passwd_hash, &lct)) {
- DEBUG(0,("process: unable to read the machine account password for \
-machine %s in domain %s.\n", global_myname, global_myworkgroup ));
- trust_password_unlock();
- continue;
- }
+#if USE_READ_PREDICTION
+ if (lp_readprediction())
+ do_read_prediction();
+#endif
- /*
- * Make sure someone else hasn't already done this.
- */
+ errno = 0;
- if(t < lct + lp_machine_password_timeout()) {
- trust_password_unlock();
- global_machine_password_needs_changing = False;
- continue;
- }
+ while(!receive_message_or_smb(InBuffer,BUFFER_SIZE,select_timeout,&got_smb))
+ {
+ if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
+ return;
+ num_smbs = 0; /* Reset smb counter. */
+ }
- pstrcpy(remote_machine_list, lp_passwordserver());
- if (lp_server_role() == ROLE_DOMAIN_BDC)
- sec_chan = SEC_CHAN_BDC;
+ if(got_smb) {
+ /*
+ * Ensure we do timeout processing if the SMB we just got was
+ * only an echo request. This allows us to set the select
+ * timeout in 'receive_message_or_smb()' to any value we like
+ * without worrying that the client will send echo requests
+ * faster than the select timeout, thus starving out the
+ * essential processing (change notify, blocking locks) that
+ * the timeout code does. JRA.
+ */
+ int num_echos = smb_echo_count;
+
+ process_smb(InBuffer, OutBuffer);
- change_trust_account_password(global_myworkgroup, remote_machine_list,
- sec_chan);
- trust_password_unlock();
- global_machine_password_needs_changing = False;
+ if(smb_echo_count != num_echos) {
+ if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
+ return;
+ num_smbs = 0; /* Reset smb counter. */
}
- /*
- * Check to see if we have any blocking locks
- * outstanding on the queue.
- */
- process_blocking_lock_queue(t);
+ num_smbs++;
/*
- * Check to see if we have any change notifies
- * outstanding on the queue.
+ * If we are getting smb requests in a constant stream
+ * with no echos, make sure we attempt timeout processing
+ * every select_timeout milliseconds - but only check for this
+ * every 200 smb requests.
*/
- process_pending_change_notify_queue(t);
- }
- if(got_smb)
- process_smb(InBuffer, OutBuffer);
+ if((num_smbs % 200) == 0) {
+ time_t new_check_time = time(NULL);
+ if(last_timeout_processing_time - new_check_time >= (select_timeout/1000)) {
+ if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
+ return;
+ num_smbs = 0; /* Reset smb counter. */
+ last_timeout_processing_time = new_check_time; /* Reset time. */
+ }
+ }
+ }
else
process_local_message(InBuffer, BUFFER_SIZE);
}
diff --git a/source3/smbd/quotas.c b/source3/smbd/quotas.c
index afabb1befd..badc0562bc 100644
--- a/source3/smbd/quotas.c
+++ b/source3/smbd/quotas.c
@@ -47,7 +47,6 @@ try to get the disk space from disk quotas (LINUX version)
BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
- uid_t euser_id;
int r;
struct dqblk D;
SMB_STRUCT_STAT S;
@@ -55,6 +54,9 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
struct mntent *mnt;
SMB_DEV_T devno;
int found;
+ uid_t euser_id;
+
+ euser_id = geteuid();
/* find the block device file */
@@ -81,10 +83,10 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
return(False);
}
- euser_id=geteuid();
- seteuid(0);
+ save_re_uid();
+ set_effective_uid(0);
r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D);
- seteuid(euser_id);
+ restore_re_uid();
/* Use softlimit to determine disk space, except when it has been exceeded */
*bsize = 1024;
@@ -212,11 +214,10 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
*dsize = request.qf_entry.user_q.f_use ;
- if ( *dfree )
- *dfree -= *dsize ;
-
- if ( *dfree < 0 )
+ if ( *dfree < *dsize )
*dfree = 0 ;
+ else
+ *dfree -= *dsize ;
*bsize = 4096 ; /* Cray blocksize */
@@ -244,7 +245,7 @@ Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
- uid_t user_id, euser_id;
+ uid_t euser_id;
int ret;
struct dqblk D;
#if defined(SUNOS5)
@@ -261,6 +262,8 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
SMB_DEV_T devno ;
static SMB_DEV_T devno_cached = 0 ;
int found ;
+
+ euser_id = geteuid();
if ( sys_stat(path,&sbuf) == -1 )
return(False) ;
@@ -312,18 +315,14 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
return(False) ;
}
- euser_id = geteuid();
- user_id = getuid();
-
- setuid(0); /* Solaris seems to want to give info only to super-user */
- seteuid(0);
+ save_re_uid();
+ set_effective_uid(0);
#if defined(SUNOS5)
DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
if((file=sys_open(name, O_RDONLY,0))<0) {
- setuid(user_id); /* Restore the original UID status */
- seteuid(euser_id);
- return(False);
+ restore_re_uid();
+ return(False);
}
command.op = Q_GETQUOTA;
command.uid = euser_id;
@@ -335,8 +334,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
#endif
- setuid(user_id); /* Restore the original uid status. */
- seteuid(euser_id);
+ restore_re_uid();
if (ret < 0) {
DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
@@ -353,14 +351,13 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
if (D.dqb_bsoftlimit==0)
return(False);
*bsize = DEV_BSIZE;
- *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
*dsize = D.dqb_bsoftlimit;
- if(*dfree < 0)
- {
+ if (D.dqb_curblocks > D.dqb_bsoftlimit) {
*dfree = 0;
*dsize = D.dqb_curblocks;
- }
+ } else
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
path,(double)*bsize,(double)*dfree,(double)*dsize));
@@ -378,21 +375,26 @@ try to get the disk space from disk quotas - OSF1 version
BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
- uid_t user_id, euser_id;
int r, save_errno;
struct dqblk D;
SMB_STRUCT_STAT S;
+ uid_t euser_id;
+ /*
+ * This code presumes that OSF1 will only
+ * give out quota info when the real uid
+ * matches the effective uid. JRA.
+ */
euser_id = geteuid();
- user_id = getuid();
+ save_re_uid();
+ if (set_re_uid() != 0) return False;
- setreuid(euser_id, -1);
r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
- if (r)
+ if (r) {
save_errno = errno;
+ }
- if (setreuid(user_id, -1) == -1)
- DEBUG(5,("Unable to reset uid to %d\n", user_id));
+ restore_re_uid();
*bsize = DEV_BSIZE;
@@ -423,7 +425,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
return (True);
}
-#elif defined (SGI6)
+#elif defined (IRIX6)
/****************************************************************************
try to get the disk space from disk quotas (IRIX 6.2 version)
****************************************************************************/
@@ -469,7 +471,8 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
}
euser_id=geteuid();
- seteuid(0);
+ save_re_uid();
+ set_effective_uid(0);
/* Use softlimit to determine disk space, except when it has been exceeded */
@@ -479,7 +482,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
{
r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
- seteuid(euser_id); /* Restore the original uid status. */
+ restore_re_uid();
if (r==-1)
return(False);
@@ -510,7 +513,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
{
r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
- seteuid(euser_id); /* Restore the original uid status. */
+ restore_re_uid();
if (r==-1)
return(False);
@@ -539,8 +542,8 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
}
else
{
- seteuid(euser_id); /* Restore the original uid status. */
- return(False);
+ restore_re_uid();
+ return(False);
}
return (True);
@@ -570,9 +573,9 @@ try to get the disk space from disk quotas - default version
BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
- uid_t euser_id;
int r;
struct dqblk D;
+ uid_t euser_id;
#if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
char dev_disk[256];
SMB_STRUCT_STAT S;
@@ -584,36 +587,32 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
euser_id = geteuid();
#ifdef HPUX
- {
- uid_t user_id;
-
- /* for HPUX, real uid must be same as euid to execute quotactl for euid */
- user_id = getuid();
- setresuid(euser_id,-1,-1);
- r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
- if (setresuid(user_id,-1,-1))
- DEBUG(5,("Unable to reset uid to %d\n", user_id));
- }
+ /* for HPUX, real uid must be same as euid to execute quotactl for euid */
+ save_re_uid();
+ if (set_re_uid() != 0) return False;
+
+ r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
+
+ restore_re_uid();
#else
#if defined(__FreeBSD__) || defined(__OpenBSD__)
{
/* FreeBSD patches from Marty Moll <martym@arbor.edu> */
- uid_t user_id;
gid_t egrp_id;
- /* Need to be root to get quotas in FreeBSD */
- user_id = getuid();
+ save_re_uid();
+ set_effective_uid(0);
+
egrp_id = getegid();
- setuid(0);
- seteuid(0);
r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
/* As FreeBSD has group quotas, if getting the user
quota fails, try getting the group instead. */
- if (r)
- r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
- setuid(user_id);
- seteuid(euser_id);
+ if (r) {
+ r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
+ }
+
+ restore_re_uid();
}
#elif defined(AIX)
/* AIX has both USER and GROUP quotas:
@@ -622,7 +621,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U
#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
#endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
-#endif /* HAVE_SETRES */
+#endif /* HPUX */
/* Use softlimit to determine disk space, except when it has been exceeded */
#if defined(__FreeBSD__) || defined(__OpenBSD__)
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index fed82b5e54..54f646e091 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -38,77 +38,33 @@ extern BOOL case_sensitive;
extern BOOL case_preserve;
extern BOOL short_case_preserve;
extern pstring sesssetup_user;
+extern pstring global_myname;
extern fstring global_myworkgroup;
-extern fstring global_myname;
extern int Client;
extern int global_oplock_break;
uint32 global_client_caps = 0;
-
+unsigned int smb_echo_count = 0;
/****************************************************************************
report a possible attack via the password buffer overflow bug
****************************************************************************/
+
static void overflow_attack(int len)
{
- if( DEBUGLVL( 0 ) )
- {
- dbgtext( "ERROR: Invalid password length %d.\n", len );
- dbgtext( "Your machine may be under attack by someone " );
- dbgtext( "attempting to exploit an old bug.\n" );
- dbgtext( "Attack was from IP = %s.\n", client_addr(Client) );
- }
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "ERROR: Invalid password length %d.\n", len );
+ dbgtext( "Your machine may be under attack by someone " );
+ dbgtext( "attempting to exploit an old bug.\n" );
+ dbgtext( "Attack was from IP = %s.\n", client_addr(Client) );
+ }
exit_server("possible attack");
}
/****************************************************************************
- does _both_ nt->unix and unix->unix username remappings.
-****************************************************************************/
-static void map_nt_and_unix_username(const char *domain, char *user)
-{
- DOM_NAME_MAP gmep;
- fstring nt_username;
-
- /*
- * Pass the user through the NT -> unix user mapping
- * function.
- */
-
- if (lp_server_role() != ROLE_DOMAIN_NONE)
- {
- memset(nt_username, 0, sizeof(nt_username));
- if (domain != NULL)
- {
- slprintf(nt_username, sizeof(nt_username)-1, "%s\\%s",
- domain, user);
- }
- else
- {
- fstrcpy(nt_username, user);
- }
-
- if (lookupsmbpwntnam(nt_username, &gmep))
- {
- fstrcpy(user, gmep.unix_name);
- }
- }
-
- /*
- * Pass the user through the unix -> unix user mapping
- * function.
- */
-
- (void)map_username(user);
-
- /*
- * Do any UNIX username case mangling.
- */
- (void)Get_Pwnam( user, True);
-}
-
-/****************************************************************************
reply to an special message
****************************************************************************/
+
int reply_special(char *inbuf,char *outbuf)
{
int outsize = 4;
@@ -122,13 +78,10 @@ int reply_special(char *inbuf,char *outbuf)
*name1 = *name2 = 0;
- bzero(outbuf,smb_size);
+ memset(outbuf,'\0',smb_size);
smb_setlen(outbuf,0);
- DEBUG(20,("NBT message\n"));
- dump_data(20, inbuf, smb_len(inbuf));
-
switch (msg_type) {
case 0x81: /* session request */
CVAL(outbuf,0) = 0x82;
@@ -202,11 +155,11 @@ int reply_special(char *inbuf,char *outbuf)
/*******************************************************************
work out what error to give to a failed connection
********************************************************************/
+
static int connection_error(char *inbuf,char *outbuf,int ecode)
{
- if (ecode == ERRnoipc) {
+ if (ecode == ERRnoipc)
return(ERROR(ERRDOS,ERRnoipc));
- }
return(ERROR(ERRSRV,ecode));
}
@@ -247,15 +200,14 @@ static void parse_connect(char *p,char *service,char *user,
}
}
-
-
-
/****************************************************************************
- reply to a tcon
+ Reply to a tcon.
****************************************************************************/
+
int reply_tcon(connection_struct *conn,
char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
+ BOOL doencrypt = SMBENCRYPT();
pstring service;
pstring user;
pstring password;
@@ -269,7 +221,25 @@ int reply_tcon(connection_struct *conn,
parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev);
- map_nt_and_unix_username(global_myworkgroup, user);
+ /*
+ * Ensure the user and password names are in UNIX codepage format.
+ */
+
+ dos_to_unix(user,True);
+ if (!doencrypt)
+ dos_to_unix(password,True);
+
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
+
+ /*
+ * Do any UNIX username case mangling.
+ */
+ (void)Get_Pwnam( user, True);
conn = make_connection(service,user,password,pwlen,dev,vuid,&ecode);
@@ -288,16 +258,17 @@ int reply_tcon(connection_struct *conn,
return(outsize);
}
-
/****************************************************************************
- reply to a tcon and X
+ Reply to a tcon and X.
****************************************************************************/
+
int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
pstring service;
pstring user;
pstring password;
pstring devicename;
+ BOOL doencrypt = SMBENCRYPT();
int ecode = -1;
uint16 vuid = SVAL(inbuf,smb_uid);
int passlen = SVAL(inbuf,smb_vwv3);
@@ -314,7 +285,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
if (passlen > MAX_PASS_LEN) {
overflow_attack(passlen);
}
-
+
memcpy(password,smb_buf(inbuf),passlen);
password[passlen]=0;
path = smb_buf(inbuf) + passlen;
@@ -339,8 +310,26 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
StrnCpy(devicename,path + strlen(path) + 1,6);
DEBUG(4,("Got device type %s\n",devicename));
- map_nt_and_unix_username(global_myworkgroup, user);
+ /*
+ * Ensure the user and password names are in UNIX codepage format.
+ */
+
+ dos_to_unix(user,True);
+ if (!doencrypt)
+ dos_to_unix(password,True);
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
+
+ /*
+ * Do any UNIX username case mangling.
+ */
+ (void)Get_Pwnam(user, True);
+
conn = make_connection(service,user,password,passlen,devicename,vuid,&ecode);
if (!conn)
@@ -397,14 +386,39 @@ int reply_unknown(char *inbuf,char *outbuf)
int reply_ioctl(connection_struct *conn,
char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- DEBUG(3,("ignoring ioctl\n"));
-#if 0
- /* we just say it succeeds and hope its all OK.
- some day it would be nice to interpret them individually */
- return set_message(outbuf,1,0,True);
-#else
- return(ERROR(ERRSRV,ERRnosupport));
-#endif
+ uint16 device = SVAL(inbuf,smb_vwv1);
+ uint16 function = SVAL(inbuf,smb_vwv2);
+ uint32 ioctl_code = (device << 16) + function;
+ int replysize, outsize;
+ char *p;
+
+ DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
+
+ switch (ioctl_code)
+ {
+ case IOCTL_QUERY_JOB_INFO:
+ replysize = 32;
+ break;
+ default:
+ return(ERROR(ERRSRV,ERRnosupport));
+ }
+
+ outsize = set_message(outbuf,8,replysize+1,True);
+ SSVAL(outbuf,smb_vwv1,replysize); /* Total data bytes returned */
+ SSVAL(outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
+ SSVAL(outbuf,smb_vwv6,52); /* Offset to data */
+ p = smb_buf(outbuf) + 1; /* Allow for alignment */
+
+ switch (ioctl_code)
+ {
+ case IOCTL_QUERY_JOB_INFO:
+ SSVAL(p,0,1); /* Job number */
+ StrnCpy(p+2, global_myname, 15); /* Our NetBIOS name */
+ StrnCpy(p+18, lp_servicename(SNUM(conn)), 13); /* Service name */
+ break;
+ }
+
+ return outsize;
}
/****************************************************************************
@@ -415,7 +429,6 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out
char *smb_nt_passwd, int smb_nt_passlen)
{
struct smb_passwd *smb_trust_acct = NULL; /* check if trust account exists */
- uchar last_chal[8];
if (lp_security() == SEC_USER)
{
smb_trust_acct = getsmbpwnam(user);
@@ -442,10 +455,8 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out
SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
}
- if (!last_challenge(last_chal) ||
- !smb_password_ok(smb_trust_acct, last_chal, NULL, NULL,
- (unsigned char *)smb_passwd, smb_passlen,
- (unsigned char *)smb_nt_passwd, smb_nt_passlen, NULL))
+
+ if (!smb_password_ok(smb_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd))
{
DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user));
SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
@@ -480,19 +491,154 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out
}
/****************************************************************************
+ Create a UNIX user on demand.
+****************************************************************************/
+
+static int smb_create_user(char *unix_user)
+{
+ pstring add_script;
+ int ret;
+
+ pstrcpy(add_script, lp_adduser_script());
+ pstring_sub(add_script, "%u", unix_user);
+ ret = smbrun(add_script,NULL,False);
+ DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret));
+ return ret;
+}
+
+/****************************************************************************
+ Delete a UNIX user on demand.
+****************************************************************************/
+
+static int smb_delete_user(char *unix_user)
+{
+ pstring del_script;
+ int ret;
+
+ pstrcpy(del_script, lp_deluser_script());
+ pstring_sub(del_script, "%u", unix_user);
+ ret = smbrun(del_script,NULL,False);
+ DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
+ return ret;
+}
+
+/****************************************************************************
+ Check user is in correct domain if required
+****************************************************************************/
+
+static BOOL check_domain_match(char *user, char *domain)
+{
+ /*
+ * If we aren't serving to trusted domains, we must make sure that
+ * the validation request comes from an account in the same domain
+ * as the Samba server
+ */
+
+ if (!lp_allow_trusted_domains() &&
+ !strequal(lp_workgroup(), domain) ) {
+ DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
+ return False;
+ } else {
+ return True;
+ }
+}
+
+/****************************************************************************
Check for a valid username and password in security=server mode.
****************************************************************************/
-static BOOL check_server_security(char *orig_user, char *domain,
+static BOOL check_server_security(char *orig_user, char *domain, char *unix_user,
char *smb_apasswd, int smb_apasslen,
char *smb_ntpasswd, int smb_ntpasslen)
{
+ BOOL ret = False;
+
if(lp_security() != SEC_SERVER)
return False;
- return server_validate(orig_user, domain,
+ if (!check_domain_match(orig_user, domain))
+ return False;
+
+ ret = server_validate(orig_user, domain,
smb_apasswd, smb_apasslen,
smb_ntpasswd, smb_ntpasslen);
+ if(ret) {
+ /*
+ * User validated ok against Domain controller.
+ * If the admin wants us to try and create a UNIX
+ * user on the fly, do so.
+ * Note that we can never delete users when in server
+ * level security as we never know if it was a failure
+ * due to a bad password, or the user really doesn't exist.
+ */
+ if(lp_adduser_script() && !Get_Pwnam(unix_user,True)) {
+ smb_create_user(unix_user);
+ }
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Check for a valid username and password in security=domain mode.
+****************************************************************************/
+
+static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user,
+ char *smb_apasswd, int smb_apasslen,
+ char *smb_ntpasswd, int smb_ntpasslen)
+{
+ BOOL ret = False;
+ BOOL user_exists = True;
+
+ if(lp_security() != SEC_DOMAIN)
+ return False;
+
+ if (!check_domain_match(orig_user, domain))
+ return False;
+
+ ret = domain_client_validate(orig_user, domain,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen,
+ &user_exists);
+
+ if(ret) {
+ /*
+ * User validated ok against Domain controller.
+ * If the admin wants us to try and create a UNIX
+ * user on the fly, do so.
+ */
+ if(user_exists && lp_adduser_script() && !Get_Pwnam(unix_user,True)) {
+ smb_create_user(unix_user);
+ }
+ } else {
+ /*
+ * User failed to validate ok against Domain controller.
+ * If the failure was "user doesn't exist" and admin
+ * wants us to try and delete that UNIX user on the fly,
+ * do so.
+ */
+ if(!user_exists && lp_deluser_script() && Get_Pwnam(unix_user,True)) {
+ smb_delete_user(unix_user);
+ }
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ Return a bad password error configured for the correct client type.
+****************************************************************************/
+
+static int bad_password_error(char *inbuf,char *outbuf)
+{
+ enum remote_arch_types ra_type = get_remote_arch();
+
+ if(ra_type == RA_WINNT && (global_client_caps & (CAP_NT_SMBS | CAP_STATUS32 ))) {
+ SSVAL(outbuf,smb_flg2,FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0,0xc0000000|NT_STATUS_LOGON_FAILURE));
+ }
+
+ return(ERROR(ERRSRV,ERRbadpw));
}
/****************************************************************************
@@ -502,9 +648,8 @@ reply to a session setup command
int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
uint16 sess_vuid;
- uchar user_sess_key[16];
- int gid;
- int uid;
+ gid_t gid;
+ uid_t uid;
int smb_bufsize;
int smb_apasslen = 0;
pstring smb_apasswd;
@@ -517,63 +662,55 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
static BOOL done_sesssetup = False;
BOOL doencrypt = SMBENCRYPT();
char *domain = "";
- uchar last_chal[8];
*smb_apasswd = 0;
*smb_ntpasswd = 0;
smb_bufsize = SVAL(inbuf,smb_vwv2);
- if (Protocol < PROTOCOL_NT1)
- {
+ if (Protocol < PROTOCOL_NT1) {
smb_apasslen = SVAL(inbuf,smb_vwv7);
if (smb_apasslen > MAX_PASS_LEN)
- {
- overflow_attack(smb_apasslen);
- }
+ overflow_attack(smb_apasslen);
memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
smb_apasswd[smb_apasslen] = 0;
pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
-
+ /*
+ * Incoming user is in DOS codepage format. Convert
+ * to UNIX.
+ */
+ dos_to_unix(user,True);
+
if (!doencrypt && (lp_security() != SEC_SERVER)) {
- smb_apasslen = strlen(smb_apasswd);
+ smb_apasslen = strlen(smb_apasswd);
}
-
- if (lp_server_ntlmv2() == True)
- {
- DEBUG(1,("NTLMv2-only accepted with NT LANMAN 1.0 and above.\n\
-user %s attempted down-level SMB connection\n", user));
- return(ERROR(ERRSRV,ERRbadpw));
- }
- }
- else
- {
+ } else {
uint16 passlen1 = SVAL(inbuf,smb_vwv7);
uint16 passlen2 = SVAL(inbuf,smb_vwv8);
enum remote_arch_types ra_type = get_remote_arch();
char *p = smb_buf(inbuf);
- global_client_caps = IVAL(inbuf,smb_vwv11);
+ if(global_client_caps == 0)
+ global_client_caps = IVAL(inbuf,smb_vwv11);
/* client_caps is used as final determination if client is NT or Win95.
This is needed to return the correct error codes in some
circumstances.
*/
- if(ra_type == RA_WINNT || ra_type == RA_WIN95)
- {
+ if(ra_type == RA_WINNT || ra_type == RA_WIN95) {
if(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))
set_remote_arch( RA_WINNT);
else
set_remote_arch( RA_WIN95);
}
- if (passlen1 != 24 && passlen2 <= 24)
+ if (passlen1 != 24 && passlen2 != 24)
doencrypt = False;
if (passlen1 > MAX_PASS_LEN) {
- overflow_attack(passlen1);
+ overflow_attack(passlen1);
}
passlen1 = MIN(passlen1, MAX_PASS_LEN);
@@ -590,18 +727,33 @@ user %s attempted down-level SMB connection\n", user));
if passlen1>0 and passlen2>0 then maybe its a NT box and its
setting passlen2 to some random value which really stuffs
- things up. we need to fix that one.
+ things up. we need to fix that one. */
- LKCLXXXX: the random value can be random 16 bit. old test
- used to have ... && passlen <= 24) which of course fails
- most of the time.
- */
-
- if (passlen1 > 0 && passlen2 > 0 && passlen2 != 1)
+ if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
passlen2 = 0;
}
- if (doencrypt || ((lp_security() == SEC_SERVER) || (lp_security() == SEC_DOMAIN))) {
+ if (lp_restrict_anonymous()) {
+ /* there seems to be no reason behind the differences in MS clients formatting
+ * various info like the domain, NativeOS, and NativeLanMan fields. Win95
+ * in particular seems to have an extra null byte between the username and the
+ * domain, or the password length calculation is wrong, which throws off the
+ * string extraction routines below. This makes the value of domain be the
+ * empty string, which fails the restrict anonymous check further down.
+ * This compensates for that, and allows browsing to work in mixed NT and
+ * win95 environments even when restrict anonymous is true. AAB
+ */
+ dump_data(100, p, 0x70);
+ DEBUG(9, ("passlen1=%d, passlen2=%d\n", passlen1, passlen2));
+ if (ra_type == RA_WIN95 && !passlen1 && !passlen2 && p[0] == 0 && p[1] == 0) {
+ DEBUG(0, ("restrict anonymous parameter used in a win95 environment!\n"));
+ DEBUG(0, ("client is win95 and broken passlen1 offset -- attempting fix\n"));
+ DEBUG(0, ("if win95 cilents are having difficulty browsing, you will be unable to use restrict anonymous\n"));
+ passlen1 = 1;
+ }
+ }
+
+ if(doencrypt || ((lp_security() == SEC_SERVER) || (lp_security() == SEC_DOMAIN))) {
/* Save the lanman2 password and the NT md4 password. */
smb_apasslen = passlen1;
memcpy(smb_apasswd,p,smb_apasslen);
@@ -609,54 +761,77 @@ user %s attempted down-level SMB connection\n", user));
smb_ntpasslen = passlen2;
memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
smb_ntpasswd[smb_ntpasslen] = 0;
+
+ /*
+ * Ensure the plaintext passwords are in UNIX format.
+ */
+ if(!doencrypt) {
+ dos_to_unix(smb_apasswd,True);
+ dos_to_unix(smb_ntpasswd,True);
+ }
+
} else {
/* we use the first password that they gave */
smb_apasslen = passlen1;
StrnCpy(smb_apasswd,p,smb_apasslen);
+ /*
+ * Ensure the plaintext password is in UNIX format.
+ */
+ dos_to_unix(smb_apasswd,True);
/* trim the password */
smb_apasslen = strlen(smb_apasswd);
/* wfwg sometimes uses a space instead of a null */
if (strequal(smb_apasswd," ")) {
- smb_apasslen = 0;
- *smb_apasswd = 0;
+ smb_apasslen = 0;
+ *smb_apasswd = 0;
}
}
- if (passlen2 == 0 && smb_apasslen == 0 && ra_type == RA_WIN95)
- {
- /* work-around for win95 NULL sessions, where NULL password is
- actually put in the data stream before the domain name etc */
- p++;
- }
- else
- {
- p += passlen1 + passlen2;
- }
-
- fstrcpy(user,p); p = skip_string(p,1);
+ p += passlen1 + passlen2;
+ fstrcpy(user,p);
+ p = skip_string(p,1);
+ /*
+ * Incoming user is in DOS codepage format. Convert
+ * to UNIX.
+ */
+ dos_to_unix(user,True);
domain = p;
DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
- domain, skip_string(p,1), skip_string(p,2)));
+ domain,skip_string(p,1),skip_string(p,2)));
}
+
DEBUG(3,("sesssetupX:name=[%s]\n",user));
/* If name ends in $ then I think it's asking about whether a */
/* computer with that name (minus the $) has access. For now */
/* say yes to everything ending in $. */
- if ((user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24))
- {
+
+ if (*user && (user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24)) {
return session_trust_account(conn, inbuf, outbuf, user,
smb_apasswd, smb_apasslen,
smb_ntpasswd, smb_ntpasslen);
}
+ if (done_sesssetup && lp_restrict_anonymous()) {
+ /* tests show that even if browsing is done over already validated connections
+ * without a username and password the domain is still provided, which it
+ * wouldn't be if it was a purely anonymous connection. So, in order to
+ * restrict anonymous, we only deny connections that have no session
+ * information. If a domain has been provided, then it's not a purely
+ * anonymous connection. AAB
+ */
+ if (!*user && !*smb_apasswd && !*domain) {
+ DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n"));
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+
/* If no username is sent use the guest account */
- if (!*user)
- {
+ if (!*user) {
pstrcpy(user,lp_guestaccount(-1));
/* If no user and no password then set guest flag. */
if( *smb_apasswd == 0)
@@ -664,6 +839,7 @@ user %s attempted down-level SMB connection\n", user));
}
strlower(user);
+
/*
* In share level security, only overwrite sesssetup_use if
* it's a non null-session share. Helps keep %U and %G
@@ -672,6 +848,7 @@ user %s attempted down-level SMB connection\n", user));
if((lp_security() != SEC_SHARE) || (*user && !guest))
pstrcpy(sesssetup_user,user);
+
reload_services(True);
/*
@@ -682,7 +859,17 @@ user %s attempted down-level SMB connection\n", user));
pstrcpy( orig_user, user);
- map_nt_and_unix_username(domain, user);
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
+
+ /*
+ * Do any UNIX username case mangling.
+ */
+ (void)Get_Pwnam( user, True);
add_session_user(user);
@@ -699,14 +886,12 @@ user %s attempted down-level SMB connection\n", user));
*/
if (!guest &&
- !check_server_security(orig_user, domain,
+ !check_server_security(orig_user, domain, user,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen) &&
+ !check_domain_security(orig_user, domain, user,
smb_apasswd, smb_apasslen,
smb_ntpasswd, smb_ntpasslen) &&
- !last_challenge(last_chal) &&
- !check_domain_security(orig_user, domain,
- last_chal,
- smb_apasswd, smb_apasslen,
- smb_ntpasswd, smb_ntpasslen, user_sess_key) &&
!check_hosts_equiv(user)
)
{
@@ -721,25 +906,31 @@ user %s attempted down-level SMB connection\n", user));
* 128 length unicode.
*/
- if (smb_ntpasslen)
+ if(smb_ntpasslen)
{
- if(!password_ok(user, smb_ntpasswd,smb_ntpasslen,NULL,user_sess_key))
- DEBUG(0,("NT Password did not match ! Defaulting to Lanman\n"));
+ if(!password_ok(user, smb_ntpasswd,smb_ntpasslen,NULL))
+ DEBUG(2,("NT Password did not match for user '%s' ! Defaulting to Lanman\n", user));
else
valid_nt_password = True;
}
- if (!valid_nt_password && !password_ok(user, smb_apasswd,smb_apasslen,NULL,user_sess_key))
+ if (!valid_nt_password && !password_ok(user, smb_apasswd,smb_apasslen,NULL))
{
if (lp_security() >= SEC_USER)
{
if (lp_map_to_guest() == NEVER_MAP_TO_GUEST)
- return(ERROR(ERRSRV,ERRbadpw));
+ {
+ DEBUG(1,("Rejecting user '%s': authentication failed\n", user));
+ return bad_password_error(inbuf,outbuf);
+ }
if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER)
{
- if (Get_Pwnam(user,True))
- return(ERROR(ERRSRV,ERRbadpw));
+ if (Get_Pwnam(user,True))
+ {
+ DEBUG(1,("Rejecting user '%s': bad password\n", user));
+ return bad_password_error(inbuf,outbuf);
+ }
}
/*
@@ -765,15 +956,12 @@ user %s attempted down-level SMB connection\n", user));
lp_servicenumber(user) < 0)
{
int homes = lp_servicenumber(HOMES_NAME);
- char *home = get_unixhome_dir(user);
+ char *home = get_user_home_dir(user);
if (homes >= 0 && home)
- {
- pstring home_dir;
- fstrcpy(home_dir, home);
- lp_add_home(user,homes,home_dir);
- }
+ lp_add_home(user,homes,home);
}
+
/* it's ok - setup a reply */
if (Protocol < PROTOCOL_NT1) {
set_message(outbuf,3,0,True);
@@ -793,10 +981,10 @@ user %s attempted down-level SMB connection\n", user));
user we should become.
*/
{
- const struct passwd *pw = Get_Pwnam(user,False);
+ struct passwd *pw = Get_Pwnam(user,False);
if (!pw) {
DEBUG(1,("Username %s is invalid on this system\n",user));
- return(ERROR(ERRSRV,ERRbadpw));
+ return bad_password_error(inbuf,outbuf);
}
gid = pw->pw_gid;
uid = pw->pw_uid;
@@ -807,7 +995,7 @@ user %s attempted down-level SMB connection\n", user));
/* register the name and uid as being validated, so further connections
to a uid can get through without a password, on the same VC */
- sess_vuid = register_vuid(uid,gid,user,sesssetup_user,guest,user_sess_key);
+ sess_vuid = register_vuid(uid,gid,user,sesssetup_user,guest);
SSVAL(outbuf,smb_uid,sess_vuid);
SSVAL(inbuf,smb_uid,sess_vuid);
@@ -836,14 +1024,10 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
SMB_STRUCT_STAT st;
pstrcpy(name,smb_buf(inbuf) + 1);
- if (!unix_dfs_convert(name,conn,0,&bad_path,&st))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(name,conn,0,&bad_path,&st);
mode = SVAL(inbuf,smb_vwv0);
-
+
if (check_name(name,conn)) {
if(VALID_STAT(st))
ok = S_ISDIR(st.st_mode);
@@ -900,7 +1084,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
BOOL bad_path = False;
pstrcpy(fname,smb_buf(inbuf) + 1);
-
+
/* dos smetimes asks for a stat of "" - it returns a "hidden directory"
under WfWg - weird! */
if (! (*fname))
@@ -913,14 +1097,10 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
}
else
{
- if (!unix_dfs_convert(fname,conn,0,&bad_path,&sbuf))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
if (check_name(fname,conn))
{
- if (VALID_STAT(sbuf) || conn->vfs_ops.stat(dos_to_unix(fname,False),&sbuf) == 0)
+ if (VALID_STAT(sbuf) || dos_stat(fname,&sbuf) == 0)
{
mode = dos_mode(conn,fname,&sbuf);
size = sbuf.st_size;
@@ -982,11 +1162,7 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
BOOL bad_path = False;
pstrcpy(fname,smb_buf(inbuf) + 1);
- if (!unix_dfs_convert(fname,conn,0,&bad_path,&st))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(fname,conn,0,&bad_path,&st);
mode = SVAL(inbuf,smb_vwv0);
mtime = make_unix_date3(inbuf+smb_vwv1);
@@ -1025,7 +1201,7 @@ int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
int outsize = 0;
SMB_BIG_UINT dfree,dsize,bsize;
- conn->vfs_ops.disk_free(".",&bsize,&dfree,&dsize);
+ sys_disk_free(".",True,&bsize,&dfree,&dsize);
outsize = set_message(outbuf,5,0,True);
@@ -1084,74 +1260,70 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
/* dirtype &= ~aDIR; */
- DEBUG(5,("path=%s status_len=%d\n",path,status_len));
+ DEBUG(5,("reply_search: path=%s status_len=%d\n",path,status_len));
if (status_len == 0)
- {
- pstring dir2;
-
- pstrcpy(directory,smb_buf(inbuf)+1);
- pstrcpy(dir2,smb_buf(inbuf)+1);
- if (!unix_dfs_convert(directory,conn,0,&bad_path,NULL))
{
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
- unix_format(dir2);
-
- if (!check_name(directory,conn))
- can_open = False;
+ pstring dir2;
- p = strrchr(dir2,'/');
- if (p == NULL)
- {
- pstrcpy(mask,dir2);
- *dir2 = 0;
- }
- else
- {
- *p = 0;
- pstrcpy(mask,p+1);
- }
+ pstrcpy(directory,smb_buf(inbuf)+1);
+ pstrcpy(dir2,smb_buf(inbuf)+1);
+ unix_convert(directory,conn,0,&bad_path,NULL);
+ unix_format(dir2);
- p = strrchr(directory,'/');
- if (!p)
- *directory = 0;
- else
- *p = 0;
+ if (!check_name(directory,conn))
+ can_open = False;
- if (strlen(directory) == 0)
- pstrcpy(directory,"./");
- bzero(status,21);
- CVAL(status,0) = dirtype;
+ p = strrchr(dir2,'/');
+ if (p == NULL)
+ {
+ pstrcpy(mask,dir2);
+ *dir2 = 0;
}
- else
+ else
{
- memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
- memcpy(mask,status+1,11);
- mask[11] = 0;
- dirtype = CVAL(status,0) & 0x1F;
- conn->dirptr = dptr_fetch(status+12,&dptr_num);
- if (!conn->dirptr)
- goto SearchEmpty;
- string_set(&conn->dirpath,dptr_path(dptr_num));
- if (!case_sensitive)
- strnorm(mask);
+ *p = 0;
+ pstrcpy(mask,p+1);
}
+ p = strrchr(directory,'/');
+ if (!p)
+ *directory = 0;
+ else
+ *p = 0;
+
+ if (strlen(directory) == 0)
+ pstrcpy(directory,"./");
+ memset((char *)status,'\0',21);
+ CVAL(status,0) = dirtype;
+ }
+ else
+ {
+ memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
+ memcpy(mask,status+1,11);
+ mask[11] = 0;
+ dirtype = CVAL(status,0) & 0x1F;
+ conn->dirptr = dptr_fetch(status+12,&dptr_num);
+ if (!conn->dirptr)
+ goto SearchEmpty;
+ string_set(&conn->dirpath,dptr_path(dptr_num));
+ if (!case_sensitive)
+ strnorm(mask);
+ }
+
/* turn strings of spaces into a . */
{
trim_string(mask,NULL," ");
if ((p = strrchr(mask,' ')))
- {
- fstring ext;
- fstrcpy(ext,p+1);
- *p = 0;
- trim_string(mask,NULL," ");
- pstrcat(mask,".");
- pstrcat(mask,ext);
- }
+ {
+ fstring ext;
+ fstrcpy(ext,p+1);
+ *p = 0;
+ trim_string(mask,NULL," ");
+ pstrcat(mask,".");
+ pstrcat(mask,ext);
+ }
}
/* Convert the formatted mask. (This code lives in trans2.c) */
@@ -1179,104 +1351,104 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
}
if (!strchr(mask,'.') && strlen(mask)>8)
- {
- fstring tmp;
- fstrcpy(tmp,&mask[8]);
- mask[8] = '.';
- mask[9] = 0;
- pstrcat(mask,tmp);
- }
+ {
+ fstring tmp;
+ fstrcpy(tmp,&mask[8]);
+ mask[8] = '.';
+ mask[9] = 0;
+ pstrcat(mask,tmp);
+ }
DEBUG(5,("mask=%s directory=%s\n",mask,directory));
if (can_open)
- {
- p = smb_buf(outbuf) + 3;
-
- ok = True;
+ {
+ p = smb_buf(outbuf) + 3;
- if (status_len == 0)
- {
- dptr_num = dptr_create(conn,directory,expect_close,SVAL(inbuf,smb_pid));
- if (dptr_num < 0)
+ ok = True;
+
+ if (status_len == 0)
+ {
+ dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
+ if (dptr_num < 0)
+ {
+ if(dptr_num == -2)
{
- if(dptr_num == -2)
+ if((errno == ENOENT) && bad_path)
{
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return (UNIXERROR(ERRDOS,ERRnofids));
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
}
- return(ERROR(ERRDOS,ERRnofids));
+ return (UNIXERROR(ERRDOS,ERRnofids));
}
- }
+ return(ERROR(ERRDOS,ERRnofids));
+ }
+ }
- DEBUG(4,("dptr_num is %d\n",dptr_num));
+ DEBUG(4,("dptr_num is %d\n",dptr_num));
- if (ok)
- {
- if ((dirtype&0x1F) == aVOLID)
- {
- memcpy(p,status,21);
- make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
- dptr_fill(p+12,dptr_num);
- if (dptr_zero(p+12) && (status_len==0))
- numentries = 1;
- else
- numentries = 0;
- p += DIR_STRUCT_SIZE;
- }
- else
- {
- DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
- conn->dirpath,lp_dontdescend(SNUM(conn))));
- if (in_list(conn->dirpath,
- lp_dontdescend(SNUM(conn)),True))
- check_descend = True;
-
- for (i=numentries;(i<maxentries) && !finished;i++)
- {
- finished =
- !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
- if (!finished)
- {
- memcpy(p,status,21);
- make_dir_struct(p,mask,fname,size,mode,date);
- dptr_fill(p+12,dptr_num);
- numentries++;
- }
- p += DIR_STRUCT_SIZE;
- }
- }
- }
- }
+ if (ok)
+ {
+ if ((dirtype&0x1F) == aVOLID)
+ {
+ memcpy(p,status,21);
+ make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
+ dptr_fill(p+12,dptr_num);
+ if (dptr_zero(p+12) && (status_len==0))
+ numentries = 1;
+ else
+ numentries = 0;
+ p += DIR_STRUCT_SIZE;
+ }
+ else
+ {
+ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
+ conn->dirpath,lp_dontdescend(SNUM(conn))));
+ if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True))
+ check_descend = True;
+
+ for (i=numentries;(i<maxentries) && !finished;i++)
+ {
+ finished =
+ !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
+ if (!finished)
+ {
+ memcpy(p,status,21);
+ make_dir_struct(p,mask,fname,size,mode,date);
+ dptr_fill(p+12,dptr_num);
+ numentries++;
+ }
+ p += DIR_STRUCT_SIZE;
+ }
+ }
+ } /* if (ok ) */
+ }
- SearchEmpty:
+ SearchEmpty:
if (numentries == 0 || !ok)
- {
- CVAL(outbuf,smb_rcls) = ERRDOS;
- SSVAL(outbuf,smb_err,ERRnofiles);
- }
+ {
+ CVAL(outbuf,smb_rcls) = ERRDOS;
+ SSVAL(outbuf,smb_err,ERRnofiles);
+ dptr_close(&dptr_num);
+ }
/* If we were called as SMBffirst with smb_search_id == NULL
and no entries were found then return error and close dirptr
(X/Open spec) */
if(ok && expect_close && numentries == 0 && status_len == 0)
- {
- CVAL(outbuf,smb_rcls) = ERRDOS;
- SSVAL(outbuf,smb_err,ERRnofiles);
- /* Also close the dptr - we know it's gone */
- dptr_close(dptr_num);
- }
+ {
+ CVAL(outbuf,smb_rcls) = ERRDOS;
+ SSVAL(outbuf,smb_err,ERRnofiles);
+ /* Also close the dptr - we know it's gone */
+ dptr_close(&dptr_num);
+ }
/* If we were called as SMBfunique, then we can close the dirptr now ! */
if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
SSVAL(outbuf,smb_vwv0,numentries);
SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
@@ -1295,8 +1467,8 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
- smb_fn_name(CVAL(inbuf,smb_com)),
- mask, directory, dirtype, numentries, maxentries ) );
+ smb_fn_name(CVAL(inbuf,smb_com)),
+ mask, directory, dirtype, numentries, maxentries ) );
return(outsize);
}
@@ -1311,7 +1483,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
int status_len;
char *path;
char status[21];
- int dptr_num= -1;
+ int dptr_num= -2;
outsize = set_message(outbuf,1,0,True);
path = smb_buf(inbuf) + 1;
@@ -1325,7 +1497,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if(dptr_fetch(status+12,&dptr_num)) {
/* Close the dptr - we know it's gone */
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
}
SSVAL(outbuf,smb_vwv0,0);
@@ -1358,11 +1530,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
share_mode = SVAL(inbuf,smb_vwv0);
pstrcpy(fname,smb_buf(inbuf)+1);
- if (!unix_dfs_convert(fname,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(fname,conn,0,&bad_path,NULL);
fsp = file_new();
if (!fsp)
@@ -1381,9 +1549,8 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
unixmode = unix_mode(conn,aARCH);
- open_file_shared(fsp, conn, fname, share_mode,
- (FILE_FAIL_IF_NOT_EXIST | FILE_EXISTS_OPEN),
- unixmode, oplock_request, &rmode, NULL);
+ open_file_shared(fsp,conn,fname,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+ unixmode, oplock_request,&rmode,NULL);
if (!fsp->open)
{
@@ -1396,7 +1563,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
- if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ if (sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
close_file(fsp,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
@@ -1425,7 +1592,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
}
- if(fsp->granted_oplock)
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
return(outsize);
}
@@ -1459,19 +1626,13 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
files_struct *fsp;
/* If it's an IPC, pass off the pipe handler. */
- if (IS_IPC(conn) && lp_nt_pipe_support() && lp_security() != SEC_SHARE)
- {
+ if (IS_IPC(conn) && lp_nt_pipe_support())
return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
- }
/* XXXX we need to handle passed times, sattr and flags */
pstrcpy(fname,smb_buf(inbuf));
- if (!unix_dfs_convert(fname,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(fname,conn,0,&bad_path,NULL);
fsp = file_new();
if (!fsp)
@@ -1490,8 +1651,8 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
unixmode = unix_mode(conn,smb_attr | aARCH);
- open_file_shared(fsp, conn, fname, smb_mode, smb_ofun, unixmode,
- oplock_request, &rmode, &smb_action);
+ open_file_shared(fsp,conn,fname,smb_mode,smb_ofun,unixmode,
+ oplock_request, &rmode,&smb_action);
if (!fsp->open)
{
@@ -1504,7 +1665,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
- if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ if (sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
close_file(fsp,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
@@ -1526,7 +1687,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
smb_action |= EXTENDED_OPLOCK_GRANTED;
}
- if(ex_oplock_request && fsp->granted_oplock) {
+ if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
smb_action |= EXTENDED_OPLOCK_GRANTED;
}
@@ -1539,7 +1700,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
}
- if(core_oplock_request && fsp->granted_oplock) {
+ if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
}
@@ -1605,11 +1766,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
createmode = SVAL(inbuf,smb_vwv0);
pstrcpy(fname,smb_buf(inbuf)+1);
- if (!unix_dfs_convert(fname,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(fname,conn,0,&bad_path,NULL);
if (createmode & aVOLID)
{
@@ -1636,18 +1793,17 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if(com == SMBmknew)
{
/* We should fail if file exists. */
- ofun = 0x10;
+ ofun = FILE_CREATE_IF_NOT_EXIST;
}
else
{
/* SMBcreate - Create if file doesn't exist, truncate if it does. */
- ofun = 0x12;
+ ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE;
}
/* Open file in dos compatibility share mode. */
- open_file_shared(fsp, conn, fname,
- SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
- ofun, unixmode, oplock_request, NULL, NULL);
+ open_file_shared(fsp,conn,fname,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
+ ofun, unixmode, oplock_request, NULL, NULL);
if (!fsp->open)
{
@@ -1667,7 +1823,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
}
- if(fsp->granted_oplock)
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
DEBUG( 2, ( "new file %s\n", fname ) );
@@ -1695,11 +1851,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
createmode = SVAL(inbuf,smb_vwv0);
pstrcpy(fname,smb_buf(inbuf)+1);
pstrcat(fname,"/TMXXXXXX");
- if (!unix_dfs_convert(fname,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(fname,conn,0,&bad_path,NULL);
unixmode = unix_mode(conn,createmode);
@@ -1718,14 +1870,12 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
- pstrcpy(fname2,(char *)mktemp(fname));
+ pstrcpy(fname2,(char *)smbd_mktemp(fname));
/* Open file in dos compatibility share mode. */
/* We should fail if file exists. */
- open_file_shared(fsp,conn,fname2,
- SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
- (FILE_CREATE_IF_NOT_EXIST | FILE_EXISTS_FAIL),
- unixmode, oplock_request, NULL, NULL);
+ open_file_shared(fsp,conn,fname2,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
+ (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL), unixmode, oplock_request, NULL, NULL);
if (!fsp->open)
{
@@ -1747,7 +1897,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
}
- if(fsp->granted_oplock)
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
DEBUG( 2, ( "created temp file %s\n", fname2 ) );
@@ -1768,7 +1918,7 @@ static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
if (!CAN_WRITE(conn)) return(False);
- if (conn->vfs_ops.lstat(fname,&sbuf) != 0) return(False);
+ if (dos_lstat(fname,&sbuf) != 0) return(False);
fmode = dos_mode(conn,fname,&sbuf);
if (fmode & aDIR) return(False);
if (!lp_delete_readonly(SNUM(conn))) {
@@ -1781,8 +1931,9 @@ static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
}
/****************************************************************************
- reply to a unlink
+ Reply to a unlink
****************************************************************************/
+
int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int outsize = 0;
@@ -1796,6 +1947,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
BOOL has_wild;
BOOL exists=False;
BOOL bad_path = False;
+ BOOL rc = True;
*directory = *mask = 0;
@@ -1805,11 +1957,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
DEBUG(3,("reply_unlink : %s\n",name));
- if (!unix_dfs_convert(name,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ rc = unix_convert(name,conn,0,&bad_path,NULL);
p = strrchr(name,'/');
if (!p) {
@@ -1821,7 +1969,16 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
pstrcpy(mask,p+1);
}
- if (is_mangled(mask))
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+ if (!rc && is_mangled(mask))
check_mangled_cache( mask );
has_wild = strchr(mask,'*') || strchr(mask,'?');
@@ -1829,10 +1986,10 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if (!has_wild) {
pstrcat(directory,"/");
pstrcat(directory,mask);
- if (can_delete(directory,conn,dirtype) && !conn->vfs_ops.unlink(directory))
+ if (can_delete(directory,conn,dirtype) && !dos_unlink(directory))
count++;
if (!count)
- exists = vfs_file_exist(conn,dos_to_unix(directory,False),NULL);
+ exists = dos_file_exist(directory,NULL);
} else {
void *dirptr = NULL;
char *dname;
@@ -1862,7 +2019,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
error = ERRnoaccess;
slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
if (!can_delete(fname,conn,dirtype)) continue;
- if (!conn->vfs_ops.unlink(fname)) count++;
+ if (!dos_unlink(fname)) count++;
DEBUG(3,("reply_unlink : doing unlink on %s\n",fname));
}
CloseDir(dirptr);
@@ -1892,6 +2049,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
/****************************************************************************
reply to a readbraw (core+ protocol)
****************************************************************************/
+
int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
{
size_t maxcount,mincount;
@@ -1917,13 +2075,45 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
fsp = file_fsp(inbuf,smb_vwv0);
+ if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
+ /*
+ * fsp could be NULL here so use the value from the packet. JRA.
+ */
+ DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
+ _smb_setlen(header,0);
+ transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
+ return(-1);
+ }
+
+ CHECK_FSP(fsp,conn);
+
+ flush_write_cache(fsp, READRAW_FLUSH);
+
startpos = IVAL(inbuf,smb_vwv1);
-#ifdef LARGE_SMB_OFF_T
if(CVAL(inbuf,smb_wct) == 10) {
/*
* This is a large offset (64 bit) read.
*/
+#ifdef LARGE_SMB_OFF_T
+
startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
+
+#else /* !LARGE_SMB_OFF_T */
+
+ /*
+ * Ensure we haven't been sent a >32 bit offset.
+ */
+
+ if(IVAL(inbuf,smb_vwv8) != 0) {
+ DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
+64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
+ _smb_setlen(header,0);
+ transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
+ return(-1);
+ }
+
+#endif /* LARGE_SMB_OFF_T */
+
if(startpos < 0) {
DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n",
(double)startpos ));
@@ -1932,7 +2122,6 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
return(-1);
}
}
-#endif /* LARGE_SMB_OFF_T */
maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
@@ -1940,13 +2129,6 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
maxcount = MIN(65535,maxcount);
maxcount = MAX(mincount,maxcount);
- if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
- DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",fsp->fnum));
- _smb_setlen(header,0);
- transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
- return(-1);
- }
-
if (!is_locked(fsp,conn,maxcount,startpos, F_RDLCK))
{
SMB_OFF_T size = fsp->size;
@@ -1955,7 +2137,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
if (size < sizeneeded)
{
SMB_STRUCT_STAT st;
- if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&st) == 0)
+ if (sys_fstat(fsp->fd_ptr->fd,&st) == 0)
size = st.st_size;
if (!fsp->can_write)
fsp->size = size;
@@ -1969,7 +2151,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n",
fsp->fnum, (double)startpos,
- maxcount, mincount, nread ) );
+ (int)maxcount, (int)mincount, (int)nread ) );
#if UNSAFE_READRAW
{
@@ -1979,11 +2161,11 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
#if USE_READ_PREDICTION
if (!fsp->can_write)
- predict = read_predict(fsp, fsp->fd_ptr->fd,startpos,header+4,NULL,nread);
+ predict = read_predict(fsp->fd_ptr->fd,startpos,header+4,NULL,nread);
#endif /* USE_READ_PREDICTION */
if ((nread-predict) > 0) {
- if(conn->vfs_ops.seek(fsp,startpos + predict) == -1) {
+ if(seek_file(fsp,startpos + predict) == -1) {
DEBUG(0,("reply_readbraw: ERROR: seek_file failed.\n"));
ret = 0;
seek_fail = True;
@@ -1991,7 +2173,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
}
if(!seek_fail)
- ret = (ssize_t)vfs_transfer_file(-1, fsp->fd_ptr->fd, Client, NULL,
+ ret = (ssize_t)transfer_file(fsp->fd_ptr->fd,Client,
(SMB_OFF_T)(nread-predict),header,4+predict,
startpos+predict);
}
@@ -2037,8 +2219,15 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
outsize = set_message(outbuf,5,3,True);
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
data = smb_buf(outbuf) + 3;
-
- if(!do_lock( fsp, conn, numtoread, startpos, F_RDLCK, &eclass, &ecode)) {
+
+ /*
+ * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
+ * protocol request that predates the read/write lock concept.
+ * Thus instead of asking for a read lock here we need to ask
+ * for a write lock. JRA.
+ */
+
+ if(!do_lock( fsp, conn, numtoread, startpos, F_WRLCK, &eclass, &ecode)) {
if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
/*
* A blocking lock was requested. Package up
@@ -2062,7 +2251,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
SSVAL(smb_buf(outbuf),1,nread);
DEBUG( 3, ( "lockread fnum=%d num=%d nread=%d\n",
- fsp->fnum, numtoread, nread ) );
+ fsp->fnum, (int)numtoread, (int)nread ) );
return(outsize);
}
@@ -2071,7 +2260,8 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
/****************************************************************************
reply to a read
****************************************************************************/
-int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
size_t numtoread;
ssize_t nread = 0;
@@ -2094,9 +2284,8 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if (is_locked(fsp,conn,numtoread,startpos, F_RDLCK))
return(ERROR(ERRDOS,ERRlock));
- if (numtoread > 0) {
+ if (numtoread > 0)
nread = read_file(fsp,data,startpos,numtoread);
- }
if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -2108,7 +2297,7 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
SSVAL(smb_buf(outbuf),1,nread);
DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
- fsp->fnum, numtoread, nread ) );
+ fsp->fnum, (int)numtoread, (int)nread ) );
return(outsize);
}
@@ -2137,28 +2326,42 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
set_message(outbuf,12,0,True);
data = smb_buf(outbuf);
-#ifdef LARGE_SMB_OFF_T
if(CVAL(inbuf,smb_wct) == 12) {
+#ifdef LARGE_SMB_OFF_T
/*
* This is a large offset (64 bit) read.
*/
startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
- }
+
+#else /* !LARGE_SMB_OFF_T */
+
+ /*
+ * Ensure we haven't been sent a >32 bit offset.
+ */
+
+ if(IVAL(inbuf,smb_vwv10) != 0) {
+ DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
+64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
+ return(ERROR(ERRDOS,ERRbadaccess));
+ }
+
#endif /* LARGE_SMB_OFF_T */
+ }
+
if (is_locked(fsp,conn,smb_maxcnt,startpos, F_RDLCK))
return(ERROR(ERRDOS,ERRlock));
nread = read_file(fsp,data,startpos,smb_maxcnt);
-
+
if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
SSVAL(outbuf,smb_vwv5,nread);
SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
SSVAL(smb_buf(outbuf),-2,nread);
-
+
DEBUG( 3, ( "readX fnum=%d min=%d max=%d nread=%d\n",
- fsp->fnum, smb_mincnt, smb_maxcnt, nread ) );
+ fsp->fnum, (int)smb_mincnt, (int)smb_maxcnt, (int)nread ) );
return chain_reply(inbuf,outbuf,length,bufsize);
}
@@ -2166,7 +2369,8 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
/****************************************************************************
reply to a writebraw (core+ or LANMAN1.0 protocol)
****************************************************************************/
-int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
ssize_t nwritten=0;
ssize_t total_written=0;
@@ -2203,16 +2407,11 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
if (is_locked(fsp,conn,tcount,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- if (seek_file(fsp,startpos) == -1) {
- DEBUG(0,("couldn't seek to %.0f in writebraw\n",(double)startpos));
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
if (numtowrite>0)
- nwritten = write_file(fsp,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
- fsp->fnum, (double)startpos, numtowrite, nwritten, write_through));
+ fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
if (nwritten < numtowrite)
return(UNIXERROR(ERRHRD,ERRdiskfull));
@@ -2237,12 +2436,11 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
if (tcount > nwritten+numtowrite) {
DEBUG(3,("Client overestimated the write %d %d %d\n",
- tcount,nwritten,numtowrite));
+ (int)tcount,(int)nwritten,(int)numtowrite));
}
- nwritten = vfs_transfer_file(Client, NULL, -1, fsp,
- (SMB_OFF_T)numtowrite,NULL,0,
- startpos+nwritten);
+ nwritten = transfer_file(Client,fsp->fd_ptr->fd,(SMB_OFF_T)numtowrite,NULL,0,
+ startpos+nwritten);
total_written += nwritten;
/* Set up outbuf to return the correct return */
@@ -2255,12 +2453,11 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
SSVAL(outbuf,smb_err,ERRdiskfull);
}
- if ((lp_syncalways(SNUM(conn)) || write_through) &&
- lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
+ if (lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
- fsp->fnum, (double)startpos, numtowrite, total_written));
+ fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
/* we won't return a status if write through is not selected - this
follows what WfWg does */
@@ -2273,7 +2470,8 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
/****************************************************************************
reply to a writeunlock (core+)
****************************************************************************/
-int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
ssize_t nwritten = -1;
size_t numtowrite;
@@ -2295,19 +2493,16 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int dum
if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
/* The special X/Open SMB protocol handling of
zero length writes is *NOT* done for
this call */
if(numtowrite == 0)
nwritten = 0;
else
- nwritten = write_file(fsp,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if (lp_syncalways(SNUM(conn)) && lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
+ if (lp_syncalways(SNUM(conn)))
+ sync_file(conn,fsp);
if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -2320,7 +2515,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int dum
SSVAL(outbuf,smb_vwv0,nwritten);
DEBUG( 3, ( "writeunlock fnum=%d num=%d wrote=%d\n",
- fsp->fnum, numtowrite, nwritten ) );
+ fsp->fnum, (int)numtowrite, (int)nwritten ) );
return(outsize);
}
@@ -2328,7 +2523,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int dum
/****************************************************************************
reply to a write
****************************************************************************/
-int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int dum_size,int dum_buffsize)
+int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
{
size_t numtowrite;
ssize_t nwritten = -1;
@@ -2337,9 +2532,9 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int dum_size,i
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
int outsize = 0;
- /* If it's an IPC, pass off the pipe handler. */
- if (IS_IPC(conn))
- return reply_pipe_write(inbuf,outbuf,dum_size,dum_buffsize);
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn))
+ return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
CHECK_FSP(fsp,conn);
CHECK_WRITE(fsp);
@@ -2352,19 +2547,17 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int dum_size,i
if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
/* X/Open SMB protocol says that if smb_vwv1 is
zero then the file size should be extended or
truncated to the size given in smb_vwv[2-3] */
- if(numtowrite == 0)
- nwritten = set_filelen(fsp->fd_ptr->fd, (SMB_OFF_T)startpos);
- else
- nwritten = write_file(fsp,data,numtowrite);
+ if(numtowrite == 0) {
+ if((nwritten = set_filelen(fsp->fd_ptr->fd, (SMB_OFF_T)startpos)) >= 0)
+ set_filelen_write_cache(fsp, startpos);
+ } else
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if (lp_syncalways(SNUM(conn)) && lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
+ if (lp_syncalways(SNUM(conn)))
+ sync_file(conn,fsp);
if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -2379,7 +2572,7 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int dum_size,i
}
DEBUG(3,("write fnum=%d num=%d wrote=%d\n",
- fsp->fnum, numtowrite, nwritten));
+ fsp->fnum, (int)numtowrite, (int)nwritten));
return(outsize);
}
@@ -2408,21 +2601,31 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
data = smb_base(inbuf) + smb_doff;
-#ifdef LARGE_SMB_OFF_T
if(CVAL(inbuf,smb_wct) == 14) {
+#ifdef LARGE_SMB_OFF_T
/*
* This is a large offset (64 bit) write.
*/
startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
- }
+
+#else /* !LARGE_SMB_OFF_T */
+
+ /*
+ * Ensure we haven't been sent a >32 bit offset.
+ */
+
+ if(IVAL(inbuf,smb_vwv12) != 0) {
+ DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
+64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
+ return(ERROR(ERRDOS,ERRbadaccess));
+ }
+
#endif /* LARGE_SMB_OFF_T */
+ }
if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
/* X/Open SMB protocol says that, unlike SMBwrite
if the length is zero then NO truncation is
done, just a write of zero. To truncate a file,
@@ -2430,7 +2633,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
if(numtowrite == 0)
nwritten = 0;
else
- nwritten = write_file(fsp,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -2445,11 +2648,10 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
}
DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
- fsp->fnum, numtowrite, nwritten));
+ fsp->fnum, (int)numtowrite, (int)nwritten));
- if ((lp_syncalways(SNUM(conn)) || write_through) &&
- lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
+ if (lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
return chain_reply(inbuf,outbuf,length,bufsize);
}
@@ -2458,7 +2660,8 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
/****************************************************************************
reply to a lseek
****************************************************************************/
-int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
SMB_OFF_T startpos;
SMB_OFF_T res= -1;
@@ -2469,11 +2672,12 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
CHECK_FSP(fsp,conn);
CHECK_ERROR(fsp);
+ flush_write_cache(fsp, SEEK_FLUSH);
+
mode = SVAL(inbuf,smb_vwv1) & 3;
- startpos = IVAL(inbuf,smb_vwv2);
+ startpos = IVALS(inbuf,smb_vwv2);
- switch (mode & 3)
- {
+ switch (mode) {
case 0: umode = SEEK_SET; break;
case 1: umode = SEEK_CUR; break;
case 2: umode = SEEK_END; break;
@@ -2481,16 +2685,48 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
umode = SEEK_SET; break;
}
- if((res = conn->vfs_ops.lseek(fsp->fd_ptr->fd,startpos,umode)) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ if((res = sys_lseek(fsp->fd_ptr->fd,startpos,umode)) == -1) {
+ /*
+ * Check for the special case where a seek before the start
+ * of the file sets the offset to zero. Added in the CIFS spec,
+ * section 4.2.7.
+ */
+
+ if(errno == EINVAL) {
+ SMB_OFF_T current_pos = startpos;
+
+ if(umode == SEEK_CUR) {
+
+ if((current_pos = sys_lseek(fsp->fd_ptr->fd,0,SEEK_CUR)) == -1)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ current_pos += startpos;
+
+ } else if (umode == SEEK_END) {
+
+ SMB_STRUCT_STAT sbuf;
+
+ if(sys_fstat( fsp->fd_ptr->fd, &sbuf) == -1)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ current_pos += sbuf.st_size;
+ }
+
+ if(current_pos < 0)
+ res = sys_lseek(fsp->fd_ptr->fd,0,SEEK_SET);
+ }
+
+ if(res == -1)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
fsp->pos = res;
outsize = set_message(outbuf,2,0,True);
- SIVALS(outbuf,smb_vwv0,res);
+ SIVAL(outbuf,smb_vwv0,res);
- DEBUG(3,("lseek fnum=%d ofs=%.0f mode=%d\n",
- fsp->fnum, (double)startpos, mode));
+ DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
+ fsp->fnum, (double)startpos, (double)res, mode));
return(outsize);
}
@@ -2498,7 +2734,8 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
/****************************************************************************
reply to a flush
****************************************************************************/
-int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
int outsize = set_message(outbuf,0,0,True);
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
@@ -2511,7 +2748,7 @@ int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if (!fsp) {
file_sync_all(conn);
} else {
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
+ sync_file(conn,fsp);
}
DEBUG(3,("flush\n"));
@@ -2535,8 +2772,8 @@ int reply_exit(connection_struct *conn,
/****************************************************************************
Reply to a close - has to deal with closing a directory opened by NT SMB's.
****************************************************************************/
-int reply_close(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
+ int dum_buffsize)
{
int outsize = 0;
time_t mtime;
@@ -2546,9 +2783,8 @@ int reply_close(connection_struct *conn,
outsize = set_message(outbuf,0,0,True);
/* If it's an IPC, pass off to the pipe handler. */
- if (IS_IPC(conn)) {
+ if (IS_IPC(conn))
return reply_pipe_close(conn, inbuf,outbuf);
- }
fsp = file_fsp(inbuf,smb_vwv0);
@@ -2556,25 +2792,26 @@ int reply_close(connection_struct *conn,
* We can only use CHECK_FSP if we know it's not a directory.
*/
- if(!fsp || !fsp->open || (fsp->conn != conn))
- return(ERROR(ERRDOS,ERRbadfid));
+ if(!fsp || !fsp->open || (fsp->conn != conn))
+ return(ERROR(ERRDOS,ERRbadfid));
if(HAS_CACHED_ERROR(fsp)) {
eclass = fsp->wbmpx_ptr->wr_errclass;
err = fsp->wbmpx_ptr->wr_error;
}
- if(fsp->is_directory) {
+ if(fsp->is_directory || fsp->stat_open) {
/*
- * Special case - close NT SMB directory
+ * Special case - close NT SMB directory or stat file
* handle.
*/
- DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
- close_directory(fsp);
+ DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum));
+ close_file(fsp,True);
} else {
/*
* Close ordinary file.
*/
+ int close_err;
/*
* If there was a modify time outstanding,
@@ -2592,10 +2829,19 @@ int reply_close(connection_struct *conn,
set_filetime(conn, fsp->fsp_name,mtime);
DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
- fsp->fd_ptr->fd, fsp->fnum,
+ fsp->fd_ptr ? fsp->fd_ptr->fd : -1, fsp->fnum,
conn->num_files_open));
-
- close_file(fsp,True);
+
+ /*
+ * close_file() returns the unix errno if an error
+ * was detected on close - normally this is due to
+ * a disk full error. If not then it was probably an I/O error.
+ */
+
+ if((close_err = close_file(fsp,True)) != 0) {
+ errno = close_err;
+ return (UNIXERROR(ERRHRD,ERRgeneral));
+ }
}
/* We have a cached error */
@@ -2609,12 +2855,14 @@ int reply_close(connection_struct *conn,
/****************************************************************************
reply to a writeclose (Core+ protocol)
****************************************************************************/
+
int reply_writeclose(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+ char *inbuf,char *outbuf, int size, int dum_buffsize)
{
size_t numtowrite;
ssize_t nwritten = -1;
int outsize = 0;
+ int close_err = 0;
SMB_OFF_T startpos;
char *data;
time_t mtime;
@@ -2631,23 +2879,25 @@ int reply_writeclose(connection_struct *conn,
if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
-
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- nwritten = write_file(fsp,data,numtowrite);
+
+ nwritten = write_file(fsp,data,startpos,numtowrite);
set_filetime(conn, fsp->fsp_name,mtime);
- close_file(fsp,True);
+ close_err = close_file(fsp,True);
DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
- fsp->fnum, numtowrite, nwritten,
+ fsp->fnum, (int)numtowrite, (int)nwritten,
conn->num_files_open));
if (nwritten <= 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+
+ if(close_err != 0) {
+ errno = close_err;
+ return(UNIXERROR(ERRHRD,ERRgeneral));
+ }
+
outsize = set_message(outbuf,1,0,True);
SSVAL(outbuf,smb_vwv0,nwritten);
@@ -2696,7 +2946,8 @@ int reply_lock(connection_struct *conn,
/****************************************************************************
reply to a unlock
****************************************************************************/
-int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
int outsize = set_message(outbuf,0,0,True);
SMB_OFF_T count,offset;
@@ -2775,6 +3026,8 @@ int reply_echo(connection_struct *conn,
DEBUG(3,("echo %d times\n", smb_reverb));
+ smb_echo_count++;
+
return -1;
}
@@ -2815,7 +3068,7 @@ int reply_printopen(connection_struct *conn,
if (!fsp)
return(ERROR(ERRSRV,ERRnofids));
- pstrcpy(fname2,(char *)mktemp(fname));
+ pstrcpy(fname2,(char *)smbd_mktemp(fname));
if (!check_name(fname2,conn)) {
file_free(fsp);
@@ -2852,6 +3105,7 @@ int reply_printclose(connection_struct *conn,
{
int outsize = set_message(outbuf,0,0,True);
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int close_err = 0;
CHECK_FSP(fsp,conn);
CHECK_ERROR(fsp);
@@ -2862,7 +3116,12 @@ int reply_printclose(connection_struct *conn,
DEBUG(3,("printclose fd=%d fnum=%d\n",
fsp->fd_ptr->fd,fsp->fnum));
- close_file(fsp,True);
+ close_err = close_file(fsp,True);
+
+ if(close_err != 0) {
+ errno = close_err;
+ return(UNIXERROR(ERRHRD,ERRgeneral));
+ }
return(outsize);
}
@@ -2955,7 +3214,7 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
numtowrite = SVAL(smb_buf(inbuf),1);
data = smb_buf(inbuf) + 3;
- if (write_file(fsp,data,numtowrite) != numtowrite)
+ if (write_file(fsp,data,-1,numtowrite) != numtowrite)
return(UNIXERROR(ERRDOS,ERRnoaccess));
DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
@@ -2974,15 +3233,10 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
BOOL bad_path = False;
pstrcpy(directory,smb_buf(inbuf) + 1);
- if (!unix_dfs_convert(directory,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(directory,conn,0,&bad_path,NULL);
if (check_name(directory, conn))
- ret = conn->vfs_ops.mkdir(dos_to_unix(directory,False),
- unix_mode(conn,aDIR));
+ ret = dos_mkdir(directory,unix_mode(conn,aDIR));
if (ret < 0)
{
@@ -3005,11 +3259,12 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
Static function used by reply_rmdir to delete an entire directory
tree recursively.
****************************************************************************/
-static BOOL recursive_rmdir(connection_struct *conn, char *directory)
+
+static BOOL recursive_rmdir(char *directory)
{
char *dname = NULL;
BOOL ret = False;
- void *dirptr = OpenDir(conn, directory, False);
+ void *dirptr = OpenDir(NULL, directory, False);
if(dirptr == NULL)
return True;
@@ -3033,7 +3288,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
pstrcat(fullname, "/");
pstrcat(fullname, dname);
- if(conn->vfs_ops.lstat(fullname, &st) != 0)
+ if(dos_lstat(fullname, &st) != 0)
{
ret = True;
break;
@@ -3041,18 +3296,18 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
if(st.st_mode & S_IFDIR)
{
- if(recursive_rmdir(conn, fullname)!=0)
+ if(recursive_rmdir(fullname)!=0)
{
ret = True;
break;
}
- if(conn->vfs_ops.rmdir(dos_to_unix(fullname,False)) != 0)
+ if(dos_rmdir(fullname) != 0)
{
ret = True;
break;
}
}
- else if(conn->vfs_ops.unlink(dos_to_unix(fullname,False)) != 0)
+ else if(dos_unlink(fullname) != 0)
{
ret = True;
break;
@@ -3063,8 +3318,97 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
}
/****************************************************************************
- reply to a rmdir
+ The internals of the rmdir code - called elsewhere.
+****************************************************************************/
+
+BOOL rmdir_internals(connection_struct *conn, char *directory)
+{
+ BOOL ok;
+
+ ok = (dos_rmdir(directory) == 0);
+ if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn)))
+ {
+ /*
+ * Check to see if the only thing in this directory are
+ * vetoed files/directories. If so then delete them and
+ * retry. If we fail to delete any of them (and we *don't*
+ * do a recursive delete) then fail the rmdir.
+ */
+ BOOL all_veto_files = True;
+ char *dname;
+ void *dirptr = OpenDir(conn, directory, False);
+
+ if(dirptr != NULL)
+ {
+ int dirpos = TellDir(dirptr);
+ while ((dname = ReadDirName(dirptr)))
+ {
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+ continue;
+ if(!IS_VETO_PATH(conn, dname))
+ {
+ all_veto_files = False;
+ break;
+ }
+ }
+ if(all_veto_files)
+ {
+ SeekDir(dirptr,dirpos);
+ while ((dname = ReadDirName(dirptr)))
+ {
+ pstring fullname;
+ SMB_STRUCT_STAT st;
+
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+ continue;
+
+ /* Construct the full name. */
+ if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
+ {
+ errno = ENOMEM;
+ break;
+ }
+ pstrcpy(fullname, directory);
+ pstrcat(fullname, "/");
+ pstrcat(fullname, dname);
+
+ if(dos_lstat(fullname, &st) != 0)
+ break;
+ if(st.st_mode & S_IFDIR)
+ {
+ if(lp_recursive_veto_delete(SNUM(conn)))
+ {
+ if(recursive_rmdir(fullname) != 0)
+ break;
+ }
+ if(dos_rmdir(fullname) != 0)
+ break;
+ }
+ else if(dos_unlink(fullname) != 0)
+ break;
+ }
+ CloseDir(dirptr);
+ /* Retry the rmdir */
+ ok = (dos_rmdir(directory) == 0);
+ }
+ else
+ CloseDir(dirptr);
+ }
+ else
+ errno = ENOTEMPTY;
+ }
+
+ if (!ok)
+ DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n",
+ directory,strerror(errno)));
+
+ return ok;
+}
+
+/****************************************************************************
+ Reply to a rmdir.
****************************************************************************/
+
int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring directory;
@@ -3073,92 +3417,13 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
BOOL bad_path = False;
pstrcpy(directory,smb_buf(inbuf) + 1);
- if (!unix_dfs_convert(directory,conn, NULL,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(directory,conn, NULL,&bad_path,NULL);
if (check_name(directory,conn))
- {
-
- dptr_closepath(directory,SVAL(inbuf,smb_pid));
- ok = (conn->vfs_ops.rmdir(dos_to_unix(directory,False)) == 0);
- if(!ok && (errno == ENOTEMPTY) && lp_veto_files(SNUM(conn)))
- {
- /* Check to see if the only thing in this directory are
- vetoed files/directories. If so then delete them and
- retry. If we fail to delete any of them (and we *don't*
- do a recursive delete) then fail the rmdir. */
- BOOL all_veto_files = True;
- char *dname;
- void *dirptr = OpenDir(conn, directory, False);
-
- if(dirptr != NULL)
- {
- int dirpos = TellDir(dirptr);
- while ((dname = ReadDirName(dirptr)))
- {
- if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
- continue;
- if(!IS_VETO_PATH(conn, dname))
- {
- all_veto_files = False;
- break;
- }
- }
- if(all_veto_files)
- {
- SeekDir(dirptr,dirpos);
- while ((dname = ReadDirName(dirptr)))
- {
- pstring fullname;
- SMB_STRUCT_STAT st;
-
- if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
- continue;
-
- /* Construct the full name. */
- if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
- {
- errno = ENOMEM;
- break;
- }
- pstrcpy(fullname, directory);
- pstrcat(fullname, "/");
- pstrcat(fullname, dname);
-
- if(conn->vfs_ops.lstat(fullname, &st) != 0)
- break;
- if(st.st_mode & S_IFDIR)
- {
- if(lp_recursive_veto_delete(SNUM(conn)))
- {
- DEBUG(0, ("ERROR: recursive_rmdir()\n"));
- if(recursive_rmdir(conn, fullname) != 0)
- break;
- }
- if(conn->vfs_ops.rmdir(dos_to_unix(fullname,False)) != 0)
- break;
- }
- else if(conn->vfs_ops.unlink(dos_to_unix(fullname,False)) != 0)
- break;
- }
- CloseDir(dirptr);
- /* Retry the rmdir */
- ok = (conn->vfs_ops.rmdir(dos_to_unix(directory,False)) == 0);
- }
- else
- CloseDir(dirptr);
- }
- else
- errno = ENOTEMPTY;
- }
-
- if (!ok)
- DEBUG(3,("couldn't remove directory %s : %s\n",
- directory,strerror(errno)));
- }
+ {
+ dptr_closepath(directory,SVAL(inbuf,smb_pid));
+ ok = rmdir_internals(conn, directory);
+ }
if (!ok)
{
@@ -3251,7 +3516,7 @@ static BOOL can_rename(char *fname,connection_struct *conn)
if (!CAN_WRITE(conn)) return(False);
- if (conn->vfs_ops.lstat(fname,&sbuf) != 0) return(False);
+ if (dos_lstat(fname,&sbuf) != 0) return(False);
if (!check_file_sharing(conn,fname,True)) return(False);
return(True);
@@ -3275,23 +3540,16 @@ int rename_internals(connection_struct *conn,
int count=0;
int error = ERRnoaccess;
BOOL exists=False;
+ BOOL rc = True;
*directory = *mask = 0;
- if (!unix_dfs_convert(name,conn,0,&bad_path1,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
- if (!unix_dfs_convert(newname,conn,newname_last_component,&bad_path2,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ rc = unix_convert(name,conn,0,&bad_path1,NULL);
+ unix_convert(newname,conn,newname_last_component,&bad_path2,NULL);
/*
* Split the old name into directory and last component
- * strings. Note that if (!unix_dfs_convert may have stripped off a
+ * strings. Note that unix_convert may have stripped off a
* leading ./ from both name and newname if the rename is
* at the root of the share. We need to make sure either both
* name and newname contain a / character or neither of them do
@@ -3309,7 +3567,16 @@ int rename_internals(connection_struct *conn,
*p = '/'; /* Replace needed for exceptional test below. */
}
- if (is_mangled(mask))
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+ if (!rc && is_mangled(mask))
check_mangled_cache( mask );
has_wild = strchr(mask,'*') || strchr(mask,'?');
@@ -3379,23 +3646,21 @@ int rename_internals(connection_struct *conn,
*/
if(resolve_wildcards(directory,newname) &&
can_rename(directory,conn) &&
- !conn->vfs_ops.rename(dos_to_unix(directory,False),
- newname))
+ !dos_rename(directory,newname))
count++;
} else {
if (resolve_wildcards(directory,newname) &&
can_rename(directory,conn) &&
- !vfs_file_exist(conn,dos_to_unix(newname,False),NULL) &&
- !conn->vfs_ops.rename(dos_to_unix(directory,False),
- newname))
+ !dos_file_exist(newname,NULL) &&
+ !dos_rename(directory,newname))
count++;
}
DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
directory,newname));
- if (!count) exists = vfs_file_exist(conn,dos_to_unix(directory,False),NULL);
- if (!count && exists && vfs_file_exist(conn,dos_to_unix(newname,False),NULL)) {
+ if (!count) exists = dos_file_exist(directory,NULL);
+ if (!count && exists && dos_file_exist(newname,NULL)) {
exists = True;
error = ERRrename;
}
@@ -3436,13 +3701,13 @@ int rename_internals(connection_struct *conn,
continue;
}
- if (!replace_if_exists && vfs_file_exist(conn,dos_to_unix(destname,False),NULL)) {
- DEBUG(6,("file_exist %s\n", destname));
+ if (!replace_if_exists && dos_file_exist(destname,NULL)) {
+ DEBUG(6,("dos_file_exist %s\n", destname));
error = 183;
continue;
}
- if (!conn->vfs_ops.rename(dos_to_unix(fname,False),destname))
+ if (!dos_rename(fname,destname))
count++;
DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
}
@@ -3492,14 +3757,16 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, in
******************************************************************/
static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
- int count,BOOL target_is_directory)
+ int count,BOOL target_is_directory, int *err_ret)
{
int Access,action;
SMB_STRUCT_STAT st;
- int ret=-1;
+ SMB_OFF_T ret=-1;
files_struct *fsp1,*fsp2;
pstring dest;
+ *err_ret = 0;
+
pstrcpy(dest,dest1);
if (target_is_directory) {
char *p = strrchr(src,'/');
@@ -3511,16 +3778,15 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
pstrcat(dest,p);
}
- if (!vfs_file_exist(conn,dos_to_unix(src,False),&st))
+ if (!dos_file_exist(src,&st))
return(False);
fsp1 = file_new();
- if (!fsp1)
+ if (!fsp1)
return(False);
- open_file_shared(fsp1, conn, src,
- SET_DENY_MODE(DENY_NONE) | SET_OPEN_MODE(DOS_OPEN_RDONLY),
- (FILE_FAIL_IF_NOT_EXIST | FILE_EXISTS_OPEN), 0, 0, &Access, &action);
+ open_file_shared(fsp1,conn,src,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
if (!fsp1->open) {
file_free(fsp1);
@@ -3535,9 +3801,8 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
close_file(fsp1,False);
return(False);
}
- open_file_shared(fsp2, conn, dest,
- SET_DENY_MODE(DENY_NONE) | SET_OPEN_MODE(DOS_OPEN_WRONLY),
- ofun, st.st_mode, 0, &Access, &action);
+ open_file_shared(fsp2,conn,dest,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
+ ofun,st.st_mode,0,&Access,&action);
if (!fsp2->open) {
close_file(fsp1,False);
@@ -3546,7 +3811,7 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
}
if ((ofun&3) == 1) {
- if(conn->vfs_ops.lseek(fsp2->fd_ptr->fd,0,SEEK_END) == -1) {
+ if(sys_lseek(fsp2->fd_ptr->fd,0,SEEK_END) == -1) {
DEBUG(0,("copy_file: error - sys_lseek returned error %s\n",
strerror(errno) ));
/*
@@ -3558,12 +3823,19 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
}
if (st.st_size)
- ret = vfs_transfer_file(-1, fsp1, -1, fsp2, st.st_size, NULL, 0, 0);
+ ret = transfer_file(fsp1->fd_ptr->fd,
+ fsp2->fd_ptr->fd,st.st_size,NULL,0,0);
close_file(fsp1,False);
- close_file(fsp2,False);
+ /*
+ * As we are opening fsp1 read-only we only expect
+ * an error on close on fsp2 if we are out of space.
+ * Thus we don't look at the error return from the
+ * close of fsp1.
+ */
+ *err_ret = close_file(fsp2,False);
- return(ret == st.st_size);
+ return(ret == (SMB_OFF_T)st.st_size);
}
@@ -3580,6 +3852,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
char *p;
int count=0;
int error = ERRnoaccess;
+ int err = 0;
BOOL has_wild;
BOOL exists=False;
int tid2 = SVAL(inbuf,smb_vwv0);
@@ -3588,6 +3861,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
BOOL target_is_directory=False;
BOOL bad_path1 = False;
BOOL bad_path2 = False;
+ BOOL rc = True;
*directory = *mask = 0;
@@ -3602,16 +3876,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return(ERROR(ERRSRV,ERRinvdevice));
}
- if (!unix_dfs_convert(name,conn,0,&bad_path1,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
- if (!unix_dfs_convert(newname,conn,0,&bad_path2,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ rc = unix_convert(name,conn,0,&bad_path1,NULL);
+ unix_convert(newname,conn,0,&bad_path2,NULL);
target_is_directory = dos_directory_exist(newname,NULL);
@@ -3639,7 +3905,16 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
pstrcpy(mask,p+1);
}
- if (is_mangled(mask))
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+ if (!rc && is_mangled(mask))
check_mangled_cache( mask );
has_wild = strchr(mask,'*') || strchr(mask,'?');
@@ -3649,8 +3924,12 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
pstrcat(directory,mask);
if (resolve_wildcards(directory,newname) &&
copy_file(directory,newname,conn,ofun,
- count,target_is_directory)) count++;
- if (!count) exists = vfs_file_exist(conn,dos_to_unix(directory,False),NULL);
+ count,target_is_directory,&err)) count++;
+ if(!count && err) {
+ errno = err;
+ return(UNIXERROR(ERRHRD,ERRgeneral));
+ }
+ if (!count) exists = dos_file_exist(directory,NULL);
} else {
void *dirptr = NULL;
char *dname;
@@ -3659,33 +3938,38 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if (check_name(directory,conn))
dirptr = OpenDir(conn, directory, True);
- if (dirptr)
- {
+ if (dirptr) {
error = ERRbadfile;
if (strequal(mask,"????????.???"))
pstrcpy(mask,"*");
- while ((dname = ReadDirName(dirptr)))
- {
+ while ((dname = ReadDirName(dirptr))) {
pstring fname;
pstrcpy(fname,dname);
- if(!mask_match(fname, mask, case_sensitive, False)) continue;
+ if(!mask_match(fname, mask, case_sensitive, False))
+ continue;
error = ERRnoaccess;
slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
pstrcpy(destname,newname);
if (resolve_wildcards(fname,destname) &&
- copy_file(directory,newname,conn,ofun,
- count,target_is_directory)) count++;
+ copy_file(fname,destname,conn,ofun,
+ count,target_is_directory,&err)) count++;
DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
}
CloseDir(dirptr);
- }
+ }
}
if (count == 0) {
+ if(err) {
+ /* Error on close... */
+ errno = err;
+ return(UNIXERROR(ERRHRD,ERRgeneral));
+ }
+
if (exists)
return(ERROR(ERRDOS,error));
else
@@ -3743,8 +4027,148 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
}
/****************************************************************************
+ Get a lock count, dealing with large count requests.
+****************************************************************************/
+
+SMB_OFF_T get_lock_count( char *data, int data_offset, BOOL large_file_format, BOOL *err)
+{
+ SMB_OFF_T count = 0;
+
+ *err = False;
+
+ if(!large_file_format) {
+ count = (SMB_OFF_T)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
+ } else {
+
+#if defined(LARGE_SMB_OFF_T) && !defined(HAVE_BROKEN_FCNTL64_LOCKS)
+
+ count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
+ ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
+
+#else /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
+
+ /*
+ * NT4.x seems to be broken in that it sends large file
+ * lockingX calls even if the CAP_LARGE_FILES was *not*
+ * negotiated. For boxes without large file locks truncate the
+ * lock count by dropping the top 32 bits.
+ */
+
+ if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
+ DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
+ (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
+ (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
+ SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
+ }
+
+ if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
+ /*
+ * Before we error out, see if we can sensibly map the top bits
+ * down to the lower bits - or lose the top bits if they are all 1's.
+ * It seems that NT has this horrible bug where it will send 64 bit
+ * lock requests even if told not to. JRA.
+ */
+
+ if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) == (uint32)0xFFFFFFFF)
+ count = (SMB_OFF_T)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset));
+ else if (IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) == (uint32)0xFFFFFFFF)
+ count = (SMB_OFF_T)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
+ else {
+
+ DEBUG(0,("get_lock_count: Error : a large file count (%x << 32 | %x) was sent and we don't \
+support large counts.\n", (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
+ (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
+
+ *err = True;
+ return (SMB_OFF_T)-1;
+ }
+ }
+ else
+ count = (SMB_OFF_T)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
+
+#endif /* LARGE_SMB_OFF_T */
+ }
+ return count;
+}
+
+/****************************************************************************
+ Get a lock offset, dealing with large offset requests.
+****************************************************************************/
+
+SMB_OFF_T get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err)
+{
+ SMB_OFF_T offset = 0;
+
+ *err = False;
+
+ if(!large_file_format) {
+ offset = (SMB_OFF_T)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
+ } else {
+
+#if defined(LARGE_SMB_OFF_T) && !defined(HAVE_BROKEN_FCNTL64_LOCKS)
+
+ offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
+ ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
+
+#else /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
+
+ /*
+ * NT4.x seems to be broken in that it sends large file
+ * lockingX calls even if the CAP_LARGE_FILES was *not*
+ * negotiated. For boxes without large file locks mangle the
+ * lock offset by mapping the top 32 bits onto the lower 32.
+ */
+
+ if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
+ uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+ uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
+ uint32 new_low = 0;
+
+ if((new_low = map_lock_offset(high, low)) == 0) {
+ *err = True;
+ return (SMB_OFF_T)-1;
+ }
+
+ DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
+ (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
+ SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
+ SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
+ }
+
+ if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0){
+ /*
+ * Before we error out, see if we can sensibly map the top bits
+ * down to the lower bits - or lose the top bits if they are all 1's.
+ * It seems that NT has this horrible bug where it will send 64 bit
+ * lock requests even if told not to. JRA.
+ */
+
+ if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)) == (uint32)0xFFFFFFFF)
+ offset = (SMB_OFF_T)IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
+ else if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) == (uint32)0xFFFFFFFF)
+ offset = (SMB_OFF_T)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+ else {
+
+ DEBUG(0,("get_lock_count: Error : a large file offset (%x << 32 | %x) was sent and we don't \
+support large offsets.\n", (unsigned int)IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)),
+ (unsigned int)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)) ));
+
+ *err = True;
+ return (SMB_OFF_T)-1;
+ }
+ }
+ else
+ offset = (SMB_OFF_T)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+
+#endif /* LARGE_SMB_OFF_T */
+ }
+ return offset;
+}
+
+/****************************************************************************
reply to a lockingX request
****************************************************************************/
+
int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
files_struct *fsp = file_fsp(inbuf,smb_vwv2);
@@ -3761,6 +4185,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
uint32 ecode=0, dummy2;
int eclass=0, dummy1;
BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
+ BOOL err1, err2;
+
CHECK_FSP(fsp,conn);
CHECK_ERROR(fsp);
@@ -3771,35 +4197,28 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
*/
if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
{
- int token;
- SMB_DEV_T dev = fsp->fd_ptr->dev;
- SMB_INO_T inode = fsp->fd_ptr->inode;
-
DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
fsp->fnum));
+
/*
- * Make sure we have granted an oplock on this file.
+ * Make sure we have granted an exclusive or batch oplock on this file.
*/
- if(!fsp->granted_oplock)
+
+ if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
{
DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
-no oplock granted on this file.\n", fsp->fnum));
- return ERROR(ERRDOS,ERRlock);
- }
-
- /* Remove the oplock flag from the sharemode. */
- lock_share_entry(fsp->conn, dev, inode, &token);
- if(remove_share_oplock(token, fsp)==False) {
-
- DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
-dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode));
+no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
- unlock_share_entry(fsp->conn, dev, inode, token);
- } else {
- unlock_share_entry(fsp->conn, dev, inode, token);
+ /* if this is a pure oplock break request then don't send a reply */
+ if (num_locks == 0 && num_ulocks == 0)
+ return -1;
+ else
+ return ERROR(ERRDOS,ERRlock);
+ }
- /* Clear the granted flag and return. */
- fsp->granted_oplock = False;
+ if (remove_oplock(fsp) == False) {
+ DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n",
+ fsp->fsp_name ));
}
/* if this is a pure oplock break request then don't send a reply */
@@ -3817,18 +4236,14 @@ dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode));
/* Data now points at the beginning of the list
of smb_unlkrng structs */
for(i = 0; i < (int)num_ulocks; i++) {
- if(!large_file_format) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- }
-#ifdef LARGE_SMB_OFF_T
- else {
- count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
- offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
- }
-#endif /* LARGE_SMB_OFF_T */
+ count = get_lock_count( data, i, large_file_format, &err1);
+ offset = get_lock_offset( data, i, large_file_format, &err2);
+
+ /*
+ * There is no error code marked "stupid client bug".... :-).
+ */
+ if(err1 || err2)
+ return ERROR(ERRDOS,ERRnoaccess);
DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for file %s\n",
(double)offset, (double)count, fsp->fsp_name ));
@@ -3847,18 +4262,14 @@ dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode));
of smb_lkrng structs */
for(i = 0; i < (int)num_locks; i++) {
- if(!large_file_format) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- }
-#ifdef LARGE_SMB_OFF_T
- else {
- count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
- offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
- }
-#endif /* LARGE_SMB_OFF_T */
+ count = get_lock_count( data, i, large_file_format, &err1);
+ offset = get_lock_offset( data, i, large_file_format, &err2);
+
+ /*
+ * There is no error code marked "stupid client bug".... :-).
+ */
+ if(err1 || err2)
+ return ERROR(ERRDOS,ERRnoaccess);
DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for file %s\n",
(double)offset, (double)count, fsp->fsp_name ));
@@ -3882,19 +4293,15 @@ dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode));
all of the previous locks (X/Open spec). */
if(i != num_locks && num_locks != 0) {
for(; i >= 0; i--) {
- if(!large_file_format) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- }
-#ifdef LARGE_SMB_OFF_T
- else {
- count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
- offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
- }
-#endif /* LARGE_SMB_OFF_T */
+ count = get_lock_count( data, i, large_file_format, &err1);
+ offset = get_lock_offset( data, i, large_file_format, &err2);
+ /*
+ * There is no error code marked "stupid client bug".... :-).
+ */
+ if(err1 || err2)
+ return ERROR(ERRDOS,ERRnoaccess);
+
do_unlock(fsp,conn,count,offset,&dummy1,&dummy2);
}
return ERROR(eclass,ecode);
@@ -3980,7 +4387,8 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
/****************************************************************************
reply to a SMBwritebmpx (write block multiplex primary) request
****************************************************************************/
-int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
size_t numtowrite;
ssize_t nwritten = -1;
@@ -4011,14 +4419,10 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
if (is_locked(fsp,conn,tcount,startpos,F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- nwritten = write_file(fsp,data,numtowrite);
-
- if((lp_syncalways(SNUM(conn)) || write_through) &&
- lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
+ if(lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
if(nwritten < (ssize_t)numtowrite)
return(UNIXERROR(ERRHRD,ERRdiskfull));
@@ -4056,7 +4460,7 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
- fsp->fnum, numtowrite, nwritten ) );
+ fsp->fnum, (int)numtowrite, (int)nwritten ) );
if (write_through && tcount==nwritten) {
/* we need to send both a primary and a secondary response */
@@ -4116,23 +4520,10 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
if(wbms->wr_discard)
return -1; /* Just discard the packet */
- if(seek_file(fsp,startpos) == -1)
- {
- if(write_through)
- {
- /* We are returning an error - we can delete the aux struct */
- if (wbms) free((char *)wbms);
- fsp->wbmpx_ptr = NULL;
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
- return(CACHE_ERROR(wbms,ERRDOS,ERRnoaccess));
- }
-
- nwritten = write_file(fsp,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
- if((lp_syncalways(SNUM(conn)) || write_through) &&
- lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
+ if(lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
if (nwritten < (ssize_t)numtowrite)
{
@@ -4172,7 +4563,8 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
/****************************************************************************
reply to a SMBsetattrE
****************************************************************************/
-int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
struct utimbuf unix_times;
int outsize = 0;
@@ -4224,7 +4616,8 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_si
/****************************************************************************
reply to a SMBgetattrE
****************************************************************************/
-int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
SMB_STRUCT_STAT sbuf;
int outsize = 0;
@@ -4237,7 +4630,7 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_si
CHECK_ERROR(fsp);
/* Do an fstat on this file */
- if(fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd, &sbuf))
+ if(sys_fstat(fsp->fd_ptr->fd, &sbuf))
return(UNIXERROR(ERRDOS,ERRnoaccess));
mode = dos_mode(conn,fsp->fsp_name,&sbuf);
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index bdb2827483..1c6d6536ad 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -25,9 +25,7 @@
pstring servicesf = CONFIGFILE;
extern pstring debugf;
extern fstring global_myworkgroup;
-extern fstring global_sam_name;
extern pstring global_myname;
-extern dfs_internal dfs_struct;
int am_parent = 1;
@@ -49,8 +47,6 @@ extern int dcelogin_atmost_once;
extern fstring remote_machine;
extern pstring OriginalDir;
-extern pstring myhostname;
-
/****************************************************************************
when exiting, take the whole family
@@ -76,13 +72,11 @@ static void killkids(void)
static BOOL open_sockets_inetd(void)
{
extern int Client;
- extern int ClientPort;
/* Started from inetd. fd 0 is the socket. */
/* We will abort gracefully when the client or remote system
goes away */
Client = dup(0);
- ClientPort = SMB_PORT;
/* close our standard file descriptors */
close_low_fds();
@@ -93,40 +87,19 @@ static BOOL open_sockets_inetd(void)
return True;
}
-/****************************************************************************
- open and listen to a socket
-****************************************************************************/
-static int open_server_socket(int port, uint32 ipaddr)
-{
- int s;
-
- s = open_socket_in(SOCK_STREAM, port, 0, ipaddr);
- if(s == -1)
- return -1;
- /* ready to listen */
- if (listen(s, 5) == -1) {
- DEBUG(0,("listen: %s\n", strerror(errno)));
- close(s);
- return -1;
- }
- return s;
-}
/****************************************************************************
open the socket communication
****************************************************************************/
-static BOOL open_sockets(BOOL is_daemon,int port,int port445)
+static BOOL open_sockets(BOOL is_daemon,int port)
{
extern int Client;
- extern int ClientPort;
int num_interfaces = iface_count();
int fd_listenset[FD_SETSIZE];
fd_set listen_set;
int s;
int i;
- memset(&fd_listenset, 0, sizeof(fd_listenset));
-
if (!is_daemon) {
return open_sockets_inetd();
}
@@ -154,7 +127,7 @@ static BOOL open_sockets(BOOL is_daemon,int port,int port445)
socket per interface and bind to only these.
*/
- if(num_interfaces * 2 > FD_SETSIZE) {
+ if(num_interfaces > FD_SETSIZE) {
DEBUG(0,("open_sockets: Too many interfaces specified to bind to. Number was %d \
max can be %d\n",
num_interfaces, FD_SETSIZE));
@@ -170,11 +143,15 @@ max can be %d\n",
DEBUG(0,("open_sockets: interface %d has NULL IP address !\n", i));
continue;
}
- s = fd_listenset[i * 2] = open_server_socket(port, ifip->s_addr);
- if(s == -1) return False;
- FD_SET(s,&listen_set);
- s = fd_listenset[i * 2 + 1] = open_server_socket(port445, ifip->s_addr);
- if(s == -1) return False;
+ s = fd_listenset[i] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
+ if(s == -1)
+ return False;
+ /* ready to listen */
+ if (listen(s, 5) == -1) {
+ DEBUG(0,("listen: %s\n",strerror(errno)));
+ close(s);
+ return False;
+ }
FD_SET(s,&listen_set);
}
} else {
@@ -183,18 +160,21 @@ max can be %d\n",
num_interfaces = 1;
/* open an incoming socket */
- s = open_server_socket(port, interpret_addr(lp_socket_address()));
+ s = open_socket_in(SOCK_STREAM, port, 0,
+ interpret_addr(lp_socket_address()),True);
if (s == -1)
return(False);
+
+ /* ready to listen */
+ if (listen(s, 5) == -1) {
+ DEBUG(0,("open_sockets: listen: %s\n",
+ strerror(errno)));
+ close(s);
+ return False;
+ }
+
fd_listenset[0] = s;
FD_SET(s,&listen_set);
-#if 0
- s = open_server_socket(port445, interpret_addr(lp_socket_address()));
- if (s == -1)
- return(False);
- fd_listenset[1] = s;
- FD_SET(s,&listen_set);
-#endif
}
/* now accept incoming connections - forking a new process
@@ -207,11 +187,14 @@ max can be %d\n",
memcpy((char *)&lfds, (char *)&listen_set,
sizeof(listen_set));
- num = sys_select(256,&lfds,NULL, NULL);
+ num = sys_select(FD_SETSIZE,&lfds,NULL);
if (num == -1 && errno == EINTR)
continue;
+ /* check if we need to reload services */
+ check_reload(time(NULL));
+
/* Find the sockets that are read-ready -
accept on these. */
for( ; num > 0; num--) {
@@ -220,24 +203,15 @@ max can be %d\n",
s = -1;
for(i = 0; i < num_interfaces; i++) {
- if(FD_ISSET(fd_listenset[i * 2],&lfds)) {
- s = fd_listenset[i * 2];
- ClientPort = SMB_PORT;
+ if(FD_ISSET(fd_listenset[i],&lfds)) {
+ s = fd_listenset[i];
+ /* Clear this so we don't look
+ at it again. */
+ FD_CLR(fd_listenset[i],&lfds);
break;
}
-#if 0
- if(FD_ISSET(fd_listenset[i * 2 + 1],&lfds)) {
- s = fd_listenset[i * 2 + 1];
- ClientPort = SMB_PORT2;
- break;
- }
-#endif
}
- /* Clear this so we don't look
- at it again. */
- FD_CLR(s,&lfds);
-
Client = accept(s,&addr,&in_addrlen);
if (Client == -1 && errno == EINTR)
@@ -357,9 +331,10 @@ BOOL reload_services(BOOL test)
/****************************************************************************
-this prevents zombie child processes
+ Catch a sighup.
****************************************************************************/
-BOOL reload_after_sighup = False;
+
+VOLATILE SIG_ATOMIC_T reload_after_sighup = False;
static void sig_hup(int sig)
{
@@ -434,6 +409,8 @@ void exit_server(char *reason)
conn_close_all();
+ respond_to_all_remaining_local_messages();
+
#ifdef WITH_DFS
if (dcelogin_atmost_once) {
dfs_unlogin();
@@ -456,13 +433,6 @@ void exit_server(char *reason)
locking_end();
DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
-#ifdef MEM_MAN
- {
- extern FILE *dbf;
- smb_mem_write_verbose(dbf);
- dbgflush();
- }
-#endif
exit(0);
}
@@ -471,17 +441,34 @@ void exit_server(char *reason)
/****************************************************************************
initialise connect, service and file structs
****************************************************************************/
-static void init_structs(void)
+static void init_structs(void )
{
+ /*
+ * Set the machine NETBIOS name if not already
+ * set from the config file.
+ */
+
+ if (!*global_myname) {
+ char *p;
+ fstrcpy( global_myname, myhostname() );
+ p = strchr( global_myname, '.' );
+ if (p)
+ *p = 0;
+ }
+
+ strupper( global_myname );
+
conn_init();
+
file_init();
- init_rpc_pipe_hnd(); /* for RPC pipes */
- if (!init_policy_hnd(MAX_SERVER_POLICY_HANDLES))
- {
- exit_server("could not allocate policy handles\n");
- }
+
+ /* for RPC pipes */
+ init_rpc_pipe_hnd();
+
+ /* for LSA handles */
+ init_lsa_policy_hnd();
+
init_dptrs();
- init_dfs_table();
}
/****************************************************************************
@@ -489,19 +476,21 @@ usage on the program
****************************************************************************/
static void usage(char *pname)
{
- DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
-
- printf("Usage: %s [-D] [-p port] [-d debuglevel] ", pname);
- printf("[-l log basename] [-s services file]\n" );
- printf("Version %s\n",VERSION);
- printf("\t-D become a daemon\n");
- printf("\t-p port listen on the specified port\n");
- printf("\t-d debuglevel set the debuglevel\n");
+
+ printf("Usage: %s [-DaoPh?V] [-d debuglevel] [-l log basename] [-p port]\n", pname);
+ printf(" [-O socket options] [-s services file] [-i scope]\n");
+ printf("\t-D Become a daemon\n");
+ printf("\t-a Append to log file (default)\n");
+ printf("\t-o Overwrite log file, don't append\n");
+ printf("\t-P Passive only\n");
+ printf("\t-h Print usage\n");
+ printf("\t-? Print usage\n");
+ printf("\t-V Print version\n");
+ printf("\t-d debuglevel Set the debuglevel\n");
printf("\t-l log basename. Basename for log/debug files\n");
+ printf("\t-p port Listen on the specified port\n");
+ printf("\t-O socket options Socket options\n");
printf("\t-s services file. Filename of services file\n");
- printf("\t-P passive only\n");
- printf("\t-a append to log file (default)\n");
- printf("\t-o overwrite log file, don't append\n");
printf("\t-i scope NetBIOS scope to use (default none)\n");
printf("\n");
}
@@ -516,7 +505,6 @@ static void usage(char *pname)
/* shall I run as a daemon */
BOOL is_daemon = False;
int port = SMB_PORT;
- int port445 = SMB_PORT2;
int opt;
extern char *optarg;
@@ -524,55 +512,13 @@ static void usage(char *pname)
set_auth_parameters(argc,argv);
#endif
-#ifdef HAVE_SETLUID
- /* needed for SecureWare on SCO */
- setluid(0);
-#endif
-
- append_log = True;
-
- TimeInit();
-
- pstrcpy(debugf,SMBLOGFILE);
-
- pstrcpy(remote_machine, "smb");
-
- setup_logging(argv[0],False);
-
- charset_initialise();
-
- /* make absolutely sure we run as root - to handle cases where people
- are crazy enough to have it setuid */
-#ifdef HAVE_SETRESUID
- setresuid(0,0,0);
-#else
- setuid(0);
- seteuid(0);
- setuid(0);
- seteuid(0);
-#endif
-
- fault_setup((void (*)(void *))exit_server);
- CatchSignal(SIGTERM , SIGNAL_CAST dflt_sig);
-
- /* we are never interested in SIGPIPE */
- BlockSignals(True,SIGPIPE);
-
- /* we want total control over the permissions on created files,
- so set our umask to 0 */
- umask(0);
-
- dos_GetWd(OriginalDir);
-
- init_uid();
-
/* this is for people who can't start the program correctly */
while (argc > 1 && (*argv[1] != '-')) {
argv++;
argc--;
}
- while ( EOF != (opt = getopt(argc, argv, "O:i:l:s:d:Dp:h?Paof:")) )
+ while ( EOF != (opt = getopt(argc, argv, "O:i:l:s:d:Dp:h?VPaof:")) )
switch (opt) {
case 'O':
pstrcpy(user_socket_options,optarg);
@@ -626,11 +572,72 @@ static void usage(char *pname)
exit(0);
break;
+ case 'V':
+ printf("Version %s\n",VERSION);
+ exit(0);
+ break;
default:
+ DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
usage(argv[0]);
exit(1);
}
+#ifdef HAVE_SETLUID
+ /* needed for SecureWare on SCO */
+ setluid(0);
+#endif
+
+ /*
+ * gain_root_privilege uses an assert than will cause a core
+ * dump if euid != 0. Ensure this is the case.
+ */
+
+ if(geteuid() != (uid_t)0) {
+ fprintf(stderr, "%s: Version %s : Must have effective user id of zero to run.\n", argv[0], VERSION);
+ exit(1);
+ }
+
+ append_log = True;
+
+ TimeInit();
+
+ pstrcpy(debugf,SMBLOGFILE);
+
+ pstrcpy(remote_machine, "smb");
+
+ setup_logging(argv[0],False);
+
+ charset_initialise();
+
+ /* we want to re-seed early to prevent time delays causing
+ client problems at a later date. (tridge) */
+ generate_random_buffer(NULL, 0, False);
+
+ /* make absolutely sure we run as root - to handle cases where people
+ are crazy enough to have it setuid */
+
+ gain_root_privilege();
+ gain_root_group_privilege();
+
+ fault_setup((void (*)(void *))exit_server);
+ CatchSignal(SIGTERM , SIGNAL_CAST dflt_sig);
+
+ /* we are never interested in SIGPIPE */
+ BlockSignals(True,SIGPIPE);
+
+#if defined(SIGFPE)
+ /* we are never interested in SIGFPE */
+ BlockSignals(True,SIGFPE);
+#endif
+
+ /* we want total control over the permissions on created files,
+ so set our umask to 0 */
+ umask(0);
+
+ dos_GetWd(OriginalDir);
+
+ init_uid();
+
reopen_logs();
DEBUG(1,( "smbd version %s started.\n", VERSION));
@@ -644,13 +651,15 @@ static void usage(char *pname)
exit(1);
}
- get_myname(myhostname,NULL);
+ /*
+ * Do this before reload_services.
+ */
if (!reload_services(False))
return(-1);
init_structs();
-
+
#ifdef WITH_PROFILE
if (!profile_setup(False)) {
DEBUG(0,("ERROR: failed to setup profiling\n"));
@@ -658,16 +667,6 @@ static void usage(char *pname)
}
#endif
- /*
- * Set the machine NETBIOS name if not already
- * set from the config file.
- */
- if (!*global_myname)
- {
- fstrcpy(global_myname, dns_to_netbios_name(myhostname));
- }
- strupper(global_myname);
-
#ifdef WITH_SSL
{
extern BOOL sslEnabled;
@@ -679,40 +678,10 @@ static void usage(char *pname)
codepage_initialise(lp_client_code_page());
- if (!pwdb_initialise(True))
- {
- exit(1);
- }
-
- if(!initialise_sam_password_db())
- {
- exit(1);
- }
-
- if(!initialise_passgrp_db())
- {
- exit(1);
- }
+ fstrcpy(global_myworkgroup, lp_workgroup());
- if(!initialise_group_db())
- {
- exit(1);
- }
-
- if(!initialise_alias_db())
- {
- exit(1);
- }
-
- if(!initialise_builtin_db())
- {
- exit(1);
- }
-
- if (!get_member_domain_sid())
- {
- DEBUG(0,("ERROR: Samba cannot obtain PDC SID from PDC(s) %s.\n",
- lp_passwordserver()));
+ if(!pdb_generate_sam_sid()) {
+ DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n"));
exit(1);
}
@@ -746,7 +715,7 @@ static void usage(char *pname)
become_daemon();
}
- check_kernel_oplocks();
+ check_kernel_oplocks();
if (!directory_exist(lp_lockdir(), NULL)) {
mkdir(lp_lockdir(), 0755);
@@ -756,10 +725,13 @@ static void usage(char *pname)
pidfile_create("smbd");
}
- if (!open_sockets(is_daemon,port,port445))
+ if (!locking_init(0))
exit(1);
- if (!locking_init(0))
+ if (!open_sockets(is_daemon,port))
+ exit(1);
+
+ if(!initialize_password_db())
exit(1);
/* possibly reload the services file. */
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index 64abf3de1d..92807e2d43 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -23,7 +23,7 @@
extern int DEBUGLEVEL;
-extern time_t smb_last_time;
+extern struct timeval smb_last_time;
extern int case_default;
extern BOOL case_preserve;
extern BOOL short_case_preserve;
@@ -49,7 +49,7 @@ BOOL become_service(connection_struct *conn,BOOL do_chdir)
return(False);
}
- conn->lastused = smb_last_time;
+ conn->lastused = smb_last_time.tv_sec;
snum = SNUM(conn);
@@ -84,24 +84,23 @@ int find_service(char *service)
{
int iService;
- string_sub(service,"\\","/");
+ all_string_sub(service,"\\","/",0);
iService = lp_servicenumber(service);
/* now handle the special case of a home directory */
if (iService < 0)
{
- char *phome_dir = get_unixhome_dir(service);
- pstring home_dir;
+ char *phome_dir = get_user_home_dir(service);
- if(phome_dir == NULL)
+ if(!phome_dir)
{
/*
* Try mapping the servicename, it may
* be a Windows to unix mapped user name.
*/
if(map_username(service))
- phome_dir = get_unixhome_dir(service);
+ phome_dir = get_user_home_dir(service);
}
DEBUG(3,("checking for home directory %s gave %s\n",service,
@@ -110,10 +109,9 @@ int find_service(char *service)
if (phome_dir)
{
int iHomeService;
- pstrcpy(home_dir, phome_dir);
if ((iHomeService = lp_servicenumber(HOMES_NAME)) >= 0)
{
- lp_add_home(service,iHomeService,home_dir);
+ lp_add_home(service,iHomeService,phome_dir);
iService = lp_servicenumber(service);
}
}
@@ -144,11 +142,6 @@ int find_service(char *service)
}
}
- /* Check for default vfs service? Unsure whether to implement this */
- if (iService < 0)
- {
- }
-
/* just possibly it's a default service? */
if (iService < 0)
{
@@ -168,7 +161,7 @@ int find_service(char *service)
iService = find_service(defservice);
if (iService >= 0)
{
- string_sub(service,"_","/");
+ all_string_sub(service,"_","/",0);
iService = lp_add_service(service,iService);
}
}
@@ -194,11 +187,12 @@ int find_service(char *service)
connection_struct *make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid, int *ecode)
{
int snum;
- const struct passwd *pass = NULL;
+ struct passwd *pass = NULL;
BOOL guest = False;
BOOL force = False;
extern int Client;
connection_struct *conn;
+ int ret;
strlower(service);
@@ -218,21 +212,31 @@ connection_struct *make_connection(char *service,char *user,char *password, int
}
if (strequal(service,HOMES_NAME)) {
- if (*user && Get_Pwnam(user,True))
- return(make_connection(user,user,password,
+ if (*user && Get_Pwnam(user,True)) {
+ fstring dos_username;
+ fstrcpy(dos_username, user);
+ unix_to_dos(dos_username, True);
+ return(make_connection(dos_username,user,password,
pwlen,dev,vuid,ecode));
+ }
if(lp_security() != SEC_SHARE) {
if (validated_username(vuid)) {
- pstrcpy(user,validated_username(vuid));
- return(make_connection(user,user,password,pwlen,dev,vuid,ecode));
+ fstring dos_username;
+ fstrcpy(user,validated_username(vuid));
+ fstrcpy(dos_username, user);
+ unix_to_dos(dos_username, True);
+ return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
}
} else {
/* Security = share. Try with sesssetup_user
* as the username. */
if(*sesssetup_user) {
- pstrcpy(user,sesssetup_user);
- return(make_connection(user,user,password,pwlen,dev,vuid,ecode));
+ fstring dos_username;
+ fstrcpy(user,sesssetup_user);
+ fstrcpy(dos_username, user);
+ unix_to_dos(dos_username, True);
+ return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
}
}
}
@@ -300,13 +304,13 @@ connection_struct *make_connection(char *service,char *user,char *password, int
{
pstring list;
StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1);
- string_sub(list,"%S",service);
+ pstring_sub(list,"%S",service);
if (user_in_list(user,list))
conn->read_only = True;
StrnCpy(list,lp_writelist(snum),sizeof(pstring)-1);
- string_sub(list,"%S",service);
+ pstring_sub(list,"%S",service);
if (user_in_list(user,list))
conn->read_only = False;
@@ -333,6 +337,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
conn->vuid = vuid;
conn->uid = pass->pw_uid;
conn->gid = pass->pw_gid;
+ safe_strcpy(conn->client_address, client_addr(Client), sizeof(conn->client_address)-1);
conn->num_files_open = 0;
conn->lastused = time(NULL);
conn->service = snum;
@@ -345,65 +350,83 @@ connection_struct *make_connection(char *service,char *user,char *password, int
conn->veto_oplock_list = NULL;
string_set(&conn->dirpath,"");
string_set(&conn->user,user);
+
+ /*
+ * If force user is true, then store the
+ * given userid and also the primary groupid
+ * of the user we're forcing.
+ */
+
+ if (*lp_force_user(snum)) {
+ struct passwd *pass2;
+ pstring fuser;
+ pstrcpy(fuser,lp_force_user(snum));
- /* Initialise VFS function pointers */
-
- if (*lp_vfsobj(SNUM(conn))) {
-
-#ifdef HAVE_LIBDL
-
- /* Loadable object file */
-
- if (!vfs_init_custom(conn)) {
- return NULL;
- }
-#else
- DEBUG(0, ("No libdl present - cannot use VFS objects\n"));
- conn_free(conn);
- return NULL;
-#endif
-
- } else {
-
- /* Normal share - initialise with disk access functions */
+ /* Allow %S to be used by force user. */
+ pstring_sub(fuser,"%S",service);
- vfs_init_default(conn);
+ pass2 = (struct passwd *)Get_Pwnam(fuser,True);
+ if (pass2) {
+ conn->uid = pass2->pw_uid;
+ conn->gid = pass2->pw_gid;
+ string_set(&conn->user,fuser);
+ fstrcpy(user,fuser);
+ conn->force_user = True;
+ DEBUG(3,("Forced user %s\n",fuser));
+ } else {
+ DEBUG(1,("Couldn't find user %s\n",fuser));
+ }
}
#ifdef HAVE_GETGRNAM
+ /*
+ * If force group is true, then override
+ * any groupid stored for the connecting user.
+ */
+
if (*lp_force_group(snum)) {
struct group *gptr;
pstring gname;
+ pstring tmp_gname;
+ BOOL user_must_be_member = False;
- StrnCpy(gname,lp_force_group(snum),sizeof(pstring)-1);
+ StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);
+
+ if (tmp_gname[0] == '+') {
+ user_must_be_member = True;
+ StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
+ } else {
+ StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
+ }
/* default service may be a group name */
- string_sub(gname,"%S",service);
+ pstring_sub(gname,"%S",service);
gptr = (struct group *)getgrnam(gname);
if (gptr) {
- conn->gid = gptr->gr_gid;
- DEBUG(3,("Forced group %s\n",gname));
+ /*
+ * If the user has been forced and the forced group starts
+ * with a '+', then we only set the group to be the forced
+ * group if the forced user is a member of that group.
+ * Otherwise, the meaning of the '+' would be ignored.
+ */
+ if (conn->force_user && user_must_be_member) {
+ int i;
+ for (i = 0; gptr->gr_mem[i] != NULL; i++) {
+ if (strcmp(user,gptr->gr_mem[i]) == 0) {
+ conn->gid = gptr->gr_gid;
+ DEBUG(3,("Forced group %s for member %s\n",gname,user));
+ break;
+ }
+ }
+ } else {
+ conn->gid = gptr->gr_gid;
+ DEBUG(3,("Forced group %s\n",gname));
+ }
} else {
DEBUG(1,("Couldn't find group %s\n",gname));
}
}
-#endif
-
- if (*lp_force_user(snum)) {
- const struct passwd *pass2;
- fstring fuser;
- fstrcpy(fuser,lp_force_user(snum));
- pass2 = (const struct passwd *)Get_Pwnam(fuser,True);
- if (pass2) {
- conn->uid = pass2->pw_uid;
- string_set(&conn->user,fuser);
- fstrcpy(user,fuser);
- conn->force_user = True;
- DEBUG(3,("Forced user %s\n",fuser));
- } else {
- DEBUG(1,("Couldn't find user %s\n",fuser));
- }
- }
+#endif /* HAVE_GETGRNAM */
{
pstring s;
@@ -420,7 +443,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
if (!IS_IPC(conn)) {
/* Find all the groups this uid is in and
store them. Used by become_user() */
- get_unixgroups(conn->user,conn->uid,conn->gid,
+ setup_groups(conn->user,conn->uid,conn->gid,
&conn->ngroups,&conn->groups);
/* check number of connections */
@@ -445,7 +468,13 @@ connection_struct *make_connection(char *service,char *user,char *password, int
pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
standard_sub(conn,cmd);
DEBUG(5,("cmd=%s\n",cmd));
- smbrun(cmd,NULL,False);
+ ret = smbrun(cmd,NULL,False);
+ if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
+ DEBUG(1,("preexec gave %d - failing connection\n", ret));
+ conn_free(conn);
+ *ecode = ERRsrverror;
+ return NULL;
+ }
}
if (!become_user(conn, conn->vuid)) {
@@ -499,7 +528,26 @@ connection_struct *make_connection(char *service,char *user,char *password, int
pstring cmd;
pstrcpy(cmd,lp_preexec(SNUM(conn)));
standard_sub(conn,cmd);
- smbrun(cmd,NULL,False);
+ ret = smbrun(cmd,NULL,False);
+ if (ret != 0 && lp_preexec_close(SNUM(conn))) {
+ DEBUG(1,("preexec gave %d - failing connection\n", ret));
+ conn_free(conn);
+ *ecode = ERRsrverror;
+ return NULL;
+ }
+ }
+
+ /*
+ * Print out the 'connected as' stuff here as we need
+ * to know the effective uid and gid we will be using.
+ */
+
+ if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
+ dbgtext( "%s (%s) ", remote_machine, conn->client_address );
+ dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
+ dbgtext( "as user %s ", user );
+ dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
+ dbgtext( "(pid %d)\n", (int)getpid() );
}
/* we've finished with the sensitive stuff */
@@ -512,61 +560,6 @@ connection_struct *make_connection(char *service,char *user,char *password, int
set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
}
- if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
- extern int Client;
-
- dbgtext( "%s (%s) ", remote_machine, client_addr(Client) );
- dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)));
- dbgtext( "as user %s ", user );
- dbgtext( "(uid=%d, gid=%d) ", (int)conn->uid, (int)conn->gid );
- dbgtext( "(pid %d)\n", (int)getpid() );
- }
-
- /* Invoke make connection hook */
-
- if (conn->vfs_ops.connect) {
- struct vfs_connection_struct *vconn;
-
- vconn = (struct vfs_connection_struct *)
- malloc(sizeof(struct vfs_connection_struct));
-
- if (vconn == NULL) {
- DEBUG(0, ("No memory to create vfs_connection_struct"));
- return NULL;
- }
-
- ZERO_STRUCTP(vconn);
-
- /* Copy across relevant data from connection struct */
-
- vconn->printer = conn->printer;
- vconn->ipc = conn->ipc;
- vconn->read_only = conn->read_only;
- vconn->admin_user = conn->admin_user;
-
- pstrcpy(vconn->dirpath, conn->dirpath);
- pstrcpy(vconn->connectpath, conn->connectpath);
- pstrcpy(vconn->origpath, conn->origpath);
-
- pstrcpy(vconn->service, service);
- pstrcpy(vconn->user, conn->user);
-
- vconn->uid = conn->uid;
- vconn->gid = conn->gid;
- vconn->ngroups = conn->ngroups;
- vconn->groups = (gid_t *)malloc(conn->ngroups * sizeof(gid_t));
- if (vconn->groups != NULL) {
- memcpy(vconn->groups, conn->groups,
- conn->ngroups * sizeof(gid_t));
- }
-
- /* Call connect hook */
-
- if (conn->vfs_ops.connect(vconn, service, user) < 0) {
- return NULL;
- }
- }
-
return(conn);
}
@@ -576,31 +569,14 @@ close a cnum
****************************************************************************/
void close_cnum(connection_struct *conn, uint16 vuid)
{
- extern int Client;
DirCacheFlush(SNUM(conn));
unbecome_user();
DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
- remote_machine,client_addr(Client),
+ remote_machine,conn->client_address,
lp_servicename(SNUM(conn))));
- if (conn->vfs_ops.disconnect != NULL) {
-
- /* Call disconnect hook */
-
- conn->vfs_ops.disconnect();
-
- /* Free vfs_connection_struct */
-
- if (conn->vfs_conn != NULL) {
- if (conn->vfs_conn->groups != NULL) {
- free(conn->vfs_conn->groups);
- }
- free(conn->vfs_conn);
- }
- }
-
yield_connection(conn,
lp_servicename(SNUM(conn)),
lp_max_connections(SNUM(conn)));
@@ -632,5 +608,3 @@ void close_cnum(connection_struct *conn, uint16 vuid)
conn_free(conn);
}
-
-
diff --git a/source3/smbd/ssl.c b/source3/smbd/ssl.c
index 1f098b2533..be9aae7c5c 100644
--- a/source3/smbd/ssl.c
+++ b/source3/smbd/ssl.c
@@ -19,14 +19,14 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include "includes.h"
-
-/*
- * Hmmm, only check on WITH_SSL after we have included includes.h
- * which pulls in config.h which is where WITH_SSL is defined, if
- * at all :-)
+/*
+ * since includes.h pulls in config.h which is were WITH_SSL will be
+ * defined, we want to include includes.h before testing for WITH_SSL
+ * RJS 26-Jan-1999
*/
+#include "includes.h"
+
#ifdef WITH_SSL /* should always be defined if this module is compiled */
#include <ssl.h>
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 14fa26dd55..e971f8bbb6 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -31,7 +31,7 @@ extern int Client;
extern int smb_read_error;
extern fstring local_machine;
extern int global_oplock_break;
-extern dfs_internal dfs_struct;
+extern uint32 global_client_caps;
/****************************************************************************
Send the required number of replies back.
@@ -113,8 +113,7 @@ static int send_trans2_replies(char *outbuf, int bufsize, char *params,
SSVAL(outbuf,smb_prcnt, params_sent_thistime);
if(params_sent_thistime == 0)
{
- /*SSVAL(outbuf,smb_proff,0);*/
- SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
+ SSVAL(outbuf,smb_proff,0);
SSVAL(outbuf,smb_prdisp,0);
}
else
@@ -216,11 +215,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf,
/* XXXX we need to handle passed times, sattr and flags */
- if (!unix_dfs_convert(fname,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(fname,conn,0,&bad_path,NULL);
fsp = file_new();
if (!fsp)
@@ -253,7 +248,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf,
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
- if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ if (sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
close_file(fsp,False);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
@@ -272,7 +267,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf,
if(params == NULL)
return(ERROR(ERRDOS,ERRnomem));
- bzero(params,28);
+ memset((char *)params,'\0',28);
SSVAL(params,0,fsp->fnum);
SSVAL(params,2,fmode);
put_dos_date2(params,4, mtime);
@@ -298,12 +293,12 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf,
/****************************************************************************
get a level dependent lanman2 dir entry.
****************************************************************************/
-static int get_lanman2_dir_entry(connection_struct *conn,
+static BOOL get_lanman2_dir_entry(connection_struct *conn,
char *path_mask,int dirtype,int info_level,
int requires_resume_key,
BOOL dont_descend,char **ppdata,
char *base_data, int space_remaining,
- BOOL *out_of_space,
+ BOOL *out_of_space, BOOL *got_exact_match,
int *last_name_off)
{
char *dname;
@@ -329,6 +324,7 @@ static int get_lanman2_dir_entry(connection_struct *conn,
*fname = 0;
*out_of_space = False;
+ *got_exact_match = False;
if (!conn->dirptr)
return(False);
@@ -346,6 +342,8 @@ static int get_lanman2_dir_entry(connection_struct *conn,
while (!found)
{
+ BOOL got_match;
+
/* Needed if we run out of space */
prev_dirpos = TellDir(conn->dirptr);
dname = ReadDirName(conn->dirptr);
@@ -367,7 +365,26 @@ static int get_lanman2_dir_entry(connection_struct *conn,
pstrcpy(fname,dname);
- if(mask_match(fname, mask, case_sensitive, True))
+ if(!(got_match = *got_exact_match = exact_match(fname, mask, case_sensitive)))
+ got_match = mask_match(fname, mask, case_sensitive, True);
+
+ if(!got_match && !is_8_3(fname, False)) {
+
+ /*
+ * It turns out that NT matches wildcards against
+ * both long *and* short names. This may explain some
+ * of the wildcard wierdness from old DOS clients
+ * that some people have been seeing.... JRA.
+ */
+
+ pstring newname;
+ pstrcpy( newname, fname);
+ name_map_mangle( newname, True, False, SNUM(conn));
+ if(!(got_match = *got_exact_match = exact_match(newname, mask, case_sensitive)))
+ got_match = mask_match(newname, mask, case_sensitive, True);
+ }
+
+ if(got_match)
{
BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
if (dont_descend && !isdots)
@@ -380,7 +397,7 @@ static int get_lanman2_dir_entry(connection_struct *conn,
if(needslash)
pstrcat(pathreal,"/");
pstrcat(pathreal,dname);
- if (conn->vfs_ops.stat(dos_to_unix(pathreal,False),&sbuf) != 0)
+ if (dos_stat(pathreal,&sbuf) != 0)
{
DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",pathreal,strerror(errno)));
continue;
@@ -406,7 +423,7 @@ static int get_lanman2_dir_entry(connection_struct *conn,
}
}
- name_map_mangle(fname,False,SNUM(conn));
+ name_map_mangle(fname,False,True,SNUM(conn));
p = pdata;
nameptr = p;
@@ -502,7 +519,7 @@ static int get_lanman2_dir_entry(connection_struct *conn,
SIVAL(p,0,0); p += 4;
if (!was_8_3) {
pstrcpy(p+2,fname);
- if (!name_map_mangle(p+2,True,SNUM(conn)))
+ if (!name_map_mangle(p+2,True,True,SNUM(conn)))
(p+2)[12] = 0;
} else
*(p+2) = 0;
@@ -579,6 +596,7 @@ static int get_lanman2_dir_entry(connection_struct *conn,
*last_name_off = PTR_DIFF(nameptr,base_data);
/* Advance the data pointer to the next slot */
*ppdata = p;
+
return(found);
}
@@ -610,8 +628,9 @@ void mask_convert( char *mask)
}
/****************************************************************************
- reply to a TRANS2_FINDFIRST
+ Reply to a TRANS2_FINDFIRST.
****************************************************************************/
+
static int call_trans2findfirst(connection_struct *conn,
char *inbuf, char *outbuf, int bufsize,
char **pparams, char **ppdata)
@@ -669,11 +688,7 @@ static int call_trans2findfirst(connection_struct *conn,
DEBUG(5,("path=%s\n",directory));
- if (!unix_dfs_convert(directory,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(directory,conn,0,&bad_path,NULL);
if(!check_name(directory,conn)) {
if((errno == ENOENT) && bad_path)
{
@@ -708,40 +723,25 @@ static int call_trans2findfirst(connection_struct *conn,
pdata = *ppdata = Realloc(*ppdata, max_data_bytes + 1024);
if(!*ppdata)
return(ERROR(ERRDOS,ERRnomem));
- bzero(pdata,max_data_bytes);
+ memset((char *)pdata,'\0',max_data_bytes + 1024);
/* Realloc the params space */
params = *pparams = Realloc(*pparams, 10);
if(params == NULL)
return(ERROR(ERRDOS,ERRnomem));
- dptr_num = dptr_create(conn,directory, True ,SVAL(inbuf,smb_pid));
+ dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid));
if (dptr_num < 0)
return(UNIXERROR(ERRDOS,ERRbadfile));
/* Convert the formatted mask. */
mask_convert(mask);
-#if 0 /* JRA */
- /*
- * Now we have a working mask_match in util.c, I believe
- * we no longer need these hacks (in fact they break
- * things). JRA.
- */
-
- /* a special case for 16 bit apps */
- if (strequal(mask,"????????.???")) pstrcpy(mask,"*");
-
- /* handle broken clients that send us old 8.3 format */
- string_sub(mask,"????????","*");
- string_sub(mask,".???",".*");
-#endif /* JRA */
-
/* Save the wildcard match and attribs we are using on this directory -
needed as lanman2 assumes these are being saved between calls */
if(!(wcard = strdup(mask))) {
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
return(ERROR(ERRDOS,ERRnomem));
}
@@ -763,39 +763,49 @@ static int call_trans2findfirst(connection_struct *conn,
out_of_space = False;
for (i=0;(i<maxentries) && !finished && !out_of_space;i++)
+ {
+ BOOL got_exact_match;
+
+ /* this is a heuristic to avoid seeking the dirptr except when
+ absolutely necessary. It allows for a filename of about 40 chars */
+ if (space_remaining < DIRLEN_GUESS && numentries > 0)
{
+ out_of_space = True;
+ finished = False;
+ }
+ else
+ {
+ finished = !get_lanman2_dir_entry(conn,mask,dirtype,info_level,
+ requires_resume_key,dont_descend,
+ &p,pdata,space_remaining, &out_of_space, &got_exact_match,
+ &last_name_off);
+ }
- /* this is a heuristic to avoid seeking the dirptr except when
- absolutely necessary. It allows for a filename of about 40 chars */
- if (space_remaining < DIRLEN_GUESS && numentries > 0)
- {
- out_of_space = True;
- finished = False;
- }
- else
- {
- finished =
- !get_lanman2_dir_entry(conn,mask,dirtype,info_level,
- requires_resume_key,dont_descend,
- &p,pdata,space_remaining, &out_of_space,
- &last_name_off);
- }
+ if (finished && out_of_space)
+ finished = False;
- if (finished && out_of_space)
- finished = False;
+ if (!finished && !out_of_space)
+ numentries++;
- if (!finished && !out_of_space)
- numentries++;
- space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
- }
+ /*
+ * As an optimisation if we know we aren't looking
+ * for a wildcard name (ie. the name matches the wildcard exactly)
+ * then we can finish on any (first) match.
+ * This speeds up large directory searches. JRA.
+ */
+
+ if(got_exact_match)
+ finished = True;
+
+ space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
+ }
/* Check if we can close the dirptr */
if(close_after_first || (finished && close_if_end))
- {
- dptr_close(dptr_num);
- DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
- dptr_num = -1;
- }
+ {
+ DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
+ dptr_close(&dptr_num);
+ }
/*
* If there are no matching entries we must return ERRDOS/ERRbadfile -
@@ -803,7 +813,10 @@ static int call_trans2findfirst(connection_struct *conn,
*/
if(numentries == 0)
+ {
+ dptr_close(&dptr_num);
return(ERROR(ERRDOS,ERRbadfile));
+ }
/* At this point pdata points to numentries directory entries. */
@@ -823,6 +836,17 @@ static int call_trans2findfirst(connection_struct *conn,
smb_fn_name(CVAL(inbuf,smb_com)),
mask, directory, dirtype, numentries ) );
+ /*
+ * Force a name mangle here to ensure that the
+ * mask as an 8.3 name is top of the mangled cache.
+ * The reasons for this are subtle. Don't remove
+ * this code unless you know what you are doing
+ * (see PR#13758). JRA.
+ */
+
+ if(!is_8_3( mask, False))
+ name_map_mangle(mask, True, True, SNUM(conn));
+
return(-1);
}
@@ -843,7 +867,7 @@ static int call_trans2findnext(connection_struct *conn,
int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
char *params = *pparams;
char *pdata = *ppdata;
- int16 dptr_num = SVAL(params,0);
+ int dptr_num = SVAL(params,0);
int maxentries = SVAL(params,2);
uint16 info_level = SVAL(params,4);
uint32 resume_key = IVAL(params,6);
@@ -891,7 +915,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
pdata = *ppdata = Realloc( *ppdata, max_data_bytes + 1024);
if(!*ppdata)
return(ERROR(ERRDOS,ERRnomem));
- bzero(pdata,max_data_bytes);
+ memset((char *)pdata,'\0',max_data_bytes + 1024);
/* Realloc the params space */
params = *pparams = Realloc(*pparams, 6*SIZEOFWORD);
@@ -968,7 +992,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
*/
if(dname != NULL)
- name_map_mangle( dname, False, SNUM(conn));
+ name_map_mangle( dname, False, True, SNUM(conn));
if(dname && strcsequal( resume_name, dname))
{
@@ -996,7 +1020,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
*/
if(dname != NULL)
- name_map_mangle( dname, False, SNUM(conn));
+ name_map_mangle( dname, False, True, SNUM(conn));
if(dname && strcsequal( resume_name, dname))
{
@@ -1009,38 +1033,49 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
} /* end if requires_resume_key && !continue_bit */
for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++)
+ {
+ BOOL got_exact_match;
+
+ /* this is a heuristic to avoid seeking the dirptr except when
+ absolutely necessary. It allows for a filename of about 40 chars */
+ if (space_remaining < DIRLEN_GUESS && numentries > 0)
{
- /* this is a heuristic to avoid seeking the dirptr except when
- absolutely necessary. It allows for a filename of about 40 chars */
- if (space_remaining < DIRLEN_GUESS && numentries > 0)
- {
- out_of_space = True;
- finished = False;
- }
- else
- {
- finished =
- !get_lanman2_dir_entry(conn,mask,dirtype,info_level,
- requires_resume_key,dont_descend,
- &p,pdata,space_remaining, &out_of_space,
- &last_name_off);
- }
+ out_of_space = True;
+ finished = False;
+ }
+ else
+ {
+ finished = !get_lanman2_dir_entry(conn,mask,dirtype,info_level,
+ requires_resume_key,dont_descend,
+ &p,pdata,space_remaining, &out_of_space, &got_exact_match,
+ &last_name_off);
+ }
- if (finished && out_of_space)
- finished = False;
+ if (finished && out_of_space)
+ finished = False;
- if (!finished && !out_of_space)
- numentries++;
- space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
- }
+ if (!finished && !out_of_space)
+ numentries++;
+
+ /*
+ * As an optimisation if we know we aren't looking
+ * for a wildcard name (ie. the name matches the wildcard exactly)
+ * then we can finish on any (first) match.
+ * This speeds up large directory searches. JRA.
+ */
+
+ if(got_exact_match)
+ finished = True;
+
+ space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
+ }
/* Check if we can close the dirptr */
if(close_after_request || (finished && close_if_end))
- {
- dptr_close(dptr_num); /* This frees up the saved mask */
- DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
- dptr_num = -1;
- }
+ {
+ DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
+ dptr_close(&dptr_num); /* This frees up the saved mask */
+ }
/* Set up the return parameter block */
@@ -1070,6 +1105,7 @@ static int call_trans2qfsinfo(connection_struct *conn,
int length, int bufsize,
char **pparams, char **ppdata)
{
+ int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
char *pdata = *ppdata;
char *params = *pparams;
uint16 info_level = SVAL(params,0);
@@ -1078,16 +1114,16 @@ static int call_trans2qfsinfo(connection_struct *conn,
char *vname = volume_label(SNUM(conn));
int snum = SNUM(conn);
char *fstype = lp_fstype(SNUM(conn));
- extern uint32 global_client_caps;
DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
- if(conn->vfs_ops.stat(".",&st)!=0) {
+ if(dos_stat(".",&st)!=0) {
DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
return (ERROR(ERRSRV,ERRinvdevice));
}
- pdata = *ppdata = Realloc(*ppdata, 1024); bzero(pdata,1024);
+ pdata = *ppdata = Realloc(*ppdata, max_data_bytes + 1024);
+ memset((char *)pdata,'\0',max_data_bytes + 1024);
switch (info_level)
{
@@ -1095,7 +1131,7 @@ static int call_trans2qfsinfo(connection_struct *conn,
{
SMB_BIG_UINT dfree,dsize,bsize;
data_len = 18;
- conn->vfs_ops.disk_free(".",&bsize,&dfree,&dsize);
+ sys_disk_free(".",False,&bsize,&dfree,&dsize);
SIVAL(pdata,l1_idFileSystem,st.st_dev);
SIVAL(pdata,l1_cSectorUnit,bsize/512);
SIVAL(pdata,l1_cUnit,dsize);
@@ -1124,16 +1160,21 @@ static int call_trans2qfsinfo(connection_struct *conn,
break;
}
case SMB_QUERY_FS_ATTRIBUTE_INFO:
- data_len = 12 + 2*strlen(fstype);
- SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH); /* FS ATTRIBUTES */
+ {
+ int fstype_len;
+ SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
+ lp_nt_acl_support() ? FILE_PERSISTENT_ACLS : 0); /* FS ATTRIBUTES */
#if 0 /* Old code. JRA. */
SIVAL(pdata,0,0x4006); /* FS ATTRIBUTES == long filenames supported? */
#endif /* Old code. */
+
SIVAL(pdata,4,128); /* Max filename component length */
- SIVAL(pdata,8,2*strlen(fstype));
- ascii_to_unibuf(pdata+12, fstype, 1024-2-12);
+ fstype_len = dos_PutUniCode(pdata+12,unix_to_dos(fstype,False),sizeof(pstring)/2);
+ SIVAL(pdata,8,fstype_len);
+ data_len = 12 + fstype_len;
SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS);
break;
+ }
case SMB_QUERY_FS_LABEL_INFO:
data_len = 4 + strlen(vname);
SIVAL(pdata,0,strlen(vname));
@@ -1158,19 +1199,19 @@ static int call_trans2qfsinfo(connection_struct *conn,
} else {
data_len = 18 + 2*strlen(vname);
SIVAL(pdata,12,strlen(vname)*2);
- ascii_to_unibuf(pdata+18, vname, 1024-2-18);
+ dos_PutUniCode(pdata+18,unix_to_dos(vname,False),sizeof(pstring)/2);
}
DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n",
- strlen(vname),vname));
+ (int)strlen(vname),vname));
break;
case SMB_QUERY_FS_SIZE_INFO:
{
SMB_BIG_UINT dfree,dsize,bsize;
data_len = 24;
- conn->vfs_ops.disk_free(".",&bsize,&dfree,&dsize);
- SIVAL(pdata,0,dsize);
- SIVAL(pdata,8,dfree);
+ sys_disk_free(".",False,&bsize,&dfree,&dsize);
+ SBIG_UINT(pdata,0,dsize);
+ SBIG_UINT(pdata,8,dfree);
SIVAL(pdata,16,bsize/512);
SIVAL(pdata,20,512);
break;
@@ -1236,6 +1277,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
char **pparams,char **ppdata,
int total_data)
{
+ int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
char *params = *pparams;
char *pdata = *ppdata;
uint16 tran_call = SVAL(inbuf, smb_setup0);
@@ -1256,20 +1298,17 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
files_struct *fsp = file_fsp(params,0);
info_level = SVAL(params,2);
- if(fsp && fsp->open && fsp->is_directory) {
+ DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
+
+ if(fsp && fsp->open && (fsp->is_directory || fsp->stat_open)) {
/*
* This is actually a QFILEINFO on a directory
* handle (returned from an NT SMB). NT5.0 seems
* to do this call. JRA.
*/
fname = fsp->fsp_name;
- if (!unix_dfs_convert(fname,conn,0,&bad_path,&sbuf))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
- if (!check_name(fname,conn) || (!VALID_STAT(sbuf) &&
- conn->vfs_ops.stat(dos_to_unix(fname,False),&sbuf))) {
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (!check_name(fname,conn) || (!VALID_STAT(sbuf) && dos_stat(fname,&sbuf))) {
DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
if((errno == ENOENT) && bad_path)
{
@@ -1278,6 +1317,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
}
return(UNIXERROR(ERRDOS,ERRbadpath));
}
+
+ delete_pending = fsp->directory_delete_on_close;
+
} else {
/*
* Original code - this is an open file.
@@ -1286,11 +1328,11 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
CHECK_ERROR(fsp);
fname = fsp->fsp_name;
- if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ if (sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno)));
return(UNIXERROR(ERRDOS,ERRbadfid));
}
- if((pos = fsp->conn->vfs_ops.lseek(fsp->fd_ptr->fd,0,SEEK_CUR)) == -1)
+ if((pos = sys_lseek(fsp->fd_ptr->fd,0,SEEK_CUR)) == -1)
return(UNIXERROR(ERRDOS,ERRnoaccess));
delete_pending = fsp->fd_ptr->delete_on_close;
@@ -1298,16 +1340,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
} else {
/* qpathinfo */
info_level = SVAL(params,0);
+
+ DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
+
fname = &fname1[0];
pstrcpy(fname,&params[6]);
- if (!unix_dfs_convert(fname,conn,0,&bad_path,&sbuf))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
- if (!check_name(fname,conn) ||
- (!VALID_STAT(sbuf) && conn->vfs_ops.stat(dos_to_unix(fname,False),
- &sbuf))) {
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (!check_name(fname,conn) || (!VALID_STAT(sbuf) && dos_stat(fname,&sbuf))) {
DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
if((errno == ENOENT) && bad_path)
{
@@ -1335,8 +1374,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
/* from now on we only want the part after the / */
fname = p;
- params = *pparams = Realloc(*pparams,2); bzero(params,2);
- data_size = 1024;
+ params = *pparams = Realloc(*pparams,2);
+ memset((char *)params,'\0',2);
+ data_size = max_data_bytes + 1024;
pdata = *ppdata = Realloc(*ppdata, data_size);
if (total_data > 0 && IVAL(pdata,0) == total_data) {
@@ -1345,7 +1385,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
}
- bzero(pdata,data_size);
+ memset((char *)pdata,'\0',data_size);
switch (info_level)
{
@@ -1416,26 +1456,37 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
case SMB_QUERY_FILE_ALT_NAME_INFO:
{
pstring short_name;
- char *data_end;
-
pstrcpy(short_name,p);
/* Mangle if not already 8.3 */
if(!is_8_3(short_name, True))
{
- if(!name_map_mangle(short_name,True,SNUM(conn)))
+ if(!name_map_mangle(short_name,True,True,SNUM(conn)))
*short_name = '\0';
}
strupper(short_name);
- data_end = ascii_to_unibuf(pdata + 4, short_name, 1024-2-4);
- data_size = data_end - pdata;
- SIVAL(pdata,0,2*(data_size-4));
+ l = strlen(short_name);
+ dos_PutUniCode(pdata + 4, unix_to_dos(short_name,False),sizeof(pstring)*2);
+ data_size = 4 + (2*l);
+ SIVAL(pdata,0,2*l);
}
break;
case SMB_QUERY_FILE_NAME_INFO:
+ /*
+ * The first part of this code is essential
+ * to get security descriptors to work on mapped
+ * drives. Don't ask how I discovered this unless
+ * you like hearing about me suffering.... :-). JRA.
+ */
+ if(strequal(".", fname) && (global_client_caps & CAP_UNICODE)) {
+ l = l*2;
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS);
+ dos_PutUniCode(pdata + 4, unix_to_dos("\\",False),sizeof(pstring)*2);
+ } else {
+ pstrcpy(pdata+4,fname);
+ }
data_size = 4 + l;
SIVAL(pdata,0,l);
- pstrcpy(pdata+4,fname);
break;
case SMB_QUERY_FILE_ALLOCATION_INFO:
@@ -1527,20 +1578,15 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
fsp = file_fsp(params,0);
info_level = SVAL(params,2);
- if(fsp && fsp->open && fsp->is_directory) {
+ if(fsp && fsp->open && (fsp->is_directory || fsp->stat_open)) {
/*
* This is actually a SETFILEINFO on a directory
* handle (returned from an NT SMB). NT5.0 seems
* to do this call. JRA.
*/
fname = fsp->fsp_name;
- if (!unix_dfs_convert(fname,conn,0,&bad_path,&st))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
- if (!check_name(fname,conn) || (!VALID_STAT(st) &&
- conn->vfs_ops.stat(dos_to_unix(fname,False),&st))) {
+ unix_convert(fname,conn,0,&bad_path,&st);
+ if (!check_name(fname,conn) || (!VALID_STAT(st) && dos_stat(fname,&st))) {
DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
if((errno == ENOENT) && bad_path)
{
@@ -1559,7 +1605,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
fname = fsp->fsp_name;
fd = fsp->fd_ptr->fd;
- if (fsp->conn->vfs_ops.fstat(fd,&st) != 0) {
+ if (sys_fstat(fd,&st) != 0) {
DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno)));
return(UNIXERROR(ERRDOS,ERRbadfid));
}
@@ -1569,11 +1615,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
info_level = SVAL(params,0);
fname = fname1;
pstrcpy(fname,&params[6]);
- if (!unix_dfs_convert(fname,conn,0,&bad_path,&st))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(fname,conn,0,&bad_path,&st);
if(!check_name(fname, conn))
{
if((errno == ENOENT) && bad_path)
@@ -1584,7 +1626,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
return(UNIXERROR(ERRDOS,ERRbadpath));
}
- if(!VALID_STAT(st) && conn->vfs_ops.stat(dos_to_unix(fname,False),&st)!=0) {
+ if(!VALID_STAT(st) && dos_stat(fname,&st)!=0) {
DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
if((errno == ENOENT) && bad_path)
{
@@ -1599,10 +1641,12 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
tran_call,fname,info_level,total_data));
/* Realloc the parameter and data sizes */
- params = *pparams = Realloc(*pparams,2); SSVAL(params,0,0);
+ params = *pparams = Realloc(*pparams,2);
if(params == NULL)
return(ERROR(ERRDOS,ERRnomem));
+ SSVAL(params,0,0);
+
size = st.st_size;
tvs.modtime = st.st_mtime;
tvs.actime = st.st_atime;
@@ -1656,7 +1700,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
tvs.actime = interpret_long_date(pdata+8);
/* write time + changed time, combined. */
- tvs.modtime=MAX(interpret_long_date(pdata+16),
+ tvs.modtime=MIN(interpret_long_date(pdata+16),
interpret_long_date(pdata+24));
#if 0 /* Needs more testing... */
@@ -1672,6 +1716,26 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
break;
}
+ /*
+ * NT seems to use this call with a size of zero
+ * to mean truncate the file. JRA.
+ */
+
+ case SMB_SET_FILE_ALLOCATION_INFO:
+ {
+ SMB_OFF_T newsize = IVAL(pdata,0);
+#ifdef LARGE_SMB_OFF_T
+ newsize |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
+#else /* LARGE_SMB_OFF_T */
+ if (IVAL(pdata,4) != 0) /* more than 32 bits? */
+ return(ERROR(ERRDOS,ERRunknownlevel));
+#endif /* LARGE_SMB_OFF_T */
+ DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n", fname, (double)newsize ));
+ if(newsize == 0)
+ size = 0;
+ break;
+ }
+
case SMB_SET_FILE_END_OF_FILE_INFO:
{
size = IVAL(pdata,0);
@@ -1681,12 +1745,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
if (IVAL(pdata,4) != 0) /* more than 32 bits? */
return(ERROR(ERRDOS,ERRunknownlevel));
#endif /* LARGE_SMB_OFF_T */
+ DEBUG(10,("call_trans2setfilepathinfo: Set end of file info for file %s to %.0f\n", fname, (double)size ));
break;
}
- case SMB_SET_FILE_ALLOCATION_INFO:
- break; /* We don't need to do anything for this call. */
-
case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
{
if ((tran_call == TRANSACT2_SETFILEINFO) && (fsp != NULL))
@@ -1694,121 +1756,134 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
BOOL delete_on_close = (CVAL(pdata,0) ? True : False);
if(fsp->is_directory)
- return(ERROR(ERRDOS,ERRnoaccess));
-
- /*
- * We can only set the delete on close flag if
- * the share mode contained ALLOW_SHARE_DELETE
- */
+ {
+ fsp->directory_delete_on_close = delete_on_close;
+ DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, directory %s\n",
+ delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
- if(lp_share_modes(SNUM(conn)))
+ }
+ else if(fsp->stat_open)
+ {
+ DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, stat open %s\n",
+ delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+ }
+ else
{
- if(!GET_ALLOW_SHARE_DELETE(fsp->share_mode))
- return(ERROR(ERRDOS,ERRnoaccess));
/*
- * If the flag has been set then
- * modify the share mode entry for all files we have open
- * on this device and inode to tell other smbds we have
- * changed the delete on close flag.
+ * We can only set the delete on close flag if
+ * the share mode contained ALLOW_SHARE_DELETE
*/
- if(delete_on_close && !GET_DELETE_ON_CLOSE_FLAG(fsp->share_mode))
+ if(lp_share_modes(SNUM(conn)))
{
- int token;
- int i;
- files_struct *iterate_fsp;
- SMB_DEV_T dev = fsp->fd_ptr->dev;
- SMB_INO_T inode = fsp->fd_ptr->inode;
- int num_share_modes;
- share_mode_entry *current_shares = NULL;
-
- if(lock_share_entry(fsp->conn, dev, inode, &token) == False)
+ if(!GET_ALLOW_SHARE_DELETE(fsp->share_mode))
return(ERROR(ERRDOS,ERRnoaccess));
/*
- * Before we allow this we need to ensure that all current opens
- * on the file have the GET_ALLOW_SHARE_DELETE flag set. If they
- * do not then we deny this (as we are essentially deleting the
- * file at this point.
+ * If the flag has been set then
+ * modify the share mode entry for all files we have open
+ * on this device and inode to tell other smbds we have
+ * changed the delete on close flag.
*/
- num_share_modes = get_share_modes(conn, token, dev, inode, &current_shares);
- for(i = 0; i < num_share_modes; i++)
+ if(delete_on_close && !GET_DELETE_ON_CLOSE_FLAG(fsp->share_mode))
{
- if(!GET_ALLOW_SHARE_DELETE(current_shares[i].share_mode))
+ int token;
+ int i;
+ files_struct *iterate_fsp;
+ SMB_DEV_T dev = fsp->fd_ptr->dev;
+ SMB_INO_T inode = fsp->fd_ptr->inode;
+ int num_share_modes;
+ share_mode_entry *current_shares = NULL;
+
+ if(lock_share_entry(fsp->conn, dev, inode, &token) == False)
+ return(ERROR(ERRDOS,ERRnoaccess));
+
+ /*
+ * Before we allow this we need to ensure that all current opens
+ * on the file have the GET_ALLOW_SHARE_DELETE flag set. If they
+ * do not then we deny this (as we are essentially deleting the
+ * file at this point.
+ */
+
+ num_share_modes = get_share_modes(conn, token, dev, inode, &current_shares);
+ for(i = 0; i < num_share_modes; i++)
{
- DEBUG(5,("call_trans2setfilepathinfo: refusing to set delete on close flag for fnum = %d, \
+ if(!GET_ALLOW_SHARE_DELETE(current_shares[i].share_mode))
+ {
+ DEBUG(5,("call_trans2setfilepathinfo: refusing to set delete on close flag for fnum = %d, \
file %s as a share exists that was not opened with FILE_DELETE access.\n",
- fsp->fnum, fsp->fsp_name ));
- /*
- * Release the lock.
- */
+ fsp->fnum, fsp->fsp_name ));
+ /*
+ * Release the lock.
+ */
- unlock_share_entry(fsp->conn, dev, inode, token);
+ unlock_share_entry(fsp->conn, dev, inode, token);
- /*
- * current_shares was malloced by get_share_modes - free it here.
- */
+ /*
+ * current_shares was malloced by get_share_modes - free it here.
+ */
- free((char *)current_shares);
+ free((char *)current_shares);
- /*
- * Even though share violation would be more appropriate here,
- * return ERRnoaccess as that's what NT does.
- */
+ /*
+ * Even though share violation would be more appropriate here,
+ * return ERRnoaccess as that's what NT does.
+ */
- return(ERROR(ERRDOS,ERRnoaccess));
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
}
- }
- /*
- * current_shares was malloced by get_share_modes - free it here.
- */
+ /*
+ * current_shares was malloced by get_share_modes - free it here.
+ */
- free((char *)current_shares);
+ free((char *)current_shares);
- DEBUG(10,("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n",
- delete_on_close ? "Adding" : "Removing", fsp->fnum, fsp->fsp_name ));
+ DEBUG(10,("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n",
+ delete_on_close ? "Adding" : "Removing", fsp->fnum, fsp->fsp_name ));
- /*
- * Go through all files we have open on the same device and
- * inode (hanging off the same hash bucket) and set the DELETE_ON_CLOSE_FLAG.
- * Other smbd's that have this file open will have to fend for themselves. We
- * take care of this (rare) case in close_file(). See the comment there.
- */
+ /*
+ * Go through all files we have open on the same device and
+ * inode (hanging off the same hash bucket) and set the DELETE_ON_CLOSE_FLAG.
+ * Other smbd's that have this file open will have to fend for themselves. We
+ * take care of this (rare) case in close_file(). See the comment there.
+ */
- for(iterate_fsp = file_find_di_first(dev, inode); iterate_fsp;
- iterate_fsp = file_find_di_next(iterate_fsp))
- {
- int new_share_mode = (delete_on_close ?
- (iterate_fsp->share_mode | DELETE_ON_CLOSE_FLAG) :
- (iterate_fsp->share_mode & ~DELETE_ON_CLOSE_FLAG) );
+ for(iterate_fsp = file_find_di_first(dev, inode); iterate_fsp;
+ iterate_fsp = file_find_di_next(iterate_fsp))
+ {
+ int new_share_mode = (delete_on_close ?
+ (iterate_fsp->share_mode | DELETE_ON_CLOSE_FLAG) :
+ (iterate_fsp->share_mode & ~DELETE_ON_CLOSE_FLAG) );
- DEBUG(10,("call_trans2setfilepathinfo: Changing share mode for fnum %d, file %s \
+ DEBUG(10,("call_trans2setfilepathinfo: Changing share mode for fnum %d, file %s \
dev = %x, inode = %.0f from %x to %x\n",
- iterate_fsp->fnum, iterate_fsp->fsp_name, (unsigned int)dev,
- (double)inode, iterate_fsp->share_mode, new_share_mode ));
+ iterate_fsp->fnum, iterate_fsp->fsp_name, (unsigned int)dev,
+ (double)inode, iterate_fsp->share_mode, new_share_mode ));
- if(modify_share_mode(token, iterate_fsp, new_share_mode)==False)
- DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close for fnum %d, \
+ if(modify_share_mode(token, iterate_fsp, new_share_mode, iterate_fsp->oplock_type)==False)
+ DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close for fnum %d, \
dev = %x, inode = %.0f\n", iterate_fsp->fnum, (unsigned int)dev, (double)inode));
- }
+ }
- /*
- * Set the delete on close flag in the reference
- * counted struct. Delete when the last reference
- * goes away.
- */
- fsp->fd_ptr->delete_on_close = delete_on_close;
- unlock_share_entry(fsp->conn, dev, inode, token);
+ /*
+ * Set the delete on close flag in the reference
+ * counted struct. Delete when the last reference
+ * goes away.
+ */
+ fsp->fd_ptr->delete_on_close = delete_on_close;
- DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n",
- delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+ unlock_share_entry(fsp->conn, dev, inode, token);
- } /* end if(delete_on_close && !GET_DELETE_ON_CLOSE_FLAG(fsp->share_mode)) */
- } /* end if lp_share_modes() */
+ DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n",
+ delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+ } /* end if(delete_on_close && !GET_DELETE_ON_CLOSE_FLAG(fsp->share_mode)) */
+ } /* end if lp_share_modes() */
+ } /* end if is_directory. */
} else
return(ERROR(ERRDOS,ERRunknownlevel));
break;
@@ -1820,23 +1895,33 @@ dev = %x, inode = %.0f\n", iterate_fsp->fnum, (unsigned int)dev, (double)inode))
}
}
+ /* get some defaults (no modifications) if any info is zero or -1. */
+ if (tvs.actime == (time_t)0 || tvs.actime == (time_t)-1)
+ tvs.actime = st.st_atime;
+
+ if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1)
+ tvs.modtime = st.st_mtime;
+
DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
DEBUG(6,("size: %.0f ", (double)size));
DEBUG(6,("mode: %x\n" , mode));
- /* get some defaults (no modifications) if any info is zero. */
- if (!tvs.actime) tvs.actime = st.st_atime;
- if (!tvs.modtime) tvs.modtime = st.st_mtime;
- if (!size) size = st.st_size;
+ if(!((info_level == SMB_SET_FILE_END_OF_FILE_INFO) ||
+ (info_level == SMB_SET_FILE_ALLOCATION_INFO))) {
+ /*
+ * Only do this test if we are not explicitly
+ * changing the size of a file.
+ */
+ if (!size)
+ size = st.st_size;
+ }
/* Try and set the times, size and mode of this file -
if they are different from the current values
*/
- if (st.st_mtime != tvs.modtime || st.st_atime != tvs.actime)
- {
- if(fsp != NULL)
- {
+ if (st.st_mtime != tvs.modtime || st.st_atime != tvs.actime) {
+ if(fsp != NULL) {
/*
* This was a setfileinfo on an open file.
* NT does this a lot. It's actually pointless
@@ -1844,38 +1929,51 @@ dev = %x, inode = %.0f\n", iterate_fsp->fnum, (unsigned int)dev, (double)inode))
* on the next write, so we save the request
* away and will set it on file code. JRA.
*/
- fsp->pending_modtime = tvs.modtime;
- }
- else if(file_utime(conn, fname, &tvs)!=0)
- {
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) {
+ DEBUG(10,("call_trans2setfilepathinfo: setting pending modtime to %s\n",
+ ctime(&tvs.modtime) ));
+ fsp->pending_modtime = tvs.modtime;
+ }
+
+ } else {
+
+ DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n"));
+
+ if(file_utime(conn, fname, &tvs)!=0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
}
}
/* check the mode isn't different, before changing it */
- if (mode != dos_mode(conn, fname, &st) && file_chmod(conn, fname, mode, NULL))
- {
- DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ if ((mode != 0) && (mode != dos_mode(conn, fname, &st))) {
+
+ DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n",
+ fname, mode ));
+
+ if(file_chmod(conn, fname, mode, NULL)) {
+ DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
}
- if(size != st.st_size)
- {
- if (fd == -1)
- {
-DEBUG(0, ("@@@ 23 @@@\n"));
+ if(size != st.st_size) {
+
+ DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new size to %.0f\n",
+ fname, (double)size ));
+
+ if (fd == -1) {
fd = dos_open(fname,O_RDWR,0);
if (fd == -1)
- {
return(UNIXERROR(ERRDOS,ERRbadpath));
- }
set_filelen(fd, size);
close(fd);
- }
- else
- {
+ } else {
set_filelen(fd, size);
}
+
+ if(fsp)
+ set_filelen_write_cache(fsp, size);
}
SSVAL(params,0,0);
@@ -1904,14 +2002,9 @@ static int call_trans2mkdir(connection_struct *conn,
DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
- if (!unix_dfs_convert(directory,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ unix_convert(directory,conn,0,&bad_path,NULL);
if (check_name(directory,conn))
- ret = conn->vfs_ops.mkdir(dos_to_unix(directory,False),
- unix_mode(conn,aDIR));
+ ret = dos_mkdir(directory,unix_mode(conn,aDIR));
if(ret < 0)
{
@@ -2012,11 +2105,11 @@ int reply_findclose(connection_struct *conn,
char *inbuf,char *outbuf,int length,int bufsize)
{
int outsize = 0;
- int16 dptr_num=SVALS(inbuf,smb_vwv0);
+ int dptr_num=SVALS(inbuf,smb_vwv0);
DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
outsize = set_message(outbuf,0,0,True);
@@ -2049,237 +2142,6 @@ int reply_findnclose(connection_struct *conn,
return(outsize);
}
-#define UNICODE_DFS
-
-/****************************************************************************
- reply to a TRANS2_GET_DFS_REFERRAL
- ****************************************************************************/
-static int call_trans2getdfsreferral(connection_struct *conn,
- char *inbuf, char *outbuf, int length,
- int bufsize,
- char **pparams, char **ppdata,
- int total_data)
-{
- char *params = *pparams;
- char *pdata;
- char *pheader;
- char *localstring_offset;
- char *mangledstring_offset;
- char *sharename_offset;
- char *referal_offset;
-
- int i;
- int j;
- unsigned int total_params = SVAL(inbuf, smb_tpscnt);
- int query_file_len=0;
- int bytesreq=0;
- int filename_len;
-
- BOOL first_one=True;
-
- referal_trans_param rtp;
- dfs_internal_table *list=dfs_struct.table;
- dfs_response reply;
-
- DEBUG(0,("call_trans2getdfsreferral:1\n"));
-
- ZERO_STRUCT(rtp);
- ZERO_STRUCT(reply);
-
- /* decode the param member of query */
- rtp.level=SVAL(params, 0);
- DEBUGADD(0,("rtp.level:[%d]\n",rtp.level));
-
- DEBUGADD(0,("total_params:[%d]\n",total_params));
- for (i=0; i<(total_params-2)/2; i++)
- {
- rtp.directory[i]=SVAL(params, 2+2*i);
- }
-/*
- strupper(rtp.directory);
-*/
- query_file_len=strlen(rtp.directory);
- DEBUGADD(0,("rtp.directory:[%s]\n",rtp.directory));
- DEBUGADD(0,("query_file_len:[%d]\n",query_file_len));
-
- /*
- lookup in the internal DFS table all the entries
- and calculate the required data buffer size
- */
- bytesreq=8; /* the header */
- reply.number_of_referal=0;
- DEBUGADD(0,("call_trans2getdfsreferral:2\n"));
-
- for(i=0; i<dfs_struct.size; i++)
- {
- filename_len=list[i].localpath_length;
- DEBUGADD(0,("checking against [%s][%d]\n", list[i].localpath, filename_len));
-
- if( (filename_len==query_file_len) &&
- (!StrnCaseCmp(rtp.directory, list[i].localpath, query_file_len)) )
- {
-
- bytesreq+=22; /* the referal size */
- bytesreq+=2*(list[i].sharename_length+1); /* the string length */
- reply.number_of_referal++;
- DEBUGADD(0,("found\n"));
-
- if (first_one) {
- DEBUGADD(0,("first one\n"));
- bytesreq+=2*(list[i].localpath_length+1);
- bytesreq+=2*(list[i].mangledpath_length+1);
-
- reply.path_consumed=list[i].localpath_length;
-
- strncpy(reply.filename, list[i].localpath, list[i].localpath_length+1);
- strncpy(reply.mangledname, list[i].mangledpath, list[i].mangledpath_length+1);
- rtp.type=list[i].type;
- first_one=False;
- }
- }
- }
- DEBUGADD(0,("call_trans2getdfsreferral:3\n"));
-
- /* allocate memory for the reply data */
- pdata = *ppdata = Realloc(*ppdata, bytesreq + 1024);
- bzero(*ppdata, bytesreq+22);
-
- pdata = *ppdata;
- pheader = pdata;
-
- localstring_offset = pdata + 8 + reply.number_of_referal*22;
-
-#ifdef UNICODE_DFS
- mangledstring_offset = localstring_offset + 2*(1+strlen(reply.filename));
- sharename_offset = mangledstring_offset + 2*(1+strlen(reply.mangledname));
-
-#else
- mangledstring_offset = localstring_offset + (1+strlen(reply.filename));
- sharename_offset = mangledstring_offset + (1+strlen(reply.mangledname));
-#endif
- referal_offset = pdata + 8;
-
- /* right now respond storage server */
-/*
- reply.server_function=rtp.type;
-*/
- reply.server_function=0x3;
-
- /* write the header */
-#ifdef UNICODE_DFS
- SSVAL(pheader, 0, reply.path_consumed*2);
-#else
- SSVAL(pheader, 0, reply.path_consumed);
-#endif
- SSVAL(pheader, 2, reply.number_of_referal);
- SIVAL(pheader, 4, reply.server_function);
-
- /* write the local path string */
-#ifdef UNICODE_DFS
- for(i=0; i<strlen(reply.filename); i++)
- {
- SSVAL(localstring_offset, 2*i, (uint16) reply.filename[i]);
- }
- SSVAL(localstring_offset, 2*strlen(reply.filename), 0);
-#else
-
- for(i=0; i<strlen(reply.filename); i++)
- {
- localstring_offset[i]=reply.filename[i];
- }
- localstring_offset[strlen(reply.filename)]=0;
-#endif
- DEBUG(0,("reply.filename is [%s]:[%d], i is [%d]\n", reply.filename, strlen(reply.filename), i));
-
- /* write the mangled local path string */
-#ifdef UNICODE_DFS
- for(i=0; i<strlen(reply.mangledname); i++)
- {
- SSVAL(mangledstring_offset, 2*i, (uint16) reply.mangledname[i]);
- }
- SSVAL(mangledstring_offset, 2*i, 0);
-#else
- for(i=0; i<strlen(reply.mangledname); i++)
- {
- mangledstring_offset[i]=reply.mangledname[i];
- }
- mangledstring_offset[i]=0;
-#endif
- DEBUGADD(0,("call_trans2getdfsreferral:4\n"));
-
- /* the order of the referals defines the load balancing */
-
- /* write each referal */
- for(i=0; i<dfs_struct.size; i++)
- {
- filename_len=list[i].localpath_length;
-
- if(filename_len==query_file_len &&
- !strncasecmp(rtp.directory, list[i].localpath, query_file_len))
- {
-
- SSVAL(referal_offset, 0, 2); /* version */
- SSVAL(referal_offset, 2, 22); /* size */
-
- if (rtp.type==3)
- SSVAL(referal_offset, 4, 1); /* type SMB server*/
- else
- SSVAL(referal_offset, 4, 0); /* type unknown */
- SSVAL(referal_offset, 6, 1); /* flags */
- SIVAL(referal_offset, 8, list[i].proximity); /* proximity */
- SIVAL(referal_offset, 12, 300); /* ttl */
- SSVAL(referal_offset, 16, localstring_offset-referal_offset);
- SSVAL(referal_offset, 18, mangledstring_offset-referal_offset);
- SSVAL(referal_offset, 20, sharename_offset-referal_offset);
-
-#ifdef UNICODE_DFS
- for(j=0; j<list[i].sharename_length; j++)
- {
- SSVAL(sharename_offset, 2*j, (uint16) list[i].sharename[j]);
- }
- SSVAL(sharename_offset, 2*j, 0);
-
- sharename_offset=sharename_offset + 2*(1+list[i].sharename_length);
-#else
- for(j=0; j<list[i].sharename_length; j++)
- {
- sharename_offset[j]=list[i].sharename[j];
- }
- sharename_offset[j]=0;
-
- sharename_offset=sharename_offset + (1+list[i].sharename_length);
-#endif
-
- referal_offset=referal_offset+22;
- }
- }
-
- DEBUGADD(0,("call_trans2getdfsreferral:5\n"));
-
- send_trans2_replies(outbuf, bufsize, params, 0, *ppdata, bytesreq+22);
-
-/* send_trans2_replies(outbuf, bufsize, *ppdata, bytesreq, params, 0);*/
- DEBUGADD(0,("call_trans2getdfsreferral:6\n"));
-
- return(-1);
-}
-
-
-/****************************************************************************
-reply to a TRANS2_REPORT_DFS_INCONSISTANCY
-****************************************************************************/
-static int call_trans2reportdfsinconsistancy(connection_struct *conn,
- char *inbuf, char *outbuf, int length,
- int bufsize,
- char **pparams, char **ppdata)
-{
- char *params = *pparams;
-
- DEBUG(4,("call_trans2reportdfsinconsistancy\n"));
- send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0);
- return(-1);
-}
-
/****************************************************************************
reply to a SMBtranss2 - just ignore it!
@@ -2410,104 +2272,73 @@ int reply_trans2(connection_struct *conn,
}
/* Now we must call the relevant TRANS2 function */
- switch(tran_call)
- {
- case TRANSACT2_OPEN:
- {
- outsize = call_trans2open(conn,
+ switch(tran_call) {
+ case TRANSACT2_OPEN:
+ outsize = call_trans2open(conn,
inbuf, outbuf, bufsize,
&params, &data);
- break;
- }
- case TRANSACT2_FINDFIRST:
- {
- outsize = call_trans2findfirst(conn, inbuf, outbuf,
- bufsize, &params, &data);
- break;
- }
- case TRANSACT2_FINDNEXT:
- {
- outsize = call_trans2findnext(conn, inbuf, outbuf,
- length, bufsize,
- &params, &data);
- break;
- }
- case TRANSACT2_QFSINFO:
- {
- outsize = call_trans2qfsinfo(conn, inbuf, outbuf,
- length, bufsize, &params,
- &data);
- break;
- }
- case TRANSACT2_SETFSINFO:
- {
- outsize = call_trans2setfsinfo(conn, inbuf, outbuf,
- length, bufsize,
- &params, &data);
- break;
- }
- case TRANSACT2_QPATHINFO:
- case TRANSACT2_QFILEINFO:
- {
- outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf,
- length, bufsize,
- &params, &data, total_data);
- break;
- }
- case TRANSACT2_SETPATHINFO:
- case TRANSACT2_SETFILEINFO:
- {
- outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf,
- length, bufsize,
- &params, &data,
- total_data);
- break;
- }
- case TRANSACT2_FINDNOTIFYFIRST:
- {
- outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf,
- length, bufsize,
- &params, &data);
- break;
- }
- case TRANSACT2_FINDNOTIFYNEXT:
- {
- outsize = call_trans2findnotifynext(conn, inbuf, outbuf,
- length, bufsize,
- &params, &data);
- break;
- }
- case TRANSACT2_MKDIR:
- {
- outsize = call_trans2mkdir(conn, inbuf, outbuf, length,
- bufsize, &params, &data);
- break;
- }
- case TRANSACT2_GET_DFS_REFERRAL:
- {
- outsize = call_trans2getdfsreferral(conn, inbuf, outbuf,
- length, bufsize, &params,
- &data, total_data);
- break;
- }
- case TRANSACT2_REPORT_DFS_INCONSISTANCY:
- {
- outsize = call_trans2reportdfsinconsistancy(conn, inbuf, outbuf,
- length, bufsize,
- &params, &data);
- break;
- }
- default:
- {
- /* Error in request */
- DEBUG(2,("Unknown request %d in trans2 call\n",
- tran_call));
- if(params)
- free(params);
- if(data)
- free(data);
- return (ERROR(ERRSRV,ERRerror));
- }
+ break;
+
+ case TRANSACT2_FINDFIRST:
+ outsize = call_trans2findfirst(conn, inbuf, outbuf,
+ bufsize, &params, &data);
+ break;
+
+ case TRANSACT2_FINDNEXT:
+ outsize = call_trans2findnext(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data);
+ break;
+
+ case TRANSACT2_QFSINFO:
+ outsize = call_trans2qfsinfo(conn, inbuf, outbuf,
+ length, bufsize, &params,
+ &data);
+ break;
+
+ case TRANSACT2_SETFSINFO:
+ outsize = call_trans2setfsinfo(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data);
+ break;
+
+ case TRANSACT2_QPATHINFO:
+ case TRANSACT2_QFILEINFO:
+ outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data, total_data);
+ break;
+ case TRANSACT2_SETPATHINFO:
+ case TRANSACT2_SETFILEINFO:
+ outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data,
+ total_data);
+ break;
+
+ case TRANSACT2_FINDNOTIFYFIRST:
+ outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data);
+ break;
+
+ case TRANSACT2_FINDNOTIFYNEXT:
+ outsize = call_trans2findnotifynext(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data);
+ break;
+ case TRANSACT2_MKDIR:
+ outsize = call_trans2mkdir(conn, inbuf, outbuf, length,
+ bufsize, &params, &data);
+ break;
+ default:
+ /* Error in request */
+ DEBUG(2,("Unknown request %d in trans2 call\n", tran_call));
+ if(params)
+ free(params);
+ if(data)
+ free(data);
+ return (ERROR(ERRSRV,ERRerror));
}
/* As we do not know how many data packets will need to be
@@ -2525,4 +2356,3 @@ int reply_trans2(connection_struct *conn,
call_trans2xxx calls have already sent
it. If outsize != -1 then it is returning */
}
-
diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index 3501879d5f..ce0631e418 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -23,53 +23,36 @@
extern int DEBUGLEVEL;
-static uid_t initial_uid;
-static gid_t initial_gid;
-static struct uid_cache vcache;
-
/* what user is current? */
extern struct current_user current_user;
pstring OriginalDir;
/****************************************************************************
-initialise the uid routines
+ Initialise the uid routines.
****************************************************************************/
+
void init_uid(void)
{
- initial_uid = current_user.uid = geteuid();
- initial_gid = current_user.gid = getegid();
-
- if (initial_gid != 0 && initial_uid == 0) {
-#ifdef HAVE_SETRESUID
- setresgid(0,0,0);
-#else
- setgid(0);
- setegid(0);
-#endif
- }
+ current_user.uid = geteuid();
+ current_user.gid = getegid();
- initial_uid = geteuid();
- initial_gid = getegid();
+ if (current_user.gid != 0 && current_user.uid == 0) {
+ gain_root_group_privilege();
+ }
current_user.conn = NULL;
current_user.vuid = UID_FIELD_INVALID;
- vcache.entries = 0;
-
dos_ChDir(OriginalDir);
}
-
/****************************************************************************
- become the specified uid
+ Become the specified uid.
****************************************************************************/
+
static BOOL become_uid(uid_t uid)
{
- if (initial_uid != 0) {
- return(True);
- }
-
if (uid == (uid_t)-1 || ((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) {
static int done;
if (!done) {
@@ -78,98 +61,53 @@ static BOOL become_uid(uid_t uid)
}
}
-#ifdef HAVE_TRAPDOOR_UID
-#ifdef HAVE_SETUIDX
- /* AIX3 has setuidx which is NOT a trapoor function (tridge) */
- if (setuidx(ID_EFFECTIVE, uid) != 0) {
- if (seteuid(uid) != 0) {
- DEBUG(1,("Can't set uid %d (setuidx)\n", (int)uid));
- return False;
- }
- }
-#endif
-#endif
-
-#ifdef HAVE_SETRESUID
- if (setresuid(-1,uid,-1) != 0)
-#else
- if ((seteuid(uid) != 0) &&
- (setuid(uid) != 0))
-#endif
- {
- DEBUG(0,("Couldn't set uid %d currently set to (%d,%d)\n",
- (int)uid,(int)getuid(), (int)geteuid()));
- if (uid > (uid_t)32000) {
- DEBUG(0,("Looks like your OS doesn't like high uid values - try using a different account\n"));
- }
- return(False);
- }
-
- if (((uid == (uid_t)-1) || ((sizeof(uid_t) == 2) && (uid == 65535))) && (geteuid() != uid)) {
- DEBUG(0,("Invalid uid -1. perhaps you have a account with uid 65535?\n"));
- return(False);
- }
+ set_effective_uid(uid);
- current_user.uid = uid;
+ current_user.uid = uid;
#ifdef WITH_PROFILE
- profile_p->uid_changes++;
+ profile_p->uid_changes++;
#endif
- return(True);
+ return(True);
}
/****************************************************************************
- become the specified gid
+ Become the specified gid.
****************************************************************************/
+
static BOOL become_gid(gid_t gid)
{
- if (initial_uid != 0)
- return(True);
-
- if (gid == (gid_t)-1 || ((sizeof(gid_t) == 2) && (gid == (gid_t)65535))) {
- DEBUG(1,("WARNING: using gid %d is a security risk\n",(int)gid));
- }
-
-#ifdef HAVE_SETRESUID
- if (setresgid(-1,gid,-1) != 0)
-#else
- if (setgid(gid) != 0)
-#endif
- {
- DEBUG(0,("Couldn't set gid %d currently set to (%d,%d)\n",
- (int)gid,(int)getgid(),(int)getegid()));
- if (gid > 32000) {
- DEBUG(0,("Looks like your OS doesn't like high gid values - try using a different account\n"));
+ if (gid == (gid_t)-1 || ((sizeof(gid_t) == 2) && (gid == (gid_t)65535))) {
+ DEBUG(1,("WARNING: using gid %d is a security risk\n",(int)gid));
}
- return(False);
- }
-
- current_user.gid = gid;
-
- return(True);
+
+ set_effective_gid(gid);
+
+ current_user.gid = gid;
+
+ return(True);
}
/****************************************************************************
- become the specified uid and gid
+ Become the specified uid and gid.
****************************************************************************/
+
static BOOL become_id(uid_t uid,gid_t gid)
{
return(become_gid(gid) && become_uid(uid));
}
/****************************************************************************
-become the guest user
+ Become the guest user.
****************************************************************************/
+
BOOL become_guest(void)
{
BOOL ret;
- static const struct passwd *pass=NULL;
-
- if (initial_uid != 0)
- return(True);
+ static struct passwd *pass=NULL;
if (!pass)
pass = Get_Pwnam(lp_guestaccount(-1),True);
@@ -193,138 +131,43 @@ BOOL become_guest(void)
}
/*******************************************************************
-check if a username is OK
+ Check if a username is OK.
********************************************************************/
-static BOOL check_vuser_ok(struct uid_cache *cache, user_struct *vuser,int snum)
+
+static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
{
int i;
- for (i=0;i<cache->entries;i++)
- if (cache->list[i] == vuser->uid) return(True);
+ for (i=0;i<conn->uid_cache.entries;i++)
+ if (conn->uid_cache.list[i] == vuser->uid) return(True);
if (!user_ok(vuser->name,snum)) return(False);
- i = cache->entries % UID_CACHE_SIZE;
- cache->list[i] = vuser->uid;
+ i = conn->uid_cache.entries % UID_CACHE_SIZE;
+ conn->uid_cache.list[i] = vuser->uid;
- if (cache->entries < UID_CACHE_SIZE)
- cache->entries++;
+ if (conn->uid_cache.entries < UID_CACHE_SIZE)
+ conn->uid_cache.entries++;
return(True);
}
/****************************************************************************
- become the user of a connection number
-****************************************************************************/
-BOOL become_vuser(uint16 vuid)
-{
- user_struct *vuser = get_valid_user_struct(vuid);
- gid_t gid;
- uid_t uid;
-
- unbecome_vuser();
-
- if((vuser != NULL) && !check_vuser_ok(&vcache, vuser, -1))
- return False;
-
- if ( vuser != 0 &&
- current_user.vuid == vuid &&
- current_user.uid == vuser->uid)
- {
- DEBUG(4,("Skipping become_vuser - already user\n"));
- return(True);
- }
- uid = vuser->uid;
- gid = vuser->gid;
- current_user.ngroups = vuser->n_groups;
- current_user.groups = vuser->groups;
-
- if (initial_uid == 0)
- {
- if (!become_gid(gid)) return(False);
-
-#ifdef HAVE_SETGROUPS
- /* groups stuff added by ih/wreu */
- if (current_user.ngroups > 0)
- {
- if (setgroups(current_user.ngroups,
- current_user.groups)<0) {
- DEBUG(0,("setgroups call failed!\n"));
- }
- }
-#endif
-
- if (!become_uid(uid)) return(False);
- }
-
- current_user.conn = NULL;
- current_user.vuid = vuid;
-
- DEBUG(5,("become_vuser uid=(%d,%d) gid=(%d,%d)\n",
- (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
-
- return(True);
-}
-
-/****************************************************************************
- unbecome a user
+ Become the user of a connection number.
****************************************************************************/
-BOOL unbecome_vuser(void)
-{
- dos_ChDir(OriginalDir);
-
- if (initial_uid == 0)
- {
-#ifdef HAVE_SETRESUID
- setresuid(-1,getuid(),-1);
- setresgid(-1,getgid(),-1);
-#else
- if (seteuid(initial_uid) != 0)
- setuid(initial_uid);
- setgid(initial_gid);
-#endif
- }
-
-#ifdef NO_EID
- if (initial_uid == 0)
- DEBUG(2,("Running with no EID\n"));
- initial_uid = getuid();
- initial_gid = getgid();
-#else
- if (geteuid() != initial_uid) {
- DEBUG(0,("Warning: You appear to have a trapdoor uid system\n"));
- initial_uid = geteuid();
- }
- if (getegid() != initial_gid) {
- DEBUG(0,("Warning: You appear to have a trapdoor gid system\n"));
- initial_gid = getegid();
- }
-#endif
- current_user.uid = initial_uid;
- current_user.gid = initial_gid;
-
- if (dos_ChDir(OriginalDir) != 0)
- DEBUG( 0, ( "chdir(%s) failed in unbecome_vuser\n", OriginalDir ) );
-
- DEBUG(5,("unbecome_vuser now uid=(%d,%d) gid=(%d,%d)\n",
- (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
-
- current_user.conn = NULL;
- current_user.vuid = UID_FIELD_INVALID;
-
- return(True);
-}
-
-/****************************************************************************
- become the user of a connection number
-****************************************************************************/
BOOL become_user(connection_struct *conn, uint16 vuid)
{
user_struct *vuser = get_valid_user_struct(vuid);
int snum;
- gid_t gid;
+ gid_t gid;
uid_t uid;
+ char group_c;
+
+ if (!conn) {
+ DEBUG(2,("Connection not open\n"));
+ return(False);
+ }
/*
* We need a separate check in security=share mode due to vuid
@@ -346,14 +189,9 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
unbecome_user();
- if (!conn) {
- DEBUG(2,("Connection not open\n"));
- return(False);
- }
-
snum = SNUM(conn);
- if((vuser != NULL) && !check_vuser_ok(&conn->uid_cache, vuser, snum))
+ if((vuser != NULL) && !check_user_ok(conn, vuser, snum))
return False;
if (conn->force_user ||
@@ -369,32 +207,55 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
return(False);
}
uid = vuser->uid;
- if(!*lp_force_group(snum)) {
- gid = vuser->gid;
+ gid = vuser->gid;
+ current_user.ngroups = vuser->n_groups;
+ current_user.groups = vuser->groups;
+ }
+
+ /*
+ * See if we should force group for this service.
+ * If so this overrides any group set in the force
+ * user code.
+ */
+
+ if((group_c = *lp_force_group(snum))) {
+ if(group_c == '+') {
+
+ /*
+ * Only force group if the user is a member of
+ * the service group. Check the group memberships for
+ * this user (we already have this) to
+ * see if we should force the group.
+ */
+
+ int i;
+ for (i = 0; i < current_user.ngroups; i++) {
+ if (current_user.groups[i] == conn->gid) {
+ gid = conn->gid;
+ break;
+ }
+ }
} else {
gid = conn->gid;
}
- current_user.ngroups = vuser->n_groups;
- current_user.groups = vuser->groups;
}
- if (initial_uid == 0) {
- if (!become_gid(gid)) return(False);
+ if (!become_gid(gid))
+ return(False);
#ifdef HAVE_SETGROUPS
- if (!(conn && conn->ipc)) {
- /* groups stuff added by ih/wreu */
- if (current_user.ngroups > 0)
- if (setgroups(current_user.ngroups,
- current_user.groups)<0) {
- DEBUG(0,("setgroups call failed!\n"));
- }
- }
+ if (!(conn && conn->ipc)) {
+ /* groups stuff added by ih/wreu */
+ if (current_user.ngroups > 0)
+ if (sys_setgroups(current_user.ngroups,
+ current_user.groups)<0) {
+ DEBUG(0,("sys_setgroups call failed!\n"));
+ }
+ }
#endif
- if (!conn->admin_user && !become_uid(uid))
- return(False);
- }
+ if (!conn->admin_user && !become_uid(uid))
+ return(False);
current_user.conn = conn;
current_user.vuid = vuid;
@@ -406,56 +267,83 @@ BOOL become_user(connection_struct *conn, uint16 vuid)
}
/****************************************************************************
- unbecome the user of a connection number
+ Unbecome the user of a connection number.
****************************************************************************/
+
BOOL unbecome_user(void )
{
- if (!current_user.conn)
- return(False);
-
- dos_ChDir(OriginalDir);
-
- if (initial_uid == 0)
- {
-#ifdef HAVE_SETRESUID
- setresuid(-1,getuid(),-1);
- setresgid(-1,getgid(),-1);
-#else
- if (seteuid(initial_uid) != 0)
- setuid(initial_uid);
- setgid(initial_gid);
-#endif
- }
-
-#ifdef NO_EID
- if (initial_uid == 0)
- DEBUG(2,("Running with no EID\n"));
- initial_uid = getuid();
- initial_gid = getgid();
-#else
- if (geteuid() != initial_uid) {
- DEBUG(0,("Warning: You appear to have a trapdoor uid system\n"));
- initial_uid = geteuid();
- }
- if (getegid() != initial_gid) {
- DEBUG(0,("Warning: You appear to have a trapdoor gid system\n"));
- initial_gid = getegid();
- }
-#endif
+ if (!current_user.conn)
+ return(False);
+
+ dos_ChDir(OriginalDir);
- current_user.uid = initial_uid;
- current_user.gid = initial_gid;
+ set_effective_uid(0);
+ set_effective_gid(0);
+
+ if (geteuid() != 0) {
+ DEBUG(0,("Warning: You appear to have a trapdoor uid system\n"));
+ }
+ if (getegid() != 0) {
+ DEBUG(0,("Warning: You appear to have a trapdoor gid system\n"));
+ }
+
+ current_user.uid = 0;
+ current_user.gid = 0;
- if (dos_ChDir(OriginalDir) != 0)
- DEBUG( 0, ( "chdir(%s) failed in unbecome_user\n", OriginalDir ) );
+ if (dos_ChDir(OriginalDir) != 0)
+ DEBUG( 0, ( "chdir(%s) failed in unbecome_user\n", OriginalDir ) );
- DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n",
- (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
+ DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n",
+ (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
- current_user.conn = NULL;
- current_user.vuid = UID_FIELD_INVALID;
+ current_user.conn = NULL;
+ current_user.vuid = UID_FIELD_INVALID;
- return(True);
+ return(True);
+}
+
+/****************************************************************************
+ Become the user of an authenticated connected named pipe.
+ When this is called we are currently running as the connection
+ user.
+****************************************************************************/
+
+BOOL become_authenticated_pipe_user(pipes_struct *p)
+{
+ /*
+ * Go back to root.
+ */
+
+ if(!unbecome_user())
+ return False;
+
+ /*
+ * Now become the authenticated user stored in the pipe struct.
+ */
+
+ if(!become_id(p->uid, p->gid)) {
+ /* Go back to the connection user. */
+ become_user(p->conn, p->vuid);
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Unbecome the user of an authenticated connected named pipe.
+ When this is called we are running as the authenticated pipe
+ user and need to go back to being the connection user.
+****************************************************************************/
+
+BOOL unbecome_authenticated_pipe_user(pipes_struct *p)
+{
+ if(!become_id(0,0)) {
+ DEBUG(0,("unbecome_authenticated_pipe_user: Unable to go back to root.\n"));
+ return False;
+ }
+
+ return become_user(p->conn, p->vuid);
}
static struct current_user current_user_saved;
@@ -463,13 +351,14 @@ static int become_root_depth;
static pstring become_root_dir;
/****************************************************************************
-This is used when we need to do a privilaged operation (such as mucking
+This is used when we need to do a privileged operation (such as mucking
with share mode files) and temporarily need root access to do it. This
call should always be paired with an unbecome_root() call immediately
after the operation
Set save_dir if you also need to save/restore the CWD
****************************************************************************/
+
void become_root(BOOL save_dir)
{
if (become_root_depth) {
@@ -486,10 +375,11 @@ void become_root(BOOL save_dir)
}
/****************************************************************************
-When the privilaged operation is over call this
+When the privileged operation is over call this
Set save_dir if you also need to save/restore the CWD
****************************************************************************/
+
void unbecome_root(BOOL restore_dir)
{
if (become_root_depth != 1) {
@@ -512,9 +402,9 @@ void unbecome_root(BOOL restore_dir)
#ifdef HAVE_SETGROUPS
if (current_user_saved.ngroups > 0) {
- if (setgroups(current_user_saved.ngroups,
+ if (sys_setgroups(current_user_saved.ngroups,
current_user_saved.groups)<0)
- DEBUG(0,("ERROR: setgroups call failed!\n"));
+ DEBUG(0,("ERROR: sys_setgroups call failed!\n"));
}
#endif
@@ -531,5 +421,3 @@ void unbecome_root(BOOL restore_dir)
become_root_depth = 0;
}
-
-