summaryrefslogtreecommitdiff
path: root/source/smbd
diff options
context:
space:
mode:
authorLuke Leighton <lkcl@samba.org>2000-04-03 02:39:42 +0000
committerLuke Leighton <lkcl@samba.org>2000-04-03 02:39:42 +0000
commit12be5496048bec9566d7b70c20bb236e9ad11a07 (patch)
tree170bd143a7fe24524b66482894350ceaf37e870a /source/smbd
parent54c1d574a88cafbc029cf5aa5ebbd6f27054724c (diff)
downloadsamba-12be5496048bec9566d7b70c20bb236e9ad11a07.tar.gz
merge of smbd and related files, from cvs main.
Diffstat (limited to 'source/smbd')
-rw-r--r--source/smbd/.cvsignore1
-rw-r--r--source/smbd/blocking.c72
-rw-r--r--source/smbd/chgpasswd.c199
-rw-r--r--source/smbd/close.c91
-rw-r--r--source/smbd/conn.c9
-rw-r--r--source/smbd/connection.c265
-rw-r--r--source/smbd/dfree.c87
-rw-r--r--source/smbd/dir.c748
-rw-r--r--source/smbd/dosmode.c88
-rw-r--r--source/smbd/fileio.c562
-rw-r--r--source/smbd/filename.c401
-rw-r--r--source/smbd/files.c20
-rw-r--r--source/smbd/ipc.c476
-rw-r--r--source/smbd/lanman.c5499
-rw-r--r--source/smbd/mangle.c111
-rw-r--r--source/smbd/message.c30
-rw-r--r--source/smbd/negprot.c85
-rw-r--r--source/smbd/nttrans.c1490
-rw-r--r--source/smbd/open.c530
-rw-r--r--source/smbd/oplock.c661
-rw-r--r--source/smbd/password.c588
-rw-r--r--source/smbd/pipes.c182
-rw-r--r--source/smbd/predict.c4
-rw-r--r--source/smbd/process.c428
-rw-r--r--source/smbd/reply.c1470
-rw-r--r--source/smbd/server.c215
-rw-r--r--source/smbd/service.c224
-rw-r--r--source/smbd/ssl.c12
-rw-r--r--source/smbd/trans2.c1125
-rw-r--r--source/smbd/vfs-wrap.c19
-rw-r--r--source/smbd/vfs.c108
31 files changed, 9797 insertions, 6003 deletions
diff --git a/source/smbd/.cvsignore b/source/smbd/.cvsignore
index c8b522d6e79..455336d2ee6 100644
--- a/source/smbd/.cvsignore
+++ b/source/smbd/.cvsignore
@@ -1 +1,2 @@
+.libs
*.lo
diff --git a/source/smbd/blocking.c b/source/smbd/blocking.c
index 96833286e2b..deb9bae9d1c 100644
--- a/source/smbd/blocking.c
+++ b/source/smbd/blocking.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Blocking Locking functions
- Copyright (C) Jeremy Allison 1998
+ Copyright (C) Jeremy Allison 1998-2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,7 +24,6 @@
extern int DEBUGLEVEL;
extern int Client;
-extern int chain_size;
extern char *OutBuffer;
/****************************************************************************
@@ -210,21 +209,25 @@ static void reply_lockingX_error(blocking_lock_record *blr, int eclass, int32 ec
* of smb_lkrng structs.
*/
- for(i = blr->lock_num; i >= 0; i--) {
+ /*
+ * Ensure we don't do a remove on the lock that just failed,
+ * as under POSIX rules, if we have a lock already there, we
+ * will delete it (and we shouldn't) .....
+ */
+
+ for(i = blr->lock_num - 1; 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);
}
@@ -278,7 +281,7 @@ static BOOL process_lockread(blocking_lock_record *blr)
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
data = smb_buf(outbuf) + 3;
- if(!do_lock( fsp, conn, numtoread, startpos, F_RDLCK, &eclass, &ecode)) {
+ if(!do_lock( fsp, conn, numtoread, startpos, READ_LOCK, &eclass, &ecode)) {
if((errno != EACCES) && (errno != EAGAIN)) {
/*
* We have other than a "can't get lock" POSIX
@@ -315,7 +318,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;
@@ -341,7 +344,7 @@ static BOOL process_lock(blocking_lock_record *blr)
offset = IVAL(inbuf,smb_vwv3);
errno = 0;
- if (!do_lock(fsp, conn, count, offset, F_WRLCK, &eclass, &ecode)) {
+ if (!do_lock(fsp, conn, count, offset, WRITE_LOCK, &eclass, &ecode)) {
if((errno != EACCES) && (errno != EAGAIN)) {
/*
@@ -403,20 +406,17 @@ 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),
+ if(!do_lock(fsp,conn,count,offset, ((locktype & 1) ? READ_LOCK : WRITE_LOCK),
&eclass, &ecode))
break;
}
@@ -529,6 +529,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/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c
index 2b1abc9174e..c4ec3981f8a 100644
--- a/source/smbd/chgpasswd.c
+++ b/source/smbd/chgpasswd.c
@@ -52,25 +52,21 @@
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;
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,
@@ -86,15 +82,15 @@ static int findpty(char **slave)
return (master);
}
}
-#else /* HAVE_GRANTPT */
+#endif /* HAVE_GRANTPT */
+
fstrcpy(line, "/dev/ptyXX");
dirp = opendir("/dev");
if (!dirp)
return (-1);
- while ((dentry = readdir(dirp)) != NULL)
+ while ((dpname = readdirname(dirp)) != NULL)
{
- dpname = dentry->d_name;
if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5)
{
DEBUG(3,
@@ -113,7 +109,6 @@ static int findpty(char **slave)
}
}
closedir(dirp);
-#endif /* HAVE_GRANTPT */
return (-1);
}
@@ -228,99 +223,90 @@ static int dochild(int master, char *slavedev, const char *_name,
return (True);
}
-static int expect(int master, char *expected, char *buf)
+static int expect(int master, char *issue, char *expected)
{
- int n, m;
+ pstring buffer;
+ int attempts, timeout, nread, len;
+ BOOL match = False;
- n = 0;
- buf[0] = 0;
- while (1)
+ for (attempts = 0; attempts < 2; attempts++)
{
- if (n >= BUFSIZE - 1)
+ if (!strequal(issue, "."))
{
- return False;
+ if (lp_passwd_chat_debug())
+ DEBUG(100, ("expect: sending [%s]\n", issue));
+
+ write(master, issue, strlen(issue));
}
- /* 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;
+ if (strequal(expected, "."))
+ return True;
- n += m;
- buf[n] = 0;
+ timeout = 2000;
+ nread = 0;
+ buffer[nread] = 0;
+ while ((len = read_with_timeout(master, buffer + nread, 1,
+ sizeof(buffer) - nread - 1,
+ timeout)) > 0)
{
- pstring s1, s2;
- pstrcpy(s1, buf);
- pstrcpy(s2, expected);
- if (do_match(s1, s2, False))
- return (True);
+ 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;
}
}
-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");
+ return match;
}
-static void writestring(int fd, char *s)
+static void pwd_sub(char *buf)
{
- int l;
-
- l = strlen(s);
- write(fd, s, l);
+ 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 int talktochild(int master, char *chatsequence)
+static int talktochild(int master, char *seq)
{
- char buf[BUFSIZE];
int count = 0;
- char *ptr = chatsequence;
- fstring chatbuf;
+ fstring issue, expected;
- *buf = 0;
- sleep(1);
+ fstrcpy(issue, ".");
- while (next_token(&ptr, chatbuf, NULL, sizeof(chatbuf)))
+ while (next_token(&seq, expected, NULL, sizeof(expected)))
{
- BOOL ok = True;
+ pwd_sub(expected);
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)
+ if (!expect(master, issue, expected))
{
- DEBUG(3, ("response %d incorrect\n", count));
- return (False);
+ DEBUG(3, ("Response %d incorrect\n", count));
+ return False;
}
- if (!next_token(&ptr, chatbuf, NULL, sizeof(chatbuf)))
- break;
- pwd_sub(chatbuf);
- if (!strequal(chatbuf, "."))
- writestring(master, chatbuf);
+ if (!next_token(&seq, issue, NULL, sizeof(issue)))
+ fstrcpy(issue, ".");
- if (lp_passwd_chat_debug())
- DEBUG(100, ("talktochild: sendbuf=[%s]\n", chatbuf));
+ pwd_sub(issue);
}
- if (count < 1)
- return (False);
-
- return (True);
+ return (count > 0);
}
@@ -342,12 +328,20 @@ static BOOL chat_with_program(char *passwordprogram, const char *name,
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);
}
@@ -362,13 +356,29 @@ static BOOL chat_with_program(char *passwordprogram, const char *name,
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)
@@ -415,8 +425,14 @@ static BOOL chat_with_program(char *passwordprogram, const char *name,
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)
@@ -431,8 +447,7 @@ BOOL chgpasswd(const char *_name, char *oldpass, char *newpass, BOOL as_root)
{
pstring passwordprogram;
pstring chatsequence;
- int i;
- int len;
+ size_t i, len;
fstring name;
fstrcpy(name, _name);
@@ -445,11 +460,11 @@ BOOL chgpasswd(const 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 */
}
@@ -503,11 +518,12 @@ BOOL chgpasswd(const char *_name, char *oldpass, char *newpass, BOOL as_root)
}
}
- string_sub(passwordprogram, "%u", name);
- all_string_sub(passwordprogram, "%o", oldpass, 0);
- all_string_sub(passwordprogram, "%n", newpass, 0);
+ 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);
+ 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
@@ -550,15 +566,8 @@ static BOOL check_oem_password(const char *user,
BOOL nt_pass_set = (_ntdata != NULL && nthash != NULL);
- if (_lmdata != NULL)
- {
- memcpy(lmdata, _lmdata, sizeof(lmdata));
- }
-
- if (_ntdata != NULL)
- {
- memcpy(ntdata, _ntdata, sizeof(ntdata));
- }
+ Memcpy(lmdata, _lmdata, sizeof(lmdata));
+ Memcpy(ntdata, _ntdata, sizeof(ntdata));
become_root(False);
(*psmbpw) = smbpw = getsmbpwnam(user);
diff --git a/source/smbd/close.c b/source/smbd/close.c
index f588f248487..905b1c5b947 100644
--- a/source/smbd/close.c
+++ b/source/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,13 +89,15 @@ 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;
- 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);
@@ -118,10 +112,15 @@ void close_file(files_struct *fsp, BOOL normal_close)
del_share_mode(fsp);
}
- if(fd_attempt_close(fsp) == 0)
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ release_file_oplock(fsp);
+
+ locking_close_file(fsp);
+
+ if(fd_attempt_close(fsp, &err) == 0)
last_reference = True;
- fsp->fd_ptr = NULL;
+ fsp->fd_ptr = NULL;
if (lp_share_modes(SNUM(conn)))
unlock_share_entry(conn, dev, inode);
@@ -161,31 +160,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);
@@ -194,5 +209,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/source/smbd/conn.c b/source/smbd/conn.c
index fcec05acce7..83289b21848 100644
--- a/source/smbd/conn.c
+++ b/source/smbd/conn.c
@@ -110,16 +110,15 @@ connection_struct *conn_new(void)
ZERO_STRUCTP(conn);
conn->cnum = i;
- conn->smbd_pid = getpid();
bitmap_set(bmap, i);
num_open++;
- string_init(&conn->user,"");
- string_init(&conn->dirpath,"");
- string_init(&conn->connectpath,"");
- string_init(&conn->origpath,"");
+ string_set(&conn->user,"");
+ string_set(&conn->dirpath,"");
+ string_set(&conn->connectpath,"");
+ string_set(&conn->origpath,"");
DLIST_ADD(Connections, conn);
diff --git a/source/smbd/connection.c b/source/smbd/connection.c
index fc025bc826a..f049b473046 100644
--- a/source/smbd/connection.c
+++ b/source/smbd/connection.c
@@ -27,6 +27,11 @@ static TDB_CONTEXT *tdb;
extern int DEBUGLEVEL;
+#ifdef WITH_UTMP
+static void utmp_yield(pid_t pid, const connection_struct *conn);
+static void utmp_claim(const struct connections_data *crec, const connection_struct *conn);
+#endif
+
/****************************************************************************
delete a connection record
****************************************************************************/
@@ -48,6 +53,12 @@ BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
kbuf.dsize = sizeof(key);
tdb_delete(tdb, kbuf);
+
+#ifdef WITH_UTMP
+ if(conn)
+ utmp_yield(key.pid, conn);
+#endif
+
return(True);
}
@@ -101,5 +112,259 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO
if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) return False;
+#ifdef WITH_UTMP
+ if (conn)
+ utmp_claim(&crec, conn);
+#endif
+
return True;
}
+
+#ifdef WITH_UTMP
+
+/****************************************************************************
+Reflect connection status in utmp/wtmp files.
+ T.D.Lee@durham.ac.uk September 1999
+
+Hints for porting:
+ o Always attempt to use programmatic interface (pututline() etc.)
+ o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable.
+
+OS status:
+ Solaris 2.x: Tested on 2.6 and 2.7; should be OK on other flavours.
+ T.D.Lee@durham.ac.uk
+ HPUX 9.x: Not tested. Appears not to have "x".
+ IRIX 6.5: Not tested. Appears to have "x".
+
+Notes:
+ The 4 byte 'ut_id' component is vital to distinguish connections,
+ of which there could be several hundered or even thousand.
+ Entries seem to be printable characters, with optional NULL pads.
+
+ We need to be distinct from other entries in utmp/wtmp.
+
+ Observed things: therefore avoid them. Add to this list please.
+ From Solaris 2.x (because that's what I have):
+ 'sN' : run-levels; N: [0-9]
+ 'co' : console
+ 'CC' : arbitrary things; C: [a-z]
+ 'rXNN' : rlogin; N: [0-9]; X: [0-9a-z]
+ 'tXNN' : rlogin; N: [0-9]; X: [0-9a-z]
+ '/NNN' : Solaris CDE
+ 'ftpZ' : ftp (Z is the number 255, aka 0377, aka 0xff)
+ Mostly a record uses the same 'ut_id' in both "utmp" and "wtmp",
+ but differences have been seen.
+
+ Arbitrarily I have chosen to use a distinctive 'SM' for the
+ first two bytes.
+
+ The remaining two encode the connection number used in samba locking
+ functions "claim_connection() and "yield_connection()". This seems
+ to be a "nicely behaved" number: starting from 0 then working up
+ looking for an available slot.
+
+****************************************************************************/
+
+#include <utmp.h>
+
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+
+static const char *ut_id_encstr =
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+static
+int
+ut_id_encode(int i, char *fourbyte)
+{
+ int nbase;
+
+ fourbyte[0] = 'S';
+ fourbyte[1] = 'M';
+
+/*
+ * Encode remaining 2 bytes from 'i'.
+ * 'ut_id_encstr' is the character set on which modulo arithmetic is done.
+ * Example: digits would produce the base-10 numbers from '001'.
+ */
+ nbase = strlen(ut_id_encstr);
+
+ fourbyte[3] = ut_id_encstr[i % nbase];
+ i /= nbase;
+ fourbyte[2] = ut_id_encstr[i % nbase];
+ i /= nbase;
+
+ return(i); /* 0: good; else overflow */
+}
+
+static int utmp_fill(struct utmp *u, const connection_struct *conn, pid_t pid, int i)
+{
+ struct timeval timeval;
+ int rc;
+
+ pstrcpy(u->ut_user, conn->user);
+ rc = ut_id_encode(i, u->ut_id);
+ slprintf(u->ut_line, 12, "smb/%d", i);
+
+ u->ut_pid = pid;
+
+ gettimeofday(&timeval, NULL);
+ u->ut_time = timeval.tv_sec;
+
+ return(rc);
+}
+
+/* Default path (if possible) */
+#ifdef HAVE_UTMPX_H
+
+# ifdef UTMPX_FILE
+static char *ut_pathname = UTMPX_FILE;
+# else
+static char *ut_pathname = "";
+# endif
+# ifdef WTMPX_FILE
+static char *wt_pathname = WTMPX_FILE;
+# else
+static char *wt_pathname = "";
+# endif
+
+#else /* HAVE_UTMPX_H */
+
+# ifdef UTMP_FILE
+static char *ut_pathname = UTMP_FILE;
+# else
+static char *ut_pathname = "";
+# endif
+# ifdef WTMP_FILE
+static char *wt_pathname = WTMP_FILE;
+# else
+static char *wt_pathname = "";
+# endif
+
+#endif /* HAVE_UTMPX_H */
+
+static void uw_pathname(pstring fname, const char *uw_name)
+{
+ pstring dirname;
+
+ pstrcpy(dirname,lp_utmpdir());
+ trim_string(dirname,"","/");
+
+ /* Given directory: use it */
+ if (dirname != 0 && strlen(dirname) != 0) {
+ pstrcpy(fname, dirname);
+ pstrcat(fname, "/");
+ pstrcat(fname, uw_name);
+ return;
+ }
+
+ /* No given directory: attempt to use default paths */
+ if (uw_name[0] == 'u') {
+ pstrcpy(fname, ut_pathname);
+ return;
+ }
+
+ if (uw_name[0] == 'w') {
+ pstrcpy(fname, wt_pathname);
+ return;
+ }
+
+ pstrcpy(fname, "");
+}
+
+static void utmp_update(const struct utmp *u, const char *host)
+{
+ pstring fname;
+
+#ifdef HAVE_UTMPX_H
+ struct utmpx ux, *uxrc;
+
+ getutmpx(u, &ux);
+ if (host) {
+#if defined(HAVE_UX_UT_SYSLEN)
+ ux.ut_syslen = strlen(host);
+#endif /* defined(HAVE_UX_UT_SYSLEN) */
+ pstrcpy(ux.ut_host, host);
+ }
+
+ uw_pathname(fname, "utmpx");
+ DEBUG(2,("utmp_update: fname:%s\n", fname));
+ if (strlen(fname) != 0) {
+ utmpxname(fname);
+ }
+ uxrc = pututxline(&ux);
+ if (uxrc == NULL) {
+ DEBUG(2,("utmp_update: pututxline() failed\n"));
+ return;
+ }
+
+ uw_pathname(fname, "wtmpx");
+ DEBUG(2,("utmp_update: fname:%s\n", fname));
+ if (strlen(fname) != 0) {
+ updwtmpx(fname, &ux);
+ }
+#else
+ uw_pathname(fname, "utmp");
+ DEBUG(2,("utmp_update: fname:%s\n", fname));
+ if (strlen(fname) != 0) {
+ utmpname(fname);
+ }
+ pututline(u);
+
+ uw_pathname(fname, "wtmp");
+
+ /* *** Hmmm. Appending wtmp (as distinct from overwriting utmp) has
+ me baffled. How is it to be done? *** */
+#endif
+}
+
+static void utmp_yield(pid_t pid, const connection_struct *conn)
+{
+ struct utmp u;
+
+ if (! lp_utmp(SNUM(conn))) {
+ DEBUG(2,("utmp_yield: lp_utmp() NULL\n"));
+ return;
+ }
+
+ DEBUG(2,("utmp_yield: conn: user:%s cnum:%d i:%d\n",
+ conn->user, conn->cnum, i));
+
+ memset((char *)&u, '\0', sizeof(struct utmp));
+ u.ut_type = DEAD_PROCESS;
+ u.ut_exit.e_termination = 0;
+ u.ut_exit.e_exit = 0;
+ if (utmp_fill(&u, conn, pid, conn->cnum) == 0) {
+ utmp_update(&u, NULL);
+ }
+}
+
+static void utmp_claim(const struct connect_record *crec, const connection_struct *conn)
+{
+ struct utmp u;
+
+ if (conn == NULL) {
+ DEBUG(2,("utmp_claim: conn NULL\n"));
+ return;
+ }
+
+ if (! lp_utmp(SNUM(conn))) {
+ DEBUG(2,("utmp_claim: lp_utmp() NULL\n"));
+ return;
+ }
+
+ DEBUG(2,("utmp_claim: conn: user:%s cnum:%d i:%d\n",
+ conn->user, conn->cnum, i));
+ DEBUG(2,("utmp_claim: crec: pid:%d, cnum:%d name:%s addr:%s mach:%s DNS:%s\n",
+ crec->pid, crec->cnum, crec->name, crec->addr, crec->machine, client_connection_name()));
+
+
+ memset((char *)&u, '\0', sizeof(struct utmp));
+ u.ut_type = USER_PROCESS;
+ if (utmp_fill(&u, conn, crec->pid, conn->cnum) == 0) {
+ utmp_update(&u, crec->machine);
+ }
+}
+
+#endif
diff --git a/source/smbd/dfree.c b/source/smbd/dfree.c
index 8cba8d0644a..0a892bad05e 100644
--- a/source/smbd/dfree.c
+++ b/source/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,17 +190,68 @@ 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;
SMB_BIG_UINT bsize_q = 0;
SMB_BIG_UINT dsize_q = 0;
+ char *dfree_command;
(*dfree) = (*dsize) = 0;
(*bsize) = 512;
- fsusage(path, dfree, dsize);
+
+ /*
+ * If external disk calculation specified, use it.
+ */
+
+ dfree_command = lp_dfree_command();
+ if (dfree_command && *dfree_command) {
+ pstring line;
+ char *p;
+ FILE *pp;
+
+ slprintf (line, sizeof(pstring) - 1, "%s %s", dfree_command, path);
+ DEBUG (3, ("disk_free: Running command %s\n", line));
+
+ pp = sys_popen(line, "r", False);
+ if (pp) {
+ fgets(line, sizeof(pstring), pp);
+ line[sizeof(pstring)-1] = '\0';
+ if (strlen(line) > 0)
+ line[strlen(line)-1] = '\0';
+
+ DEBUG (3, ("Read input from dfree, \"%s\"\n", line));
+
+ *dsize = (SMB_BIG_UINT)strtoul(line, &p, 10);
+ while (p && *p & isspace(*p))
+ p++;
+ if (p && *p)
+ *dfree = (SMB_BIG_UINT)strtoul(p, &p, 10);
+ while (p && *p & isspace(*p))
+ p++;
+ if (p && *p)
+ *bsize = (SMB_BIG_UINT)strtoul(p, NULL, 10);
+ else
+ *bsize = 1024;
+ sys_pclose (pp);
+ DEBUG (3, ("Parsed output of dfree, dsize=%u, dfree=%u, bsize=%u\n",
+ (unsigned int)*dsize, (unsigned int)*dfree, (unsigned int)*bsize));
+
+ if (!*dsize)
+ *dsize = 2048;
+ if (!*dfree)
+ *dfree = 1024;
+ } else {
+ DEBUG (0, ("disk_free: sys_popen() failed for command %s. Error was : %s\n",
+ line, strerror(errno) ));
+ fsusage(path, dfree, dsize);
+ }
+ } else
+ fsusage(path, dfree, dsize);
if (disk_quotas(path, &bsize_q, &dfree_q, &dsize_q)) {
(*bsize) = bsize_q;
@@ -219,7 +275,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 +290,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/source/smbd/dir.c b/source/smbd/dir.c
index b7c3177ce2c..55d5bf132cf 100644
--- a/source/smbd/dir.c
+++ b/source/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)
-{
- 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);
+
+static dptr_struct *dptr_get(int key, BOOL forclose)
+{
+ 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 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
+ 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,101 @@ 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);
- /* 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) {
+
+ /*
+ * 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);
+
+ 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) {
+
+ /*
+ * 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);
- /* 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;
+ /* 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);
- if (dirptrs[i].valid)
- dptr_close(i);
+ dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
- 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;
+ 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 */
+
+ 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));
@@ -362,22 +514,14 @@ BOOL dptr_fill(char *buf1,unsigned int key)
return(True);
}
-
/****************************************************************************
-return True is the offset is at zero
+ Fetch the dir ptr and seek it given the 5 byte server field.
****************************************************************************/
-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
-****************************************************************************/
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 +536,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 +552,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 +563,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 +584,68 @@ 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 (conn->vfs_ops.stat(dos_to_unix(pathreal, False), &sbuf) != 0)
+ {
+ DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
+ 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;
+ }
- *size = sbuf.st_size;
- *date = sbuf.st_mtime;
+ 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));
+ }
- DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
+ *size = sbuf.st_size;
+ *date = sbuf.st_mtime;
+
+ DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
- found = True;
- }
+ found = True;
}
+ }
return(found);
}
@@ -512,8 +663,9 @@ typedef struct
/*******************************************************************
-open a directory
+ Open a directory.
********************************************************************/
+
void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
{
Dir *dirp;
@@ -532,13 +684,15 @@ void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
while ((n = vfs_readdirname(conn, p)))
{
- int l = strlen(n)+1;
- pstring zn;
+ int l;
+
+ l = strlen(n)+1;
- pstrcpy(zn, unix_to_dos(n, True));
+ /* Return value of vfs_readdirname has already gone through
+ unix_to_dos() */
/* If it's a vetoed file, pretend it doesn't even exist */
- if (use_veto && conn && IS_VETO_PATH(conn, zn)) continue;
+ if (use_veto && conn && IS_VETO_PATH(conn, n)) continue;
if (used + l > dirp->mallocsize) {
int s = MAX(used+l,used+2000);
@@ -552,7 +706,7 @@ void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
dirp->mallocsize = s;
dirp->current = dirp->data;
}
- pstrcpy(dirp->data+used,zn);
+ pstrcpy(dirp->data+used,n);
used += l;
dirp->numentries++;
}
@@ -563,8 +717,9 @@ void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
/*******************************************************************
-close a directory
+ Close a directory.
********************************************************************/
+
void CloseDir(void *p)
{
Dir *dirp = (Dir *)p;
@@ -574,8 +729,9 @@ void CloseDir(void *p)
}
/*******************************************************************
-read from a directory
+ Read from a directory.
********************************************************************/
+
char *ReadDirName(void *p)
{
char *ret;
@@ -592,8 +748,9 @@ char *ReadDirName(void *p)
/*******************************************************************
-seek a dir
+ Seek a dir.
********************************************************************/
+
BOOL SeekDir(void *p,int pos)
{
Dir *dirp = (Dir *)p;
@@ -611,8 +768,9 @@ BOOL SeekDir(void *p,int pos)
}
/*******************************************************************
-tell a dir position
+ Tell a dir position.
********************************************************************/
+
int TellDir(void *p)
{
Dir *dirp = (Dir *)p;
@@ -622,38 +780,32 @@ int TellDir(void *p)
return(dirp->pos);
}
+/*******************************************************************************
+ This section manages a global directory cache.
+ (It should probably be split into a separate module. crh)
+********************************************************************************/
-/* -------------------------------------------------------------------------- **
- * This section manages a global directory cache.
- * (It should probably be split into a separate module. crh)
- * -------------------------------------------------------------------------- **
- */
-
-typedef struct
- {
+typedef struct {
ubi_dlNode node;
char *path;
char *name;
char *dname;
int snum;
- } dir_cache_entry;
+} dir_cache_entry;
static ubi_dlNewList( dir_cache );
+/*****************************************************************************
+ Add an entry to the directory cache.
+ Input: path -
+ name -
+ dname -
+ snum -
+ Output: None.
+*****************************************************************************/
+
void DirCacheAdd( char *path, char *name, char *dname, int snum )
- /* ------------------------------------------------------------------------ **
- * Add an entry to the directory cache.
- *
- * Input: path -
- * name -
- * dname -
- * snum -
- *
- * Output: None.
- *
- * ------------------------------------------------------------------------ **
- */
- {
+{
int pathlen;
int namelen;
dir_cache_entry *entry;
@@ -684,27 +836,23 @@ void DirCacheAdd( char *path, char *name, char *dname, int snum )
while( DIRCACHESIZE < dir_cache->count )
free( ubi_dlRemTail( dir_cache ) );
- } /* DirCacheAdd */
+}
+
+/*****************************************************************************
+ Search for an entry to the directory cache.
+ Input: path -
+ name -
+ snum -
+ Output: The dname string of the located entry, or NULL if the entry was
+ not found.
+ Notes: This uses a linear search, which is is okay because of
+ the small size of the cache. Use a splay tree or hash
+ for large caches.
+*****************************************************************************/
char *DirCacheCheck( char *path, char *name, int snum )
- /* ------------------------------------------------------------------------ **
- * Search for an entry to the directory cache.
- *
- * Input: path -
- * name -
- * snum -
- *
- * Output: The dname string of the located entry, or NULL if the entry was
- * not found.
- *
- * Notes: This uses a linear search, which is is okay because of
- * the small size of the cache. Use a splay tree or hash
- * for large caches.
- *
- * ------------------------------------------------------------------------ **
- */
- {
+{
dir_cache_entry *entry;
for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
@@ -721,18 +869,15 @@ char *DirCacheCheck( char *path, char *name, int snum )
}
return(NULL);
- } /* DirCacheCheck */
+}
+
+/*****************************************************************************
+ Remove all cache entries which have an snum that matches the input.
+ Input: snum -
+ Output: None.
+*****************************************************************************/
void DirCacheFlush(int snum)
- /* ------------------------------------------------------------------------ **
- * Remove all cache entries which have an snum that matches the input.
- *
- * Input: snum -
- *
- * Output: None.
- *
- * ------------------------------------------------------------------------ **
- */
{
dir_cache_entry *entry;
ubi_dlNodePtr next;
@@ -744,11 +889,4 @@ void DirCacheFlush(int snum)
free( ubi_dlRemThis( dir_cache, entry ) );
entry = (dir_cache_entry *)next;
}
-} /* DirCacheFlush */
-
-/* -------------------------------------------------------------------------- **
- * End of the section that manages the global directory cache.
- * -------------------------------------------------------------------------- **
- */
-
-
+}
diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c
index 2923959b038..278a4ab5e3d 100644
--- a/source/smbd/dosmode.c
+++ b/source/smbd/dosmode.c
@@ -26,33 +26,68 @@ extern int DEBUGLEVEL;
/****************************************************************************
change a dos mode to a unix mode
base permission for files:
- everybody gets read bit set
+ if inheriting
+ apply read/write bits from parent directory.
+ else
+ everybody gets read bit set
dos readonly is represented in unix by removing everyone's write bit
dos archive is represented in unix by the user's execute bit
dos system is represented in unix by the group's execute bit
dos hidden is represented in unix by the other's execute bit
- Then apply create mask,
- then add force bits.
+ if !inheriting {
+ Then apply create mask,
+ then add force bits.
+ }
base permission for directories:
dos directory is represented in unix by unix's dir bit and the exec bit
- Then apply create mask,
- then add force bits.
+ if !inheriting {
+ Then apply create mask,
+ then add force bits.
+ }
****************************************************************************/
-mode_t unix_mode(connection_struct *conn,int dosmode)
+mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname)
{
mode_t result = (S_IRUSR | S_IRGRP | S_IROTH);
+ mode_t dir_mode = 0; /* Mode of the parent directory if inheriting. */
if ( !IS_DOS_READONLY(dosmode) )
result |= (S_IWUSR | S_IWGRP | S_IWOTH);
-
+
+ if (fname && lp_inherit_perms(SNUM(conn))) {
+ char *dname;
+ SMB_STRUCT_STAT sbuf;
+
+ dname = parent_dirname(fname);
+ DEBUG(2,("unix_mode(%s) inheriting from %s\n",fname,dname));
+ if (dos_stat(dname,&sbuf) != 0) {
+ DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",fname,dname,strerror(errno)));
+ return(0); /* *** shouldn't happen! *** */
+ }
+
+ /* Save for later - but explicitly remove setuid bit for safety. */
+ dir_mode = sbuf.st_mode & ~S_ISUID;
+ DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
+ /* Clear "result" */
+ result = 0;
+ }
+
if (IS_DOS_DIR(dosmode)) {
/* We never make directories read only for the owner as under DOS a user
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));
- /* Add in force bits */
- result |= lp_force_dir_mode(SNUM(conn));
+ result |= (S_IFDIR | S_IWUSR);
+
+ if (dir_mode) {
+ /* Inherit mode of parent directory. */
+ result |= dir_mode;
+ } else {
+ /* Provisionally add all 'x' bits */
+ result |= (S_IXUSR | S_IXGRP | S_IXOTH);
+
+ /* Apply directory mask */
+ result &= lp_dir_mask(SNUM(conn));
+ /* Add in force bits */
+ result |= lp_force_dir_mode(SNUM(conn));
+ }
} else {
if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
result |= S_IXUSR;
@@ -62,11 +97,17 @@ mode_t unix_mode(connection_struct *conn,int dosmode)
if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
result |= S_IXOTH;
-
- /* Apply mode mask */
- result &= lp_create_mode(SNUM(conn));
- /* Add in force bits */
- result |= lp_force_create_mode(SNUM(conn));
+
+ if (dir_mode) {
+ /* Inherit 666 component of parent directory mode */
+ result |= dir_mode
+ & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
+ } else {
+ /* Apply mode mask */
+ result &= lp_create_mask(SNUM(conn));
+ /* Add in force bits */
+ result |= lp_force_create_mode(SNUM(conn));
+ }
}
return(result);
}
@@ -155,7 +196,7 @@ int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *
if (dos_mode(conn,fname,st) == dosmode) return(0);
- unixmode = unix_mode(conn,dosmode);
+ unixmode = unix_mode(conn,dosmode,fname);
/* preserve the s bits */
mask |= (S_ISUID | S_ISGID);
@@ -179,11 +220,9 @@ 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(dos_to_unix(fname,False),unixmode));
@@ -251,9 +290,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/source/smbd/fileio.c b/source/smbd/fileio.c
index 1e166275152..7a96e6e598c 100644
--- a/source/smbd/fileio.c
+++ b/source/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
@@ -38,6 +39,18 @@ SMB_OFF_T seek_file(files_struct *fsp,SMB_OFF_T pos)
seek_ret = fsp->conn->vfs_ops.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) ));
fsp->pos = -1;
@@ -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,25 +106,19 @@ 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);
if (readret > 0) ret += readret;
@@ -97,13 +127,43 @@ ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
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,489 @@ 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) {
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) == 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, 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);
+ }
+
+ /* 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 filesize)
+{
+ 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 = filesize;
+ 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 filesize)
+{
+ if(fsp->wcp) {
+ flush_write_cache(fsp, SIZECHANGE_FLUSH);
+ fsp->wcp->file_size = filesize;
+ }
+}
+
+/*******************************************************************
+ 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 sys_fsync_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);
+ conn->vfs_ops.fsync(fsp->fd_ptr->fd);
+ }
#endif
}
diff --git a/source/smbd/filename.c b/source/smbd/filename.c
index 504c35aeec4..729ef8c8099 100644
--- a/source/smbd/filename.c
+++ b/source/smbd/filename.c
@@ -3,6 +3,8 @@
Version 1.9.
filename handling routines
Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1999-200
+ Copyright (C) Ying Chen 2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,6 +21,10 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/*
+ * New hash table stat cache code added by Ying Chen.
+ */
+
#include "includes.h"
extern int DEBUGLEVEL;
@@ -26,7 +32,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 +102,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,
@@ -105,15 +115,12 @@ stat cache was %f%% effective.\n", global_stat_cache_lookups,
}
typedef struct {
- ubi_dlNode link;
int name_len;
- pstring orig_name;
- pstring translated_name;
+ char names[2]; /* This is extended via malloc... */
} stat_cache_entry;
-#define MAX_STAT_CACHE_SIZE 50
-
-static ubi_dlList stat_cache = { NULL, (ubi_dlNodePtr)&stat_cache, 0};
+#define INIT_STAT_CACHE_SIZE 512
+static hash_table stat_cache;
/****************************************************************************
Compare a pathname to a name in the stat cache - of a given length.
@@ -124,6 +131,7 @@ static ubi_dlList stat_cache = { NULL, (ubi_dlNodePtr)&stat_cache, 0};
case.
*****************************************************************************/
+#if 0 /* This function unused?? */
static BOOL stat_name_equal_len( char *stat_name, char *orig_name, int len)
{
BOOL matched = (memcmp( stat_name, orig_name, len) == 0);
@@ -132,6 +140,7 @@ static BOOL stat_name_equal_len( char *stat_name, char *orig_name, int len)
return matched;
}
+#endif
/****************************************************************************
Add an entry into the stat cache.
@@ -140,9 +149,11 @@ static BOOL stat_name_equal_len( char *stat_name, char *orig_name, int len)
static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
{
stat_cache_entry *scp;
+ stat_cache_entry *found_scp;
pstring orig_name;
pstring translated_path;
int namelen;
+ hash_element *hash_elem;
if (!lp_stat_cache()) return;
@@ -190,39 +201,39 @@ static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
* add it.
*/
- for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp;
- scp = (stat_cache_entry *)ubi_dlNext( scp )) {
- if((strcmp( scp->orig_name, orig_name) == 0) &&
- (strcmp( scp->translated_name, translated_path) == 0)) {
- /*
- * Name does exist - promote it.
- */
- if( (stat_cache_entry *)ubi_dlFirst( &stat_cache) != scp ) {
- ubi_dlRemThis( &stat_cache, scp);
- ubi_dlAddHead( &stat_cache, scp);
- }
+ if ((hash_elem = hash_lookup(&stat_cache, orig_name))) {
+ found_scp = (stat_cache_entry *)(hash_elem->value);
+ if (strcmp((found_scp->names+found_scp->name_len+1), translated_path) == 0) {
return;
+ } else {
+ hash_remove(&stat_cache, hash_elem);
+ if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry)+2*namelen)) == NULL) {
+ DEBUG(0,("stat_cache_add: Out of memory !\n"));
+ return;
+ }
+ pstrcpy(scp->names, orig_name);
+ pstrcpy((scp->names+namelen+1), translated_path);
+ scp->name_len = namelen;
+ hash_insert(&stat_cache, (char *)scp, orig_name);
}
- }
-
- if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry))) == NULL) {
- DEBUG(0,("stat_cache_add: Out of memory !\n"));
return;
- }
-
- pstrcpy(scp->orig_name, orig_name);
- pstrcpy(scp->translated_name, translated_path);
- scp->name_len = namelen;
+ } else {
- ubi_dlAddHead( &stat_cache, scp);
-
- DEBUG(10,("stat_cache_add: Added entry %s -> %s\n", scp->orig_name, scp->translated_name ));
+ /*
+ * New entry.
+ */
- if(ubi_dlCount(&stat_cache) > lp_stat_cache_size()) {
- scp = (stat_cache_entry *)ubi_dlRemTail( &stat_cache );
- free((char *)scp);
- return;
+ if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry)+2*namelen)) == NULL) {
+ DEBUG(0,("stat_cache_add: Out of memory !\n"));
+ return;
+ }
+ pstrcpy(scp->names, orig_name);
+ pstrcpy(scp->names+namelen+1, translated_path);
+ scp->name_len = namelen;
+ hash_insert(&stat_cache, (char *)scp, orig_name);
}
+
+ DEBUG(5,("stat_cache_add: Added entry %s -> %s\n", scp->names, (scp->names+scp->name_len+1)));
}
/****************************************************************************
@@ -230,16 +241,18 @@ 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(connection_struct *conn, char *name, char *dirpath,
+ char **start, SMB_STRUCT_STAT *pst)
{
stat_cache_entry *scp;
- stat_cache_entry *longest_hit = NULL;
+ char *trans_name;
pstring chk_name;
int namelen;
+ hash_element *hash_elem;
+ char *sp;
- if (!lp_stat_cache()) return False;
+ if (!lp_stat_cache())
+ return False;
namelen = strlen(name);
@@ -258,124 +271,47 @@ static BOOL stat_cache_lookup(struct connection_struct *conn, char *name,
if(!case_sensitive)
strupper( chk_name );
- for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp;
- scp = (stat_cache_entry *)ubi_dlNext( scp )) {
- if(scp->name_len <= namelen) {
- if(stat_name_equal_len(scp->orig_name, chk_name, scp->name_len)) {
- if((longest_hit == NULL) || (longest_hit->name_len <= scp->name_len))
- longest_hit = scp;
+ while (1) {
+ hash_elem = hash_lookup(&stat_cache, chk_name);
+ if(hash_elem == NULL) {
+ /*
+ * Didn't find it - remove last component for next try.
+ */
+ sp = strrchr(chk_name, '/');
+ if (sp) {
+ *sp = '\0';
+ } else {
+ /*
+ * We reached the end of the name - no match.
+ */
+ global_stat_cache_misses++;
+ return False;
+ }
+ if((*chk_name == '\0') || (strcmp(chk_name, ".") == 0)
+ || (strcmp(chk_name, "..") == 0)) {
+ global_stat_cache_misses++;
+ return False;
}
+ } else {
+ scp = (stat_cache_entry *)(hash_elem->value);
+ global_stat_cache_hits++;
+ trans_name = scp->names+scp->name_len+1;
+ if(conn->vfs_ops.stat(dos_to_unix(trans_name,False), pst) != 0) {
+ /* Discard this entry - it doesn't exist in the filesystem. */
+ hash_remove(&stat_cache, hash_elem);
+ return False;
+ }
+ memcpy(name, trans_name, scp->name_len);
+ *start = &name[scp->name_len];
+ if(**start == '/')
+ ++*start;
+ StrnCpy( dirpath, trans_name, name - (*start));
+ return (namelen == scp->name_len);
}
}
-
- if(longest_hit == NULL) {
- DEBUG(10,("stat_cache_lookup: cache miss on %s\n", name));
- global_stat_cache_misses++;
- return False;
- }
-
- global_stat_cache_hits++;
-
- DEBUG(10,("stat_cache_lookup: cache hit for name %s. %s -> %s\n",
- name, longest_hit->orig_name, longest_hit->translated_name ));
-
- /*
- * longest_hit is the longest match we got in the list.
- * Check it exists - if so, overwrite the original name
- * and then promote it to the top.
- */
-
- if(conn->vfs_ops.stat(dos_to_unix(longest_hit->translated_name,False),
- pst) != 0) {
- /*
- * Discard this entry.
- */
- ubi_dlRemThis( &stat_cache, longest_hit);
- free((char *)longest_hit);
- return False;
- }
-
- memcpy(name, longest_hit->translated_name, longest_hit->name_len);
- if( (stat_cache_entry *)ubi_dlFirst( &stat_cache) != longest_hit ) {
- ubi_dlRemThis( &stat_cache, longest_hit);
- ubi_dlAddHead( &stat_cache, longest_hit);
- }
-
- *start = &name[longest_hit->name_len];
- if(**start == '/')
- ++*start;
-
- StrnCpy( dirpath, longest_hit->translated_name, name - (*start));
-
- return (namelen == longest_hit->name_len);
}
/****************************************************************************
- 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);
-}
-
-
-/*******************************************************************
-reduce a file name, removing .. elements.
-********************************************************************/
-static void unix_clean_name(char *s)
-{
- char *p=NULL;
-
- DEBUG(3,("unix_clean_name [%s]\n",s));
-
- /* remove any double slashes */
- string_sub(s, "//","/");
-
- /* Remove leading ./ characters */
- if(strncmp(s, "./", 2) == 0) {
- trim_string(s, "./", NULL);
- if(*s == 0)
- pstrcpy(s,"./");
- }
-
- while ((p = strstr(s,"/../")) != NULL)
- {
- pstring s1;
-
- *p = 0;
- pstrcpy(s1,p+3);
-
- if ((p=strrchr(s,'/')) != NULL)
- *p = 0;
- else
- *s = 0;
- pstrcat(s,s1);
- }
-
- trim_string(s,NULL,"/..");
-}
-/****************************************************************************
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.
@@ -396,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
@@ -417,7 +352,7 @@ BOOL unix_convert(char *name,connection_struct *conn,
*dirpath = 0;
*bad_path = False;
if(pst) {
- ZERO_STRUCTP(pst);
+ ZERO_STRUCTP(pst);
}
if(saved_last_component)
@@ -480,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);
}
@@ -518,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));
@@ -529,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,'*'))
@@ -702,136 +635,6 @@ BOOL unix_convert(char *name,connection_struct *conn,
return(True);
}
-/*******************************************************************
-reduce a file name, removing .. elements and checking that
-it is below dir in the hierarchy. This uses GetWd() and so must be run
-on the system that has the referenced file system.
-
-widelinks are allowed if widelinks is true
-********************************************************************/
-
-static BOOL reduce_name(char *s,char *dir,BOOL widelinks)
-{
-#ifndef REDUCE_PATHS
- return True;
-#else
- pstring dir2;
- pstring wd;
- pstring base_name;
- pstring newname;
- char *p=NULL;
- BOOL relative = (*s != '/');
-
- *dir2 = *wd = *base_name = *newname = 0;
-
- if (widelinks)
- {
- unix_clean_name(s);
- /* can't have a leading .. */
- if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
- {
- DEBUG(3,("Illegal file name? (%s)\n",s));
- return(False);
- }
-
- if (strlen(s) == 0)
- pstrcpy(s,"./");
-
- return(True);
- }
-
- DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
-
- /* remove any double slashes */
- string_sub(s,"//","/");
-
- pstrcpy(base_name,s);
- p = strrchr(base_name,'/');
-
- if (!p)
- return(True);
-
- if (!dos_GetWd(wd))
- {
- DEBUG(0,("couldn't getwd for %s %s\n",s,dir));
- return(False);
- }
-
- if (dos_ChDir(dir) != 0)
- {
- DEBUG(0,("couldn't chdir to %s\n",dir));
- return(False);
- }
-
- if (!dos_GetWd(dir2))
- {
- DEBUG(0,("couldn't getwd for %s\n",dir));
- dos_ChDir(wd);
- return(False);
- }
-
-
- if (p && (p != base_name))
- {
- *p = 0;
- if (strcmp(p+1,".")==0)
- p[1]=0;
- if (strcmp(p+1,"..")==0)
- *p = '/';
- }
-
- if (dos_ChDir(base_name) != 0)
- {
- dos_ChDir(wd);
- DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,base_name));
- return(False);
- }
-
- if (!dos_GetWd(newname))
- {
- dos_ChDir(wd);
- DEBUG(2,("couldn't get wd for %s %s\n",s,dir2));
- return(False);
- }
-
- if (p && (p != base_name))
- {
- pstrcat(newname,"/");
- pstrcat(newname,p+1);
- }
-
- {
- size_t l = strlen(dir2);
- if (dir2[l-1] == '/')
- l--;
-
- if (strncmp(newname,dir2,l) != 0)
- {
- dos_ChDir(wd);
- DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,l));
- return(False);
- }
-
- if (relative)
- {
- if (newname[l] == '/')
- pstrcpy(s,newname + l + 1);
- else
- pstrcpy(s,newname+l);
- }
- else
- pstrcpy(s,newname);
- }
-
- dos_ChDir(wd);
-
- if (strlen(s) == 0)
- pstrcpy(s,"./");
-
- DEBUG(3,("reduced to %s\n",s));
- return(True);
-#endif
-}
/****************************************************************************
check a filename - possibly caling reducename
@@ -925,7 +728,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))
@@ -941,3 +745,16 @@ static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL d
CloseDir(cur_dir);
return(False);
}
+
+/*************************************************************************** **
+ * Initializes or clears the stat cache.
+ *
+ * Input: none.
+ * Output: none.
+ *
+ * ************************************************************************** **
+ */
+BOOL reset_stat_cache( void )
+{
+ return hash_table_init( &stat_cache, INIT_STAT_CACHE_SIZE, (compare_function)(strcmp));
+} /* reset_stat_cache */
diff --git a/source/smbd/files.c b/source/smbd/files.c
index 7f4533e7ae7..d62950c568a 100644
--- a/source/smbd/files.c
+++ b/source/smbd/files.c
@@ -97,7 +97,7 @@ files_struct *file_new(void )
files_used++;
fsp->fnum = i + FILE_HANDLE_OFFSET;
- string_init(&fsp->fsp_name,"");
+ string_set(&fsp->fsp_name,"");
DLIST_ADD(Files, fsp);
@@ -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)) {
+ conn->vfs_ops.fsync(fsp->fd_ptr->fd);
}
}
}
+
/****************************************************************************
free up a fd_ptr
****************************************************************************/
diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c
index 278869d4946..578775e73a0 100644
--- a/source/smbd/ipc.c
+++ b/source/smbd/ipc.c
@@ -51,55 +51,63 @@ extern uint32 global_client_caps;
******************************************************************/
static void copy_trans_params_and_data(char *outbuf, int align,
- prs_struct *rparam, prs_struct *rdata,
- int param_offset, int data_offset,
- int param_len, int data_len)
+ prs_struct *rparam, prs_struct *rdata,
+ int param_offset, int data_offset,
+ int param_len, int data_len)
{
- char *copy_into = smb_buf(outbuf)+1;
+ char *copy_into = smb_buf(outbuf) + 1;
- 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));
+ 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) prs_buf_copy(copy_into, rparam, param_offset, param_len);
+ if (param_len)
+ prs_buf_copy(copy_into, rparam, param_offset, param_len);
copy_into += param_len + align;
- if (data_len ) prs_buf_copy(copy_into, rdata , data_offset , data_len);
+ if (data_len)
+ prs_buf_copy(copy_into, rdata, data_offset, data_len);
}
/****************************************************************************
send a trans reply
****************************************************************************/
void send_trans_reply(char *outbuf,
- prs_struct *rdata,
- prs_struct *rparam,
- uint16 *setup, int lsetup, int max_data_ret,
- BOOL pipe_data_outstanding)
+ prs_struct *rdata,
+ prs_struct *rparam,
+ uint16 *setup, int lsetup, int max_data_ret,
+ BOOL pipe_data_outstanding)
{
int i;
- int this_ldata,this_lparam;
- int tot_data=0,tot_param=0;
+ int this_ldata, this_lparam;
+ int tot_data = 0, tot_param = 0;
int align;
- int ldata = rdata ? prs_buf_len(rdata ) : 0;
+ int ldata = rdata ? prs_buf_len(rdata) : 0;
int lparam = rparam ? prs_buf_len(rparam) : 0;
BOOL buffer_too_large = max_data_ret ? ldata > max_data_ret : False;
- DEBUG(10,("send_trans_reply: max_data_ret: %d datalen: %d plen: %d\n",
- max_data_ret, ldata, lparam));
+ DEBUG(10,
+ ("send_trans_reply: max_data_ret: %d datalen: %d plen: %d\n",
+ max_data_ret, ldata, lparam));
if (buffer_too_large)
{
- DEBUG(5,("send_trans_reply: buffer %d too large %d\n", ldata, max_data_ret));
+ DEBUG(5,
+ ("send_trans_reply: buffer %d too large %d\n", ldata,
+ max_data_ret));
ldata = max_data_ret;
}
- this_lparam = MIN(lparam,max_send - (500+lsetup*SIZEOFWORD)); /* hack */
- this_ldata = MIN(ldata,max_send - (500+lsetup*SIZEOFWORD+this_lparam));
+ this_lparam = MIN(lparam, max_send - (500 + lsetup * SIZEOFWORD)); /* hack */
+ this_ldata =
+ MIN(ldata,
+ max_send - (500 + lsetup * SIZEOFWORD + this_lparam));
- align = ((this_lparam)%4);
+ align = ((this_lparam) % 4);
- set_message(outbuf,10+lsetup,1+align+this_ldata+this_lparam,True);
+ set_message(outbuf, 10 + lsetup, 1 + align + this_ldata + this_lparam,
+ True);
if (buffer_too_large || pipe_data_outstanding)
{
@@ -107,65 +115,73 @@ void send_trans_reply(char *outbuf,
{
/* 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 {
+ SIVAL(outbuf, smb_rcls, 0x80000005); /* STATUS_BUFFER_OVERFLOW */
+ }
+ else
+ {
SCVAL(outbuf, smb_rcls, ERRDOS);
SSVAL(outbuf, smb_err, ERRmoredata);
}
}
copy_trans_params_and_data(outbuf, align,
- rparam , rdata,
- tot_param , tot_data,
- this_lparam, this_ldata);
-
- SSVAL(outbuf,smb_vwv0,lparam);
- SSVAL(outbuf,smb_vwv1,ldata);
- SSVAL(outbuf,smb_vwv3,this_lparam);
- SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
- SSVAL(outbuf,smb_vwv5,0);
- 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++)
+ rparam, rdata,
+ tot_param, tot_data,
+ this_lparam, this_ldata);
+
+ SSVAL(outbuf, smb_vwv0, lparam);
+ SSVAL(outbuf, smb_vwv1, ldata);
+ SSVAL(outbuf, smb_vwv3, this_lparam);
+ SSVAL(outbuf, smb_vwv4, smb_offset(smb_buf(outbuf) + 1, outbuf));
+ SSVAL(outbuf, smb_vwv5, 0);
+ 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_vwv10 + i * SIZEOFWORD, setup[i]);
}
show_msg(outbuf);
- send_smb(Client,outbuf);
+ send_smb(Client, outbuf);
tot_data = this_ldata;
tot_param = this_lparam;
while (tot_data < ldata || tot_param < lparam)
{
- this_lparam = MIN(lparam-tot_param, max_send - 500); /* hack */
- this_ldata = MIN(ldata -tot_data , max_send - (500+this_lparam));
+ this_lparam = MIN(lparam - tot_param, max_send - 500); /* hack */
+ this_ldata =
+ MIN(ldata - tot_data, max_send - (500 + this_lparam));
- align = (this_lparam%4);
+ align = (this_lparam % 4);
- set_message(outbuf,10,1+this_ldata+this_lparam+align,False);
+ 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);
-
- 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_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_vwv9,0);
+ rparam, rdata,
+ tot_param, tot_data,
+ this_lparam, 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_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_vwv9, 0);
show_msg(outbuf);
- send_smb(Client,outbuf);
+ send_smb(Client, outbuf);
- tot_data += this_ldata;
+ tot_data += this_ldata;
tot_param += this_lparam;
}
}
@@ -177,20 +193,21 @@ static void api_rpc_trans_reply(char *outbuf, char *rdata, int rlen,
prs_create(&ps, rdata, rlen, 0, False);
prs_debug_out(&ps, "api_rpc_trans_reply", 200);
send_trans_reply(outbuf, &ps, NULL, NULL, 0, rlen,
- pipe_data_outstanding);
+ pipe_data_outstanding);
}
/****************************************************************************
WaitNamedPipeHandleState
****************************************************************************/
-static BOOL api_WNPHS(char *outbuf, pipes_struct *p, char *param, int mdrcnt)
+static BOOL api_WNPHS(char *outbuf, pipes_struct * p, char *param, int mdrcnt)
{
uint16 priority;
- if (!param) return False;
+ if (!param)
+ return False;
priority = param[0] + (param[1] << 8);
- DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority));
+ DEBUG(4, ("WaitNamedPipeHandleState priority %x\n", priority));
if (wait_rpc_pipe_hnd_state(p, priority))
{
@@ -206,14 +223,15 @@ static BOOL api_WNPHS(char *outbuf, pipes_struct *p, char *param, int mdrcnt)
/****************************************************************************
SetNamedPipeHandleState
****************************************************************************/
-static BOOL api_SNPHS(char *outbuf, pipes_struct *p, char *param, int mdrcnt)
+static BOOL api_SNPHS(char *outbuf, pipes_struct * p, char *param, int mdrcnt)
{
uint16 id;
- if (!param) return False;
+ if (!param)
+ return False;
id = param[0] + (param[1] << 8);
- DEBUG(4,("SetNamedPipeHandleState to code %x\n", id));
+ DEBUG(4, ("SetNamedPipeHandleState to code %x\n", id));
if (set_rpc_pipe_hnd_state(p, id))
{
@@ -236,42 +254,44 @@ static BOOL api_no_reply(char *outbuf, int max_rdata_len)
prs_init(&rparam, 4, 0, False);
rparam.start = 0;
- rparam.end = 4;
+ rparam.end = 4;
/* unsupported */
- SSVAL(rparam.data,0,NERR_notsupported);
- SSVAL(rparam.data,2,0); /* converter word */
+ SSVAL(rparam.data, 0, NERR_notsupported);
+ SSVAL(rparam.data, 2, 0); /* converter word */
- DEBUG(3,("Unsupported API fd command\n"));
+ DEBUG(3, ("Unsupported API fd command\n"));
/* now send the reply */
- send_trans_reply(outbuf, NULL, &rparam, NULL, 0, max_rdata_len, False);
+ send_trans_reply(outbuf, NULL, &rparam, NULL, 0, max_rdata_len,
+ False);
prs_free_data(&rparam);
- return(-1);
+ return (-1);
}
/****************************************************************************
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)
+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;
+ BOOL reply = False;
uint16 pnum;
uint16 subcommand;
pipes_struct *p = NULL;
- DEBUG(5,("api_fd_reply\n"));
+ DEBUG(5, ("api_fd_reply\n"));
/* First find out the name of this file. */
if (suwcnt != 2)
{
- DEBUG(0,("Unexpected named pipe transaction.\n"));
- return(-1);
+ DEBUG(0, ("Unexpected named pipe transaction.\n"));
+ return (-1);
}
/* Get the file handle and hence the file name. */
@@ -281,11 +301,11 @@ static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
if (p != NULL)
{
- DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)",
- subcommand, p->name, pnum));
+ DEBUG(3, ("Got API command 0x%x on pipe \"%s\" (pnum %x)",
+ subcommand, p->name, pnum));
/* record maximum data length that can be transmitted in an SMBtrans */
- DEBUG(10,("api_fd_reply: p:%p mdrcnt: %d\n", p, mdrcnt));
+ DEBUG(10, ("api_fd_reply: p:%p mdrcnt: %d\n", p, mdrcnt));
switch (subcommand)
{
@@ -295,12 +315,13 @@ static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
char *rdata = NULL;
int rlen = mdrcnt;
reply = readwrite_pipe(p, data, tdscnt,
- &rdata, &rlen,
- &pipe_outstanding);
+ &rdata, &rlen,
+ &pipe_outstanding);
if (reply)
{
- api_rpc_trans_reply(outbuf, rdata, rlen,
- pipe_outstanding);
+ api_rpc_trans_reply(outbuf, rdata,
+ rlen,
+ pipe_outstanding);
}
break;
}
@@ -320,7 +341,7 @@ static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
}
else
{
- DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
+ DEBUG(1, ("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
}
if (!reply)
@@ -333,36 +354,40 @@ static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
/****************************************************************************
handle named pipe commands
****************************************************************************/
-static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *name,
- uint16 *setup,char *data,char *params,
- int suwcnt,int tdscnt,int tpscnt,
- int msrcnt,int mdrcnt,int mprcnt)
+static int named_pipe(connection_struct * conn, uint16 vuid, char *outbuf,
+ char *name, uint16 *setup, char *data, char *params,
+ int suwcnt, int tdscnt, int tpscnt, int msrcnt,
+ int mdrcnt, int mprcnt)
{
- DEBUG(3,("named pipe command on <%s> name\n", name));
+ DEBUG(3, ("named pipe command on <%s> name\n", name));
- if (strequal(name,"LANMAN"))
+ if (strequal(name, "LANMAN"))
{
- return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
+ return api_reply(conn, vuid, outbuf, data, params, tdscnt,
+ tpscnt, mdrcnt, mprcnt);
}
- if (strequal(name,"WKSSVC") ||
- strequal(name,"SRVSVC") ||
- strequal(name,"WINREG") ||
- strequal(name,"SAMR") ||
- strequal(name,"LSARPC"))
+ if (strequal(name, "WKSSVC") ||
+ strequal(name, "SRVSVC") ||
+ strequal(name, "WINREG") ||
+ strequal(name, "SAMR") || strequal(name, "LSARPC"))
{
- DEBUG(4,("named pipe command from Win95 (wow!)\n"));
- return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
+ DEBUG(4, ("named pipe command from Win95 (wow!)\n"));
+ return api_fd_reply(conn, vuid, outbuf, setup, data, params,
+ suwcnt, tdscnt, tpscnt, mdrcnt, mprcnt);
}
if (strlen(name) < 1)
{
- return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
+ 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]));
+ DEBUG(3,
+ ("unknown named pipe: setup 0x%X setup1=%d\n",
+ (int)setup[0], (int)setup[1]));
}
return 0;
@@ -372,153 +397,188 @@ static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *na
/****************************************************************************
reply to a SMBtrans
****************************************************************************/
-int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
+int reply_trans(connection_struct * conn, char *inbuf, char *outbuf, int size,
+ int bufsize)
{
fstring name;
- int name_offset = 0;
- char *data=NULL,*params=NULL;
- uint16 *setup=NULL;
+ int name_offset = 0;
+ char *data = NULL, *params = NULL;
+ uint16 *setup = NULL;
int outsize = 0;
- uint16 vuid = SVAL(inbuf,smb_uid);
- int tpscnt = SVAL(inbuf,smb_vwv0);
- int tdscnt = SVAL(inbuf,smb_vwv1);
- int mprcnt = SVAL(inbuf,smb_vwv2);
- int mdrcnt = SVAL(inbuf,smb_vwv3);
- int msrcnt = CVAL(inbuf,smb_vwv4);
- BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
- BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
- int pscnt = SVAL(inbuf,smb_vwv9);
- int psoff = SVAL(inbuf,smb_vwv10);
- int dscnt = SVAL(inbuf,smb_vwv11);
- int dsoff = SVAL(inbuf,smb_vwv12);
- int suwcnt = CVAL(inbuf,smb_vwv13);
+ uint16 vuid = SVAL(inbuf, smb_uid);
+ int tpscnt = SVAL(inbuf, smb_vwv0);
+ int tdscnt = SVAL(inbuf, smb_vwv1);
+ int mprcnt = SVAL(inbuf, smb_vwv2);
+ int mdrcnt = SVAL(inbuf, smb_vwv3);
+ int msrcnt = CVAL(inbuf, smb_vwv4);
+ BOOL close_on_completion = BITSETW(inbuf + smb_vwv5, 0);
+ BOOL one_way = BITSETW(inbuf + smb_vwv5, 1);
+ int pscnt = SVAL(inbuf, smb_vwv9);
+ int psoff = SVAL(inbuf, smb_vwv10);
+ int dscnt = SVAL(inbuf, smb_vwv11);
+ int dsoff = SVAL(inbuf, smb_vwv12);
+ int suwcnt = CVAL(inbuf, smb_vwv13);
ZERO_STRUCT(name);
- fstrcpy(name,smb_buf(inbuf));
+ fstrcpy(name, smb_buf(inbuf));
- if (dscnt > tdscnt || pscnt > tpscnt) {
+ if (dscnt > tdscnt || pscnt > tpscnt)
+ {
exit_server("invalid trans parameters\n");
}
-
- if (tdscnt) {
- if((data = (char *)malloc(tdscnt)) == NULL) {
- DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt));
- return(ERROR(ERRDOS,ERRnomem));
- }
- memcpy(data,smb_base(inbuf)+dsoff,dscnt);
+
+ if (tdscnt)
+ {
+ if ((data = (char *)malloc(tdscnt)) == NULL)
+ {
+ DEBUG(0,
+ ("reply_trans: data malloc fail for %d bytes !\n",
+ tdscnt));
+ return (ERROR(ERRDOS, ERRnomem));
+ }
+ memcpy(data, smb_base(inbuf) + dsoff, dscnt);
}
- if (tpscnt) {
- if((params = (char *)malloc(tpscnt)) == NULL) {
- DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt));
- return(ERROR(ERRDOS,ERRnomem));
- }
- memcpy(params,smb_base(inbuf)+psoff,pscnt);
+ if (tpscnt)
+ {
+ if ((params = (char *)malloc(tpscnt)) == NULL)
+ {
+ DEBUG(0,
+ ("reply_trans: param malloc fail for %d bytes !\n",
+ tpscnt));
+ return (ERROR(ERRDOS, ERRnomem));
+ }
+ memcpy(params, smb_base(inbuf) + psoff, pscnt);
}
- if (suwcnt) {
+ 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)));
- return(ERROR(ERRDOS,ERRnomem));
- }
- for (i=0;i<suwcnt;i++)
- setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
+ if ((setup = (uint16 *)malloc(suwcnt * sizeof(uint16))) ==
+ NULL)
+ {
+ DEBUG(0,
+ ("reply_trans: setup malloc fail for %d bytes !\n",
+ suwcnt * sizeof(uint16)));
+ return (ERROR(ERRDOS, ERRnomem));
+ }
+ for (i = 0; i < suwcnt; i++)
+ setup[i] = SVAL(inbuf, smb_vwv14 + i * SIZEOFWORD);
}
- if (pscnt < tpscnt || dscnt < tdscnt) {
+ if (pscnt < tpscnt || dscnt < tdscnt)
+ {
/* We need to send an interim response then receive the rest
of the parameter/data bytes */
- outsize = set_message(outbuf,0,0,True);
+ outsize = set_message(outbuf, 0, 0, True);
show_msg(outbuf);
- send_smb(Client,outbuf);
+ send_smb(Client, outbuf);
}
/* receive the rest of the trans packet */
- while (pscnt < tpscnt || dscnt < tdscnt) {
+ while (pscnt < tpscnt || dscnt < tdscnt)
+ {
BOOL ret;
- int pcnt,poff,dcnt,doff,pdisp,ddisp;
-
- ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
+ int pcnt, poff, dcnt, doff, pdisp, ddisp;
+
+ ret = receive_next_smb(inbuf, bufsize, SMB_SECONDARY_WAIT);
show_msg(inbuf);
-
+
if ((ret && (CVAL(inbuf, smb_com) != SMBtrans &&
- CVAL(inbuf, smb_com) != SMBtranss)) || !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 (ret)
+ {
+ DEBUG(0,
+ ("reply_trans: Invalid secondary trans packet\n"));
}
- if (params) free(params);
- if (data) free(data);
- if (setup) free(setup);
- return(ERROR(ERRSRV,ERRerror));
+ else
+ {
+ DEBUG(0,
+ ("reply_trans: %s in getting secondary trans response.\n",
+ (smb_read_error ==
+ READ_ERROR) ? "error" : "timeout"));
+ }
+ if (params)
+ free(params);
+ if (data)
+ free(data);
+ if (setup)
+ free(setup);
+ return (ERROR(ERRSRV, ERRerror));
}
- tpscnt = SVAL(inbuf,smb_vwv0);
- tdscnt = SVAL(inbuf,smb_vwv1);
-
- pcnt = SVAL(inbuf,smb_vwv2);
- poff = SVAL(inbuf,smb_vwv3);
- pdisp = SVAL(inbuf,smb_vwv4);
-
- dcnt = SVAL(inbuf,smb_vwv5);
- doff = SVAL(inbuf,smb_vwv6);
- ddisp = SVAL(inbuf,smb_vwv7);
-
+ tpscnt = SVAL(inbuf, smb_vwv0);
+ tdscnt = SVAL(inbuf, smb_vwv1);
+
+ pcnt = SVAL(inbuf, smb_vwv2);
+ poff = SVAL(inbuf, smb_vwv3);
+ pdisp = SVAL(inbuf, smb_vwv4);
+
+ dcnt = SVAL(inbuf, smb_vwv5);
+ doff = SVAL(inbuf, smb_vwv6);
+ ddisp = SVAL(inbuf, smb_vwv7);
+
pscnt += pcnt;
dscnt += dcnt;
-
- if (dscnt > tdscnt || pscnt > tpscnt) {
+
+ if (dscnt > tdscnt || pscnt > tpscnt)
+ {
exit_server("invalid trans parameters\n");
}
-
+
if (pcnt)
- memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
+ memcpy(params + pdisp, smb_base(inbuf) + poff, pcnt);
if (dcnt)
- memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);
+ memcpy(data + ddisp, smb_base(inbuf) + doff, dcnt);
+ }
+
+
+ DEBUG(3, ("trans <%s> data=%d params=%d setup=%d\n",
+ name, tdscnt, tpscnt, suwcnt));
+
+ /*
+ * WinCE wierdness....
+ */
+
+ if (name[0] == '\\' && (StrnCaseCmp(&name[1], local_machine,
+ strlen(local_machine)) == 0))
+ {
+ name_offset = strlen(local_machine) + 1;
}
-
-
- DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",
- name,tdscnt,tpscnt,suwcnt));
-
- /*
- * WinCE wierdness....
- */
-
- if (name[0] == '\\' && (StrnCaseCmp(&name[1],local_machine,
- strlen(local_machine)) == 0)) {
- name_offset = strlen(local_machine)+1;
- }
-
- if (strncmp(&name[name_offset],"\\PIPE\\",strlen("\\PIPE\\")) == 0) {
- DEBUG(5,("calling named_pipe\n"));
- outsize = named_pipe(conn,vuid,outbuf,
- name+name_offset+strlen("\\PIPE\\"),setup,data,params,
- suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
- } else {
- DEBUG(3,("invalid pipe name\n"));
+
+ if (strncmp(&name[name_offset], "\\PIPE\\", strlen("\\PIPE\\")) == 0)
+ {
+ DEBUG(5, ("calling named_pipe\n"));
+ outsize = named_pipe(conn, vuid, outbuf,
+ name + name_offset + strlen("\\PIPE\\"),
+ setup, data, params, suwcnt, tdscnt,
+ tpscnt, msrcnt, mdrcnt, mprcnt);
+ }
+ else
+ {
+ DEBUG(3, ("invalid pipe name\n"));
outsize = 0;
}
-
- 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);
+ close_cnum(conn, vuid);
if (one_way)
- return(-1);
-
+ return (-1);
+
if (outsize == 0)
- return(ERROR(ERRSRV,ERRnosupport));
-
- return(outsize);
+ return (ERROR(ERRSRV, ERRnosupport));
+
+ return (outsize);
}
diff --git a/source/smbd/lanman.c b/source/smbd/lanman.c
index 0096499237b..6ffcb2bb566 100644
--- a/source/smbd/lanman.c
+++ b/source/smbd/lanman.c
@@ -1,27 +1,27 @@
/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- Inter-process communication and named pipe handling
- Copyright (C) Andrew Tridgell 1992-2000
-
- SMB Version handling
- Copyright (C) John H Terpstra 1995-2000
-
- Copyright (C) Luke Kenneth Casson Leighton 1996-2000
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Inter-process communication and named pipe handling
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ SMB Version handling
+ Copyright (C) John H Terpstra 1995-2000
+
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
This file handles the named pipe and mailslot calls
@@ -37,6 +37,7 @@
#define CHECK_TYPES 0
extern int DEBUGLEVEL;
+extern int max_send;
extern fstring local_machine;
extern fstring global_myworkgroup;
@@ -63,280 +64,316 @@ extern fstring global_sam_name;
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,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len);
-static BOOL api_TooSmall(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len);
+static BOOL api_Unsupported(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt, int mprcnt,
+ char **rdata, char **rparam, int *rdata_len,
+ int *rparam_len);
+static BOOL api_TooSmall(connection_struct * conn, uint16 vuid, char *param,
+ char *data, int mdrcnt, int mprcnt, char **rdata,
+ char **rparam, int *rdata_len, int *rparam_len);
-static int CopyExpanded(connection_struct *conn, const vuser_key *key,
- int snum, char** dst, char* src, int* n)
+static int CopyExpanded(connection_struct * conn, const vuser_key * key,
+ int snum, char **dst, char *src, int *n)
{
pstring buf;
int l;
user_struct *vuser;
- if (!src || !dst || !n || !(*dst)) return(0);
+ if (!src || !dst || !n || !(*dst))
+ return (0);
- StrnCpy(buf,src,sizeof(buf)/2);
- string_sub(buf,"%S",lp_servicename(snum));
+ StrnCpy(buf, src, sizeof(buf) / 2);
+ pstring_sub(buf, "%S", lp_servicename(snum));
vuser = get_valid_user_struct(key);
- standard_sub(conn,vuser, buf);
+ standard_sub(conn, vuser, buf);
vuid_free_user_struct(vuser);
- StrnCpy(*dst,buf,*n);
+ StrnCpy(*dst, buf, *n);
l = strlen(*dst) + 1;
(*dst) += l;
(*n) -= l;
return l;
}
-static int CopyAndAdvance(char** dst, char* src, int* n)
+static int CopyAndAdvance(char **dst, char *src, int *n)
{
- int l;
- if (!src || !dst || !n || !(*dst)) return(0);
- StrnCpy(*dst,src,*n);
- l = strlen(*dst) + 1;
- (*dst) += l;
- (*n) -= l;
- return l;
+ int l;
+ if (!src || !dst || !n || !(*dst))
+ return (0);
+ StrnCpy(*dst, src, *n - 1);
+ l = strlen(*dst) + 1;
+ (*dst) += l;
+ (*n) -= l;
+ return l;
}
-static int StrlenExpanded(connection_struct *conn,
- const vuser_key *key, int snum, char* s)
+static int StrlenExpanded(connection_struct * conn,
+ const vuser_key * key, int snum, char *s)
{
user_struct *vuser;
pstring buf;
- if (!s) return(0);
- StrnCpy(buf,s,sizeof(buf)/2);
- string_sub(buf,"%S",lp_servicename(snum));
+ if (!s)
+ return (0);
+ StrnCpy(buf, s, sizeof(buf) / 2);
+ pstring_sub(buf, "%S", lp_servicename(snum));
vuser = get_valid_user_struct(key);
- standard_sub(conn,vuser, buf);
+ standard_sub(conn, vuser, buf);
vuid_free_user_struct(vuser);
return strlen(buf) + 1;
}
-static char* Expand(connection_struct *conn, const vuser_key *key, int snum, char* s)
+static char *Expand(connection_struct * conn, const vuser_key * key, int snum,
+ char *s)
{
user_struct *vuser;
static pstring buf;
- if (!s) return(NULL);
- StrnCpy(buf,s,sizeof(buf)/2);
- string_sub(buf,"%S",lp_servicename(snum));
+ if (!s)
+ return (NULL);
+ StrnCpy(buf, s, sizeof(buf) / 2);
+ pstring_sub(buf, "%S", lp_servicename(snum));
vuser = get_valid_user_struct(key);
- standard_sub(conn,vuser, buf);
+ standard_sub(conn, vuser, buf);
return &buf[0];
}
/*******************************************************************
check a API string for validity when we only need to check the prefix
******************************************************************/
-static BOOL prefix_ok(char *str,char *prefix)
+static BOOL prefix_ok(char *str, char *prefix)
{
- return(strncmp(str,prefix,strlen(prefix)) == 0);
+ return (strncmp(str, prefix, strlen(prefix)) == 0);
}
-struct pack_desc {
- char* format; /* formatstring for structure */
- char* subformat; /* subformat for structure */
- char* base; /* baseaddress of buffer */
- int buflen; /* remaining size for fixed part; on init: length of base */
- int subcount; /* count of substructures */
- char* structbuf; /* pointer into buffer for remaining fixed part */
- int stringlen; /* remaining size for variable part */
- char* stringbuf; /* pointer into buffer for remaining variable part */
- int neededlen; /* total needed size */
- int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
- char* curpos; /* current position; pointer into format or subformat */
- int errcode;
+struct pack_desc
+{
+ char *format; /* formatstring for structure */
+ char *subformat; /* subformat for structure */
+ char *base; /* baseaddress of buffer */
+ int buflen; /* remaining size for fixed part; on init: length of base */
+ int subcount; /* count of substructures */
+ char *structbuf; /* pointer into buffer for remaining fixed part */
+ int stringlen; /* remaining size for variable part */
+ char *stringbuf; /* pointer into buffer for remaining variable part */
+ int neededlen; /* total needed size */
+ int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */
+ char *curpos; /* current position; pointer into format or subformat */
+ int errcode;
};
-static int get_counter(char** p)
+static int get_counter(char **p)
{
- int i, n;
- if (!p || !(*p)) return(1);
- if (!isdigit((int)**p)) return 1;
- for (n = 0;;) {
- i = **p;
- if (isdigit(i))
- n = 10 * n + (i - '0');
- else
- return n;
- (*p)++;
- }
+ int i, n;
+ if (!p || !(*p))
+ return (1);
+ if (!isdigit((int)**p))
+ return 1;
+ for (n = 0;;)
+ {
+ i = **p;
+ if (isdigit(i))
+ n = 10 * n + (i - '0');
+ else
+ return n;
+ (*p)++;
+ }
}
-static int getlen(char* p)
+static int getlen(char *p)
{
- int n = 0;
- if (!p) return(0);
- while (*p) {
- switch( *p++ ) {
- case 'W': /* word (2 byte) */
- n += 2;
- break;
- case 'N': /* count of substructures (word) at end */
- n += 2;
- break;
- case 'D': /* double word (4 byte) */
- case 'z': /* offset to zero terminated string (4 byte) */
- case 'l': /* offset to user data (4 byte) */
- n += 4;
- break;
- case 'b': /* offset to data (with counter) (4 byte) */
- n += 4;
- get_counter(&p);
- break;
- case 'B': /* byte (with optional counter) */
- n += get_counter(&p);
- break;
- }
- }
- return n;
+ int n = 0;
+ if (!p)
+ return (0);
+ while (*p)
+ {
+ switch (*p++)
+ {
+ case 'W': /* word (2 byte) */
+ n += 2;
+ break;
+ case 'N': /* count of substructures (word) at end */
+ n += 2;
+ break;
+ case 'D': /* double word (4 byte) */
+ case 'z': /* offset to zero terminated string (4 byte) */
+ case 'l': /* offset to user data (4 byte) */
+ n += 4;
+ break;
+ case 'b': /* offset to data (with counter) (4 byte) */
+ n += 4;
+ get_counter(&p);
+ break;
+ case 'B': /* byte (with optional counter) */
+ n += get_counter(&p);
+ break;
+ }
+ }
+ return n;
}
-static BOOL init_package(struct pack_desc* p, int count, int subcount)
+static BOOL init_package(struct pack_desc *p, int count, int subcount)
{
- int n = p->buflen;
- int i;
-
- if (!p->format || !p->base) return(False);
-
- i = count * getlen(p->format);
- if (p->subformat) i += subcount * getlen(p->subformat);
- p->structbuf = p->base;
- p->neededlen = 0;
- p->usedlen = 0;
- p->subcount = 0;
- p->curpos = p->format;
- if (i > n) {
- p->neededlen = i;
- i = n = 0;
- p->errcode = ERRmoredata;
- }
- else
- p->errcode = NERR_Success;
- p->buflen = i;
- n -= i;
- p->stringbuf = p->base + i;
- p->stringlen = n;
- return(p->errcode == NERR_Success);
+ int n = p->buflen;
+ int i;
+
+ if (!p->format || !p->base)
+ return (False);
+
+ i = count * getlen(p->format);
+ if (p->subformat)
+ i += subcount * getlen(p->subformat);
+ p->structbuf = p->base;
+ p->neededlen = 0;
+ p->usedlen = 0;
+ p->subcount = 0;
+ p->curpos = p->format;
+ if (i > n)
+ {
+ p->neededlen = i;
+ i = n = 0;
+ p->errcode = ERRmoredata;
+ }
+ else
+ p->errcode = NERR_Success;
+ p->buflen = i;
+ n -= i;
+ p->stringbuf = p->base + i;
+ p->stringlen = n;
+ return (p->errcode == NERR_Success);
}
#ifdef HAVE_STDARG_H
-static int package(struct pack_desc* p, ...)
+static int package(struct pack_desc *p, ...)
{
#else
static int package(va_alist)
-va_dcl
+ va_dcl
{
- struct pack_desc* p;
+ struct pack_desc *p;
#endif
- va_list args;
- int needed=0, stringneeded;
- char* str=NULL;
- int is_string=0, stringused;
- int32 temp;
+ va_list args;
+ int needed = 0, stringneeded;
+ char *str = NULL;
+ int is_string = 0, stringused;
+ int32 temp;
#ifdef HAVE_STDARG_H
- va_start(args,p);
+ va_start(args, p);
#else
- va_start(args);
- p = va_arg(args,struct pack_desc *);
+ va_start(args);
+ p = va_arg(args, struct pack_desc *);
#endif
- if (!*p->curpos) {
- if (!p->subcount)
- p->curpos = p->format;
- else {
- p->curpos = p->subformat;
- p->subcount--;
- }
- }
+ if (!*p->curpos)
+ {
+ if (!p->subcount)
+ p->curpos = p->format;
+ else
+ {
+ p->curpos = p->subformat;
+ p->subcount--;
+ }
+ }
#if CHECK_TYPES
- str = va_arg(args,char*);
- SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
+ str = va_arg(args, char *);
+ SMB_ASSERT(strncmp(str, p->curpos, strlen(str)) == 0);
#endif
- stringneeded = -1;
-
- if (!p->curpos) return(0);
-
- switch( *p->curpos++ ) {
- case 'W': /* word (2 byte) */
- needed = 2;
- temp = va_arg(args,int);
- if (p->buflen >= needed) SSVAL(p->structbuf,0,temp);
- break;
- case 'N': /* count of substructures (word) at end */
- needed = 2;
- p->subcount = va_arg(args,int);
- if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount);
- break;
- case 'D': /* double word (4 byte) */
- needed = 4;
- temp = va_arg(args,int);
- if (p->buflen >= needed) SIVAL(p->structbuf,0,temp);
- break;
- case 'B': /* byte (with optional counter) */
- needed = get_counter(&p->curpos);
- {
- char *s = va_arg(args,char*);
- if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed);
- }
- break;
- case 'z': /* offset to zero terminated string (4 byte) */
- str = va_arg(args,char*);
- stringneeded = (str ? strlen(str)+1 : 0);
- is_string = 1;
- break;
- case 'l': /* offset to user data (4 byte) */
- str = va_arg(args,char*);
- stringneeded = va_arg(args,int);
- is_string = 0;
- break;
- case 'b': /* offset to data (with counter) (4 byte) */
- str = va_arg(args,char*);
- stringneeded = get_counter(&p->curpos);
- is_string = 0;
- break;
- }
- va_end(args);
- if (stringneeded >= 0) {
- needed = 4;
- if (p->buflen >= needed) {
- stringused = stringneeded;
- if (stringused > p->stringlen) {
- stringused = (is_string ? p->stringlen : 0);
- if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
- }
- if (!stringused)
- SIVAL(p->structbuf,0,0);
- else {
- SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base));
- memcpy(p->stringbuf,str?str:"",stringused);
- if (is_string) p->stringbuf[stringused-1] = '\0';
- p->stringbuf += stringused;
- p->stringlen -= stringused;
- p->usedlen += stringused;
- }
- }
- p->neededlen += stringneeded;
- }
- p->neededlen += needed;
- if (p->buflen >= needed) {
- p->structbuf += needed;
- p->buflen -= needed;
- p->usedlen += needed;
- }
- else {
- if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
- }
- return 1;
+ stringneeded = -1;
+
+ if (!p->curpos)
+ {
+ va_end(args);
+ return (0);
+ }
+
+ switch (*p->curpos++)
+ {
+ case 'W': /* word (2 byte) */
+ needed = 2;
+ temp = va_arg(args, int);
+ if (p->buflen >= needed)
+ SSVAL(p->structbuf, 0, temp);
+ break;
+ case 'N': /* count of substructures (word) at end */
+ needed = 2;
+ p->subcount = va_arg(args, int);
+ if (p->buflen >= needed)
+ SSVAL(p->structbuf, 0, p->subcount);
+ break;
+ case 'D': /* double word (4 byte) */
+ needed = 4;
+ temp = va_arg(args, int);
+ if (p->buflen >= needed)
+ SIVAL(p->structbuf, 0, temp);
+ break;
+ case 'B': /* byte (with optional counter) */
+ needed = get_counter(&p->curpos);
+ {
+ char *s = va_arg(args, char *);
+ if (p->buflen >= needed)
+ StrnCpy(p->structbuf, s ? s : "",
+ needed - 1);
+ }
+ break;
+ case 'z': /* offset to zero terminated string (4 byte) */
+ str = va_arg(args, char *);
+ stringneeded = (str ? strlen(str) + 1 : 0);
+ is_string = 1;
+ break;
+ case 'l': /* offset to user data (4 byte) */
+ str = va_arg(args, char *);
+ stringneeded = va_arg(args, int);
+ is_string = 0;
+ break;
+ case 'b': /* offset to data (with counter) (4 byte) */
+ str = va_arg(args, char *);
+ stringneeded = get_counter(&p->curpos);
+ is_string = 0;
+ break;
+ }
+ va_end(args);
+ if (stringneeded >= 0)
+ {
+ needed = 4;
+ if (p->buflen >= needed)
+ {
+ stringused = stringneeded;
+ if (stringused > p->stringlen)
+ {
+ stringused = (is_string ? p->stringlen : 0);
+ if (p->errcode == NERR_Success)
+ p->errcode = ERRmoredata;
+ }
+ if (!stringused)
+ SIVAL(p->structbuf, 0, 0);
+ else
+ {
+ SIVAL(p->structbuf, 0,
+ PTR_DIFF(p->stringbuf, p->base));
+ memcpy(p->stringbuf, str ? str : "",
+ stringused);
+ if (is_string)
+ p->stringbuf[stringused - 1] = '\0';
+ p->stringbuf += stringused;
+ p->stringlen -= stringused;
+ p->usedlen += stringused;
+ }
+ }
+ p->neededlen += stringneeded;
+ }
+ p->neededlen += needed;
+ if (p->buflen >= needed)
+ {
+ p->structbuf += needed;
+ p->buflen -= needed;
+ p->usedlen += needed;
+ }
+ else
+ {
+ if (p->errcode == NERR_Success)
+ p->errcode = ERRmoredata;
+ }
+ return 1;
}
#if CHECK_TYPES
@@ -347,14 +384,14 @@ va_dcl
#define PACKl(desc,t,v,l) package(desc,v,l)
#endif
-static void PACKI(struct pack_desc* desc,char *t,int v)
+static void PACKI(struct pack_desc *desc, char *t, int v)
{
- PACK(desc,t,v);
+ PACK(desc, t, v);
}
-static void PACKS(struct pack_desc* desc,char *t,char *v)
+static void PACKS(struct pack_desc *desc, char *t, char *v)
{
- PACK(desc,t,v);
+ PACK(desc, t, v);
}
@@ -362,538 +399,670 @@ static void PACKS(struct pack_desc* desc,char *t,char *v)
get a print queue
****************************************************************************/
-static void PackDriverData(struct pack_desc* desc)
+static void PackDriverData(struct pack_desc *desc)
{
- char drivdata[4+4+32];
- SIVAL(drivdata,0,sizeof drivdata); /* cb */
- SIVAL(drivdata,4,1000); /* lVersion */
- memset(drivdata+8,0,32); /* szDeviceName */
- pstrcpy(drivdata+8,"NULL");
- PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
+ char drivdata[4 + 4 + 32];
+ SIVAL(drivdata, 0, sizeof drivdata); /* cb */
+ SIVAL(drivdata, 4, 1000); /* lVersion */
+ memset(drivdata + 8, 0, 32); /* szDeviceName */
+ pstrcpy(drivdata + 8, "NULL");
+ PACKl(desc, "l", drivdata, sizeof drivdata); /* pDriverData */
}
-static int check_printq_info(struct pack_desc* desc,
- int uLevel, char *id1, char *id2)
+static int check_printq_info(struct pack_desc *desc,
+ int uLevel, char *id1, char *id2)
{
- desc->subformat = NULL;
- switch( uLevel ) {
- case 0:
- desc->format = "B13";
- break;
- case 1:
- desc->format = "B13BWWWzzzzzWW";
- break;
- case 2:
- desc->format = "B13BWWWzzzzzWN";
- desc->subformat = "WB21BB16B10zWWzDDz";
- break;
- case 3:
- desc->format = "zWWWWzzzzWWzzl";
- break;
- case 4:
- desc->format = "zWWWWzzzzWNzzl";
- desc->subformat = "WWzWWDDzz";
- break;
- case 5:
- desc->format = "z";
- break;
- case 52:
- desc->format = "WzzzzzzzzN";
- desc->subformat = "z";
- break;
- default: return False;
- }
- if (strcmp(desc->format,id1) != 0) return False;
- if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False;
- return True;
+ desc->subformat = NULL;
+ switch (uLevel)
+ {
+ case 0:
+ desc->format = "B13";
+ break;
+ case 1:
+ desc->format = "B13BWWWzzzzzWW";
+ break;
+ case 2:
+ desc->format = "B13BWWWzzzzzWN";
+ desc->subformat = "WB21BB16B10zWWzDDz";
+ break;
+ case 3:
+ desc->format = "zWWWWzzzzWWzzl";
+ break;
+ case 4:
+ desc->format = "zWWWWzzzzWNzzl";
+ desc->subformat = "WWzWWDDzz";
+ break;
+ case 5:
+ desc->format = "z";
+ break;
+ case 52:
+ desc->format = "WzzzzzzzzN";
+ desc->subformat = "z";
+ break;
+ default:
+ return False;
+ }
+ if (strcmp(desc->format, id1) != 0)
+ return False;
+ if (desc->subformat && strcmp(desc->subformat, id2) != 0)
+ return False;
+ return True;
}
-static void fill_printjob_info(connection_struct *conn,
- int snum, int uLevel,
- struct pack_desc* desc,
- print_queue_struct* queue, int n)
+static void fill_printjob_info(connection_struct * conn, int snum, int uLevel,
+ struct pack_desc *desc,
+ print_queue_struct * queue, int n)
{
- time_t t = queue->time;
-
- /* the client expects localtime */
- t -= TimeDiff(t);
-
- PACKI(desc,"W",printjob_encode(snum, queue->job)); /* uJobId */
- if (uLevel == 1) {
- PACKS(desc,"B21",queue->user); /* szUserName */
- PACKS(desc,"B",""); /* pad */
- PACKS(desc,"B16",""); /* szNotifyName */
- PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */
- PACKS(desc,"z",""); /* pszParms */
- PACKI(desc,"W",n+1); /* uPosition */
- PACKI(desc,"W",queue->status); /* fsStatus */
- PACKS(desc,"z",""); /* pszStatus */
- PACKI(desc,"D",t); /* ulSubmitted */
- PACKI(desc,"D",queue->size); /* ulSize */
- PACKS(desc,"z",queue->file); /* pszComment */
- }
- if (uLevel == 2 || uLevel == 3) {
- PACKI(desc,"W",queue->priority); /* uPriority */
- PACKS(desc,"z",queue->user); /* pszUserName */
- PACKI(desc,"W",n+1); /* uPosition */
- PACKI(desc,"W",queue->status); /* fsStatus */
- PACKI(desc,"D",t); /* ulSubmitted */
- PACKI(desc,"D",queue->size); /* ulSize */
- PACKS(desc,"z","Samba"); /* pszComment */
- PACKS(desc,"z",queue->file); /* pszDocument */
- if (uLevel == 3) {
- PACKS(desc,"z",""); /* pszNotifyName */
- PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */
- PACKS(desc,"z",""); /* pszParms */
- PACKS(desc,"z",""); /* pszStatus */
- PACKS(desc,"z",SERVICE(snum)); /* pszQueue */
- PACKS(desc,"z","lpd"); /* pszQProcName */
- PACKS(desc,"z",""); /* pszQProcParms */
- PACKS(desc,"z","NULL"); /* pszDriverName */
- PackDriverData(desc); /* pDriverData */
- PACKS(desc,"z",""); /* pszPrinterName */
- }
- }
+ time_t t = queue->time;
+
+ /* the client expects localtime */
+ t -= TimeDiff(t);
+
+ PACKI(desc, "W", printjob_encode(snum, queue->job)); /* uJobId */
+ if (uLevel == 1)
+ {
+ PACKS(desc, "B21", queue->user); /* szUserName */
+ PACKS(desc, "B", ""); /* pad */
+ PACKS(desc, "B16", ""); /* szNotifyName */
+ PACKS(desc, "B10", "PM_Q_RAW"); /* szDataType */
+ PACKS(desc, "z", ""); /* pszParms */
+ PACKI(desc, "W", n + 1); /* uPosition */
+ PACKI(desc, "W", queue->status); /* fsStatus */
+ PACKS(desc, "z", ""); /* pszStatus */
+ PACKI(desc, "D", t); /* ulSubmitted */
+ PACKI(desc, "D", queue->size); /* ulSize */
+ PACKS(desc, "z", queue->file); /* pszComment */
+ }
+ if (uLevel == 2 || uLevel == 3)
+ {
+ PACKI(desc, "W", queue->priority); /* uPriority */
+ PACKS(desc, "z", queue->user); /* pszUserName */
+ PACKI(desc, "W", n + 1); /* uPosition */
+ PACKI(desc, "W", queue->status); /* fsStatus */
+ PACKI(desc, "D", t); /* ulSubmitted */
+ PACKI(desc, "D", queue->size); /* ulSize */
+ PACKS(desc, "z", "Samba"); /* pszComment */
+ PACKS(desc, "z", queue->file); /* pszDocument */
+ if (uLevel == 3)
+ {
+ PACKS(desc, "z", ""); /* pszNotifyName */
+ PACKS(desc, "z", "PM_Q_RAW"); /* pszDataType */
+ PACKS(desc, "z", ""); /* pszParms */
+ PACKS(desc, "z", ""); /* pszStatus */
+ PACKS(desc, "z", SERVICE(snum)); /* pszQueue */
+ PACKS(desc, "z", "lpd"); /* pszQProcName */
+ PACKS(desc, "z", ""); /* pszQProcParms */
+ PACKS(desc, "z", "NULL"); /* pszDriverName */
+ PackDriverData(desc); /* pDriverData */
+ PACKS(desc, "z", ""); /* pszPrinterName */
+ }
+ }
}
-static void fill_printq_info(connection_struct *conn, const vuser_key *key,
- int snum, int uLevel,
- struct pack_desc* desc,
- int count, print_queue_struct* queue,
- print_status_struct* status)
+static void fill_printq_info(connection_struct * conn, const vuser_key * key,
+ int snum, int uLevel, struct pack_desc *desc,
+ int count, print_queue_struct * queue,
+ print_status_struct * status)
{
- switch (uLevel) {
- case 1:
- case 2:
- PACKS(desc,"B13",SERVICE(snum));
- break;
- case 3:
- case 4:
- case 5:
- PACKS(desc,"z",Expand(conn,key, snum,SERVICE(snum)));
- break;
- }
-
- if (uLevel == 1 || uLevel == 2) {
- PACKS(desc,"B",""); /* alignment */
- PACKI(desc,"W",5); /* priority */
- PACKI(desc,"W",0); /* start time */
- PACKI(desc,"W",0); /* until time */
- PACKS(desc,"z",""); /* pSepFile */
- PACKS(desc,"z","lpd"); /* pPrProc */
- PACKS(desc,"z",SERVICE(snum)); /* pDestinations */
- PACKS(desc,"z",""); /* pParms */
- if (snum < 0) {
- PACKS(desc,"z","UNKNOWN PRINTER");
- PACKI(desc,"W",LPSTAT_ERROR);
- }
- else if (!status || !status->message[0]) {
- PACKS(desc,"z",Expand(conn,key, snum,lp_comment(snum)));
- PACKI(desc,"W",LPSTAT_OK); /* status */
- } else {
- PACKS(desc,"z",status->message);
- PACKI(desc,"W",status->status); /* status */
- }
- PACKI(desc,(uLevel == 1 ? "W" : "N"),count);
- }
- if (uLevel == 3 || uLevel == 4) {
- PACKI(desc,"W",5); /* uPriority */
- PACKI(desc,"W",0); /* uStarttime */
- PACKI(desc,"W",0); /* uUntiltime */
- PACKI(desc,"W",5); /* pad1 */
- PACKS(desc,"z",""); /* pszSepFile */
- PACKS(desc,"z","WinPrint"); /* pszPrProc */
- PACKS(desc,"z",""); /* pszParms */
- if (!status || !status->message[0]) {
- PACKS(desc,"z",Expand(conn,key, snum,lp_comment(snum))); /* pszComment */
- PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
- } else {
- PACKS(desc,"z",status->message); /* pszComment */
- PACKI(desc,"W",status->status); /* fsStatus */
- }
- PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
- PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
- PACKS(desc,"z",lp_printerdriver(snum)); /* pszDriverName */
- PackDriverData(desc); /* pDriverData */
- }
- if (uLevel == 2 || uLevel == 4) {
- int i;
- for (i=0;i<count;i++)
- fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
- }
-
- if (uLevel==52) {
- int i,ok=0;
- pstring tok,driver,datafile,langmon,helpfile,datatype;
- char *p,*q;
- FILE *f;
- pstring fname;
-
- pstrcpy(fname,lp_driverfile());
- f=sys_fopen(fname,"r");
- if (!f) {
- DEBUG(3,("fill_printq_info: Can't open %s - %s\n",fname,strerror(errno)));
- desc->errcode=NERR_notsupported;
- return;
- }
-
- if ((p=(char *)malloc(8192*sizeof(char))) == NULL) {
- DEBUG(0,("fill_printq_info: malloc fail !\n"));
- desc->errcode=NERR_notsupported;
- fclose(f);
- return;
- }
-
- memset(p, 0, 8192*sizeof(char));
- q=p;
-
- /* lookup the long printer driver name in the file description */
- while (f && !feof(f) && !ok)
- {
- p = q; /* reset string pointer */
- fgets(p,8191,f);
- p[strlen(p)-1]='\0';
- if (next_token(&p,tok,":",sizeof(tok)) &&
- (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
- (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
- ok=1;
- }
- fclose(f);
-
- /* driver file name */
- if (ok && !next_token(&p,driver,":",sizeof(driver))) ok = 0;
- /* data file name */
- if (ok && !next_token(&p,datafile,":",sizeof(datafile))) ok = 0;
- /*
- * for the next tokens - which may be empty - I have to check for empty
- * tokens first because the next_token function will skip all empty
- * token fields
- */
- if (ok) {
- /* help file */
- if (*p == ':') {
- *helpfile = '\0';
- p++;
- } else if (!next_token(&p,helpfile,":",sizeof(helpfile))) ok = 0;
- }
-
- if (ok) {
- /* language monitor */
- if (*p == ':') {
- *langmon = '\0';
- p++;
- } else if (!next_token(&p,langmon,":",sizeof(langmon))) ok = 0;
- }
-
- /* default data type */
- if (ok && !next_token(&p,datatype,":",sizeof(datatype))) ok = 0;
-
- if (ok) {
- PACKI(desc,"W",0x0400); /* don't know */
- PACKS(desc,"z",lp_printerdriver(snum)); /* long printer name */
- PACKS(desc,"z",driver); /* Driverfile Name */
- PACKS(desc,"z",datafile); /* Datafile name */
- PACKS(desc,"z",langmon); /* language monitor */
- PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */
- PACKS(desc,"z",datatype); /* default data type */
- PACKS(desc,"z",helpfile); /* helpfile name */
- PACKS(desc,"z",driver); /* driver name */
- DEBUG(3,("Driver:%s:\n",driver));
- DEBUG(3,("Data File:%s:\n",datafile));
- DEBUG(3,("Language Monitor:%s:\n",langmon));
- DEBUG(3,("Data Type:%s:\n",datatype));
- DEBUG(3,("Help File:%s:\n",helpfile));
- PACKI(desc,"N",count); /* number of files to copy */
- for (i=0;i<count;i++)
- {
- /* no need to check return value here - it was already tested in
- * get_printerdrivernumber
- */
- next_token(&p,tok,",",sizeof(tok));
- PACKS(desc,"z",tok); /* driver files to copy */
- DEBUG(3,("file:%s:\n",tok));
- }
-
- DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
- SERVICE(snum),count));
- } else {
- DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
- desc->errcode=NERR_notsupported;
- }
- free(q);
- }
+ switch (uLevel)
+ {
+ case 1:
+ case 2:
+ PACKS(desc, "B13", SERVICE(snum));
+ break;
+ case 3:
+ case 4:
+ case 5:
+ PACKS(desc, "z",
+ Expand(conn, key, snum, SERVICE(snum)));
+ break;
+ }
+
+ if (uLevel == 1 || uLevel == 2)
+ {
+ PACKS(desc, "B", ""); /* alignment */
+ PACKI(desc, "W", 5); /* priority */
+ PACKI(desc, "W", 0); /* start time */
+ PACKI(desc, "W", 0); /* until time */
+ PACKS(desc, "z", ""); /* pSepFile */
+ PACKS(desc, "z", "lpd"); /* pPrProc */
+ PACKS(desc, "z", SERVICE(snum)); /* pDestinations */
+ PACKS(desc, "z", ""); /* pParms */
+ if (snum < 0)
+ {
+ PACKS(desc, "z", "UNKNOWN PRINTER");
+ PACKI(desc, "W", LPSTAT_ERROR);
+ }
+ else if (!status || !status->message[0])
+ {
+ PACKS(desc, "z",
+ Expand(conn, key, snum, lp_comment(snum)));
+ PACKI(desc, "W", LPSTAT_OK); /* status */
+ }
+ else
+ {
+ PACKS(desc, "z", status->message);
+ PACKI(desc, "W", status->status); /* status */
+ }
+ PACKI(desc, (uLevel == 1 ? "W" : "N"), count);
+ }
+ if (uLevel == 3 || uLevel == 4)
+ {
+ PACKI(desc, "W", 5); /* uPriority */
+ PACKI(desc, "W", 0); /* uStarttime */
+ PACKI(desc, "W", 0); /* uUntiltime */
+ PACKI(desc, "W", 5); /* pad1 */
+ PACKS(desc, "z", ""); /* pszSepFile */
+ PACKS(desc, "z", "WinPrint"); /* pszPrProc */
+ PACKS(desc, "z", ""); /* pszParms */
+ if (!status || !status->message[0])
+ {
+ PACKS(desc, "z", Expand(conn, key, snum, lp_comment(snum))); /* pszComment */
+ PACKI(desc, "W", LPSTAT_OK); /* fsStatus */
+ }
+ else
+ {
+ PACKS(desc, "z", status->message); /* pszComment */
+ PACKI(desc, "W", status->status); /* fsStatus */
+ }
+ PACKI(desc, (uLevel == 3 ? "W" : "N"), count); /* cJobs */
+ PACKS(desc, "z", SERVICE(snum)); /* pszPrinters */
+ PACKS(desc, "z", lp_printerdriver(snum)); /* pszDriverName */
+ PackDriverData(desc); /* pDriverData */
+ }
+ if (uLevel == 2 || uLevel == 4)
+ {
+ int i;
+ for (i = 0; i < count; i++)
+ fill_printjob_info(conn, snum, uLevel == 2 ? 1 : 2,
+ desc, &queue[i], i);
+ }
+
+ if (uLevel == 52)
+ {
+ int i, ok = 0;
+ pstring tok, driver, datafile, langmon, helpfile, datatype;
+ char *p, *q;
+ FILE *f;
+ pstring fname;
+
+ pstrcpy(fname, lp_driverfile());
+ f = sys_fopen(fname, "r");
+ if (!f)
+ {
+ DEBUG(3,
+ ("fill_printq_info: Can't open %s - %s\n",
+ fname, strerror(errno)));
+ desc->errcode = NERR_notsupported;
+ return;
+ }
+
+ if ((p = (char *)malloc(8192 * sizeof(char))) == NULL)
+ {
+ DEBUG(0, ("fill_printq_info: malloc fail !\n"));
+ desc->errcode = NERR_notsupported;
+ fclose(f);
+ return;
+ }
+
+ memset(p, 0, 8192 * sizeof(char));
+ q = p;
+
+ /* lookup the long printer driver name in the file description */
+ while (f && !feof(f) && !ok)
+ {
+ p = q; /* reset string pointer */
+ fgets(p, 8191, f);
+ p[strlen(p) - 1] = '\0';
+ if (next_token(&p, tok, ":", sizeof(tok)) &&
+ (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
+ (!strncmp(tok, lp_printerdriver(snum),
+ strlen(lp_printerdriver(snum)))))
+ ok = 1;
+ }
+ fclose(f);
+
+ /* driver file name */
+ if (ok && !next_token(&p, driver, ":", sizeof(driver)))
+ ok = 0;
+ /* data file name */
+ if (ok && !next_token(&p, datafile, ":", sizeof(datafile)))
+ ok = 0;
+ /*
+ * for the next tokens - which may be empty - I have to check for empty
+ * tokens first because the next_token function will skip all empty
+ * token fields
+ */
+ if (ok)
+ {
+ /* help file */
+ if (*p == ':')
+ {
+ *helpfile = '\0';
+ p++;
+ }
+ else
+ if (!next_token
+ (&p, helpfile, ":",
+ sizeof(helpfile))) ok = 0;
+ }
+
+ if (ok)
+ {
+ /* language monitor */
+ if (*p == ':')
+ {
+ *langmon = '\0';
+ p++;
+ }
+ else
+ if (!next_token
+ (&p, langmon, ":", sizeof(langmon))) ok =
+ 0;
+ }
+
+ /* default data type */
+ if (ok && !next_token(&p, datatype, ":", sizeof(datatype)))
+ ok = 0;
+
+ if (ok)
+ {
+ PACKI(desc, "W", 0x0400); /* don't know */
+ PACKS(desc, "z", lp_printerdriver(snum)); /* long printer name */
+ PACKS(desc, "z", driver); /* Driverfile Name */
+ PACKS(desc, "z", datafile); /* Datafile name */
+ PACKS(desc, "z", langmon); /* language monitor */
+ PACKS(desc, "z", lp_driverlocation(snum)); /* share to retrieve files */
+ PACKS(desc, "z", datatype); /* default data type */
+ PACKS(desc, "z", helpfile); /* helpfile name */
+ PACKS(desc, "z", driver); /* driver name */
+ DEBUG(3, ("Driver:%s:\n", driver));
+ DEBUG(3, ("Data File:%s:\n", datafile));
+ DEBUG(3, ("Language Monitor:%s:\n", langmon));
+ DEBUG(3, ("Data Type:%s:\n", datatype));
+ DEBUG(3, ("Help File:%s:\n", helpfile));
+ PACKI(desc, "N", count); /* number of files to copy */
+ for (i = 0; i < count; i++)
+ {
+ /* no need to check return value here - it was already tested in
+ * get_printerdrivernumber
+ */
+ next_token(&p, tok, ",", sizeof(tok));
+ PACKS(desc, "z", tok); /* driver files to copy */
+ DEBUG(3, ("file:%s:\n", tok));
+ }
+
+ DEBUG(3,
+ ("fill_printq_info on <%s> gave %d entries\n",
+ SERVICE(snum), count));
+ }
+ else
+ {
+ DEBUG(3,
+ ("fill_printq_info: Can't supply driver files\n"));
+ desc->errcode = NERR_notsupported;
+ }
+ free(q);
+ }
}
/* This function returns the number of files for a given driver */
static int get_printerdrivernumber(int snum)
{
- int i=0,ok=0;
- pstring tok;
- char *p,*q;
- FILE *f;
- pstring fname;
-
- pstrcpy(fname,lp_driverfile());
-
- DEBUG(4,("In get_printerdrivernumber: %s\n",fname));
- f=sys_fopen(fname,"r");
- if (!f) {
- DEBUG(3,("get_printerdrivernumber: Can't open %s - %s\n",fname,strerror(errno)));
- return(0);
- }
-
- if ((p=(char *)malloc(8192*sizeof(char))) == NULL) {
- DEBUG(3,("get_printerdrivernumber: malloc fail !\n"));
- fclose(f);
- return 0;
- }
-
- q=p; /* need it to free memory because p change ! */
-
- /* lookup the long printer driver name in the file description */
- while (!feof(f) && !ok)
- {
- p = q; /* reset string pointer */
- fgets(p,8191,f);
- if (next_token(&p,tok,":",sizeof(tok)) &&
- (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
- ok=1;
- }
- fclose(f);
-
- if (ok) {
- /* skip 5 fields */
- i = 5;
- while (*p && i) {
- if (*p++ == ':') i--;
- }
- if (!*p || i)
- return(0);
-
- /* count the number of files */
- while (next_token(&p,tok,",",sizeof(tok)))
- i++;
- }
- free(q);
-
- return(i);
+ int i = 0, ok = 0;
+ pstring tok;
+ char *p, *q;
+ FILE *f;
+ pstring fname;
+
+ pstrcpy(fname, lp_driverfile());
+
+ DEBUG(4, ("In get_printerdrivernumber: %s\n", fname));
+ f = sys_fopen(fname, "r");
+ if (!f)
+ {
+ DEBUG(3,
+ ("get_printerdrivernumber: Can't open %s - %s\n", fname,
+ strerror(errno)));
+ return (0);
+ }
+
+ if ((p = (char *)malloc(8192 * sizeof(char))) == NULL)
+ {
+ DEBUG(3, ("get_printerdrivernumber: malloc fail !\n"));
+ fclose(f);
+ return 0;
+ }
+
+ q = p; /* need it to free memory because p change ! */
+
+ /* lookup the long printer driver name in the file description */
+ while (!feof(f) && !ok)
+ {
+ p = q; /* reset string pointer */
+ fgets(p, 8191, f);
+ if (next_token(&p, tok, ":", sizeof(tok)) &&
+ (!strncmp
+ (tok, lp_printerdriver(snum),
+ strlen(lp_printerdriver(snum)))))
+ ok = 1;
+ }
+ fclose(f);
+
+ if (ok)
+ {
+ /* skip 5 fields */
+ i = 5;
+ while (*p && i)
+ {
+ if (*p++ == ':')
+ i--;
+ }
+ if (!*p || i)
+ return (0);
+
+ /* count the number of files */
+ while (next_token(&p, tok, ",", sizeof(tok)))
+ i++;
+ }
+ free(q);
+
+ return (i);
}
-static BOOL api_DosPrintQGetInfo(connection_struct *conn,
- uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_DosPrintQGetInfo(connection_struct * conn,
+ uint16 vuid, char *param, char *data,
+ int mdrcnt, int mprcnt,
+ char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- char *QueueName = p;
- int uLevel;
- int count=0;
- int snum;
- char* str3;
- struct pack_desc desc;
- print_queue_struct *queue=NULL;
- print_status_struct status;
-
- VUSER_KEY;
-
- ZERO_STRUCT(status);
- ZERO_STRUCT(desc);
-
- p = skip_string(p,1);
- uLevel = SVAL(p,0);
- str3 = p + 4;
-
- /* remove any trailing username */
- if ((p = strchr(QueueName,'%'))) *p = 0;
-
- DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
-
- /* check it's a supported varient */
- if (!prefix_ok(str1,"zWrLh")) return False;
- if (!check_printq_info(&desc,uLevel,str2,str3)) return False;
-
- snum = lp_servicenumber(QueueName);
- if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
- int pnum = lp_servicenumber(PRINTERS_NAME);
- if (pnum >= 0) {
- lp_add_printer(QueueName,pnum);
- snum = lp_servicenumber(QueueName);
- }
- }
-
- if (snum < 0 || !VALID_SNUM(snum)) return(False);
-
- if (uLevel==52) {
- count = get_printerdrivernumber(snum);
- DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
- } else {
- count = get_printqueue(snum, conn,&key,&queue,&status);
- }
-
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- if (init_package(&desc,1,count)) {
- desc.subcount = count;
- fill_printq_info(conn,&key,snum,uLevel,&desc,count,queue,&status);
- } else if (uLevel == 0) {
- /*
- * This is a *disgusting* hack.
- * This is *so* bad that even I'm embarrassed (and I
- * have no shame). Here's the deal :
- * Until we get the correct SPOOLSS code into smbd
- * then when we're running with NT SMB support then
- * NT makes this call with a level of zero, and then
- * immediately follows it with an open request to
- * the \\SRVSVC pipe. If we allow that open to
- * succeed then NT barfs when it cannot open the
- * \\SPOOLSS pipe immediately after and continually
- * whines saying "Printer name is invalid" forever
- * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
- * to fail, then NT downgrades to using the downlevel code
- * and everything works as well as before. I hate
- * myself for adding this code.... JRA.
- */
-
- fail_next_srvsvc_open();
- }
-
- *rdata_len = desc.usedlen;
-
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,desc.neededlen);
-
- DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
-
- if (queue) free(queue);
-
- return(True);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ char *QueueName = p;
+ int uLevel;
+ int count = 0;
+ int snum;
+ char *str3;
+ struct pack_desc desc;
+ print_queue_struct *queue = NULL;
+ print_status_struct status;
+
+ VUSER_KEY;
+
+ ZERO_STRUCT(status);
+ ZERO_STRUCT(desc);
+
+ p = skip_string(p, 1);
+ uLevel = SVAL(p, 0);
+ str3 = p + 4;
+
+ /* remove any trailing username */
+ if ((p = strchr(QueueName, '%')))
+ *p = 0;
+
+ DEBUG(3, ("PrintQueue uLevel=%d name=%s\n", uLevel, QueueName));
+
+ /* check it's a supported varient */
+ if (!prefix_ok(str1, "zWrLh"))
+ return False;
+ if (!check_printq_info(&desc, uLevel, str2, str3))
+ {
+ /*
+ * 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))
+ {
+ int pnum = lp_servicenumber(PRINTERS_NAME);
+ if (pnum >= 0)
+ {
+ lp_add_printer(QueueName, pnum);
+ snum = lp_servicenumber(QueueName);
+ }
+ }
+
+ if (snum < 0 || !VALID_SNUM(snum))
+ return (False);
+
+ if (uLevel == 52)
+ {
+ count = get_printerdrivernumber(snum);
+ DEBUG(3,
+ ("api_DosPrintQGetInfo: Driver files count: %d\n",
+ count));
+ }
+ else
+ {
+ count = get_printqueue(snum, conn, &key, &queue, &status);
+ }
+
+ if (mdrcnt > 0)
+ *rdata = REALLOC(*rdata, mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ if (init_package(&desc, 1, count))
+ {
+ desc.subcount = count;
+ fill_printq_info(conn, &key, snum, uLevel, &desc, count,
+ queue, &status);
+ }
+ else if (uLevel == 0)
+ {
+ /*
+ * This is a *disgusting* hack.
+ * This is *so* bad that even I'm embarrassed (and I
+ * have no shame). Here's the deal :
+ * Until we get the correct SPOOLSS code into smbd
+ * then when we're running with NT SMB support then
+ * NT makes this call with a level of zero, and then
+ * immediately follows it with an open request to
+ * the \\SRVSVC pipe. If we allow that open to
+ * succeed then NT barfs when it cannot open the
+ * \\SPOOLSS pipe immediately after and continually
+ * whines saying "Printer name is invalid" forever
+ * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
+ * to fail, then NT downgrades to using the downlevel code
+ * and everything works as well as before. I hate
+ * myself for adding this code.... JRA.
+ */
+
+ fail_next_srvsvc_open();
+ }
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVALS(*rparam, 0, desc.errcode);
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, desc.neededlen);
+
+ DEBUG(4, ("printqgetinfo: errorcode %d\n", desc.errcode));
+
+ if (queue)
+ free(queue);
+
+ return (True);
}
/****************************************************************************
view list of all print jobs on all queues
****************************************************************************/
-static BOOL api_DosPrintQEnum(connection_struct *conn, uint16 vuid, char* param, char* data,
- int mdrcnt, int mprcnt,
- char **rdata, char** rparam,
- int *rdata_len, int *rparam_len)
+static BOOL api_DosPrintQEnum(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt, int mprcnt,
+ char **rdata, char **rparam, int *rdata_len,
+ int *rparam_len)
{
- char *param_format = param+2;
- char *output_format1 = skip_string(param_format,1);
- char *p = skip_string(output_format1,1);
- int uLevel = SVAL(p,0);
- char *output_format2 = p + 4;
- int services = lp_numservices();
- int i, n;
- struct pack_desc desc;
- print_queue_struct **queue = NULL;
- print_status_struct *status = NULL;
- int* subcntarr = NULL;
- int queuecnt, subcnt=0, succnt=0;
+ char *param_format = param + 2;
+ char *output_format1 = skip_string(param_format, 1);
+ char *p = skip_string(output_format1, 1);
+ int uLevel = SVAL(p, 0);
+ char *output_format2 = p + 4;
+ int services = lp_numservices();
+ int i, n;
+ struct pack_desc desc;
+ print_queue_struct **queue = NULL;
+ print_status_struct *status = NULL;
+ int *subcntarr = NULL;
+ int queuecnt, subcnt = 0, succnt = 0;
VUSER_KEY;
-
- ZERO_STRUCT(desc);
-
- DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
-
- if (!prefix_ok(param_format,"WrLeh")) return False;
- if (!check_printq_info(&desc,uLevel,output_format1,output_format2))
- return False;
- queuecnt = 0;
- for (i = 0; i < services; i++)
- if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
- queuecnt++;
- if (uLevel > 0) {
- if ((queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*))) == NULL) {
- DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
- return False;
- }
- memset(queue,0,queuecnt*sizeof(print_queue_struct*));
- if ((status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct))) == NULL) {
- DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
- return False;
- }
- memset(status,0,queuecnt*sizeof(print_status_struct));
- if ((subcntarr = (int*)malloc(queuecnt*sizeof(int))) == NULL) {
- DEBUG(0,("api_DosPrintQEnum: malloc fail !\n"));
- return False;
- }
- subcnt = 0;
- n = 0;
- for (i = 0; i < services; i++)
- if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
- subcntarr[n] = get_printqueue(i, conn, &key, &queue[n],&status[n]);
- subcnt += subcntarr[n];
- n++;
- }
- }
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
-
- if (init_package(&desc,queuecnt,subcnt)) {
- n = 0;
- succnt = 0;
- for (i = 0; i < services; i++)
- if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
- fill_printq_info(conn,&key, i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
- n++;
- if (desc.errcode == NERR_Success) succnt = n;
- }
- }
-
- if (subcntarr) free(subcntarr);
-
- *rdata_len = desc.usedlen;
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,succnt);
- SSVAL(*rparam,6,queuecnt);
-
- for (i = 0; i < queuecnt; i++) {
- if (queue && queue[i]) free(queue[i]);
- }
-
- if (queue) free(queue);
- if (status) free(status);
-
- return True;
+
+ ZERO_STRUCT(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))
+ {
+ /*
+ * 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))
+ queuecnt++;
+ if (uLevel > 0)
+ {
+ if (
+ (queue =
+ (print_queue_struct **) malloc(queuecnt *
+ sizeof(print_queue_struct
+ *))) == NULL)
+ {
+ DEBUG(0, ("api_DosPrintQEnum: malloc fail !\n"));
+ return False;
+ }
+ memset(queue, 0, queuecnt * sizeof(print_queue_struct *));
+ if (
+ (status =
+ (print_status_struct *) malloc(queuecnt *
+ sizeof
+ (print_status_struct))) ==
+ NULL)
+ {
+ DEBUG(0, ("api_DosPrintQEnum: malloc fail !\n"));
+ return False;
+ }
+ memset(status, 0, queuecnt * sizeof(print_status_struct));
+ if ((subcntarr = (int *)malloc(queuecnt * sizeof(int))) ==
+ NULL)
+ {
+ DEBUG(0, ("api_DosPrintQEnum: malloc fail !\n"));
+ return False;
+ }
+ subcnt = 0;
+ n = 0;
+ for (i = 0; i < services; i++)
+ if (lp_snum_ok(i) && lp_print_ok(i)
+ && lp_browseable(i))
+ {
+ subcntarr[n] =
+ get_printqueue(i, conn, &key,
+ &queue[n], &status[n]);
+ subcnt += subcntarr[n];
+ n++;
+ }
+ }
+ if (mdrcnt > 0)
+ *rdata = REALLOC(*rdata, mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+
+ if (init_package(&desc, queuecnt, subcnt))
+ {
+ n = 0;
+ succnt = 0;
+ for (i = 0; i < services; i++)
+ if (lp_snum_ok(i) && lp_print_ok(i)
+ && lp_browseable(i))
+ {
+ fill_printq_info(conn, &key, i, uLevel, &desc,
+ subcntarr[n], queue[n],
+ &status[n]);
+ n++;
+ if (desc.errcode == NERR_Success)
+ succnt = n;
+ }
+ }
+
+ if (subcntarr)
+ free(subcntarr);
+
+ *rdata_len = desc.usedlen;
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVALS(*rparam, 0, desc.errcode);
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, succnt);
+ SSVAL(*rparam, 6, queuecnt);
+
+ for (i = 0; i < queuecnt; i++)
+ {
+ if (queue && queue[i])
+ free(queue[i]);
+ }
+
+ if (queue)
+ free(queue);
+ if (status)
+ free(status);
+
+ return True;
}
/****************************************************************************
get info level for a server list query
****************************************************************************/
-static BOOL check_server_info(int uLevel, char* id)
+static BOOL check_server_info(int uLevel, char *id)
{
- switch( uLevel ) {
- case 0:
- if (strcmp(id,"B16") != 0) return False;
- break;
- case 1:
- if (strcmp(id,"B16BBDz") != 0) return False;
- break;
- default:
- return False;
- }
- return True;
+ switch (uLevel)
+ {
+ case 0:
+ if (strcmp(id, "B16") != 0)
+ return False;
+ break;
+ case 1:
+ if (strcmp(id, "B16BBDz") != 0)
+ return False;
+ break;
+ default:
+ return False;
+ }
+ return True;
}
struct srv_info_struct
{
- fstring name;
- uint32 type;
- fstring comment;
- fstring domain;
- BOOL server_added;
+ fstring name;
+ uint32 type;
+ fstring comment;
+ fstring domain;
+ BOOL server_added;
};
@@ -901,580 +1070,664 @@ struct srv_info_struct
get server info lists from the files saved by nmbd. Return the
number of entries
******************************************************************/
-static int get_server_info(uint32 servertype,
- struct srv_info_struct **servers,
- char *domain)
+static int get_server_info(uint32 servertype,
+ struct srv_info_struct **servers, char *domain)
{
- FILE *f;
- pstring fname;
- int count=0;
- int alloced=0;
- pstring line;
- BOOL local_list_only;
-
- pstrcpy(fname,lp_lockdir());
- trim_string(fname,NULL,"/");
- pstrcat(fname,"/");
- pstrcat(fname,SERVER_LIST);
-
- f = sys_fopen(fname,"r");
-
- if (!f) {
- DEBUG(4,("Can't open %s - %s\n",fname,strerror(errno)));
- return(0);
- }
-
- /* request for everything is code for request all servers */
- if (servertype == SV_TYPE_ALL)
- servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
-
- local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
-
- DEBUG(4,("Servertype search: %8x\n",servertype));
-
- while (!feof(f))
- {
- fstring stype;
- struct srv_info_struct *s;
- char *ptr = line;
- BOOL ok = True;
- *ptr = 0;
-
- fgets(line,sizeof(line)-1,f);
- if (!*line) continue;
-
- if (count == alloced) {
- alloced += 10;
- (*servers) = (struct srv_info_struct *)
- Realloc(*servers,sizeof(**servers)*alloced);
- if (!(*servers)) return(0);
- memset((char *)((*servers)+count), 0, sizeof(**servers)*(alloced-count));
- }
- s = &(*servers)[count];
-
- if (!next_token(&ptr,s->name , NULL, sizeof(s->name))) continue;
- if (!next_token(&ptr,stype , NULL, sizeof(stype))) continue;
- if (!next_token(&ptr,s->comment, NULL, sizeof(s->comment))) continue;
- if (!next_token(&ptr,s->domain , NULL, sizeof(s->domain))) {
- /* this allows us to cope with an old nmbd */
- pstrcpy(s->domain,global_myworkgroup);
- }
-
- if (sscanf(stype,"%X",&s->type) != 1) {
- DEBUG(4,("r:host file "));
- ok = False;
- }
-
- /* Filter the servers/domains we return based on what was asked for. */
-
- /* Check to see if we are being asked for a local list only. */
- if (local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
- DEBUG(4,("r: local list only"));
- ok = False;
- }
-
- /* doesn't match up: don't want it */
- if (!(servertype & s->type)) {
- DEBUG(4,("r:serv type "));
- ok = False;
- }
-
- if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
- (s->type & SV_TYPE_DOMAIN_ENUM))
- {
- DEBUG(4,("s: dom mismatch "));
- ok = False;
- }
-
- if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
- {
- ok = False;
- }
-
- /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
- s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
-
- if (ok)
- {
- DEBUG(4,("**SV** %20s %8x %25s %15s\n",
- s->name, s->type, s->comment, s->domain));
-
- s->server_added = True;
- count++;
- }
- else
- {
- DEBUG(4,("%20s %8x %25s %15s\n",
- s->name, s->type, s->comment, s->domain));
- }
- }
-
- fclose(f);
- return(count);
+ FILE *f;
+ pstring fname;
+ int count = 0;
+ int alloced = 0;
+ pstring line;
+ BOOL local_list_only;
+
+ pstrcpy(fname, lp_lockdir());
+ trim_string(fname, NULL, "/");
+ pstrcat(fname, "/");
+ pstrcat(fname, SERVER_LIST);
+
+ f = sys_fopen(fname, "r");
+
+ if (!f)
+ {
+ DEBUG(4, ("Can't open %s - %s\n", fname, strerror(errno)));
+ return (0);
+ }
+
+ /* request for everything is code for request all servers */
+ if (servertype == SV_TYPE_ALL)
+ servertype &=
+ ~(SV_TYPE_DOMAIN_ENUM | SV_TYPE_LOCAL_LIST_ONLY);
+
+ local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
+
+ DEBUG(4, ("Servertype search: %8x\n", servertype));
+
+ while (!feof(f))
+ {
+ fstring stype;
+ struct srv_info_struct *s;
+ char *ptr = line;
+ BOOL ok = True;
+ *ptr = 0;
+
+ fgets(line, sizeof(line) - 1, f);
+ if (!*line)
+ continue;
+
+ if (count == alloced)
+ {
+ alloced += 10;
+ (*servers) = (struct srv_info_struct *)Realloc
+ (*servers, sizeof(**servers) * alloced);
+ if (!(*servers))
+ return (0);
+ memset((char *)((*servers) + count), 0,
+ sizeof(**servers) * (alloced - count));
+ }
+ s = &(*servers)[count];
+
+ if (!next_token(&ptr, s->name, NULL, sizeof(s->name)))
+ continue;
+ if (!next_token(&ptr, stype, NULL, sizeof(stype)))
+ continue;
+ if (!next_token(&ptr, s->comment, NULL, sizeof(s->comment)))
+ continue;
+ if (!next_token(&ptr, s->domain, NULL, sizeof(s->domain)))
+ {
+ /* this allows us to cope with an old nmbd */
+ pstrcpy(s->domain, global_myworkgroup);
+ }
+
+ if (sscanf(stype, "%X", &s->type) != 1)
+ {
+ DEBUG(4, ("r:host file "));
+ ok = False;
+ }
+
+ /* Filter the servers/domains we return based on what was asked for. */
+
+ /* Check to see if we are being asked for a local list only. */
+ if (local_list_only
+ && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0))
+ {
+ DEBUG(4, ("r: local list only"));
+ ok = False;
+ }
+
+ /* doesn't match up: don't want it */
+ if (!(servertype & s->type))
+ {
+ DEBUG(4, ("r:serv type "));
+ ok = False;
+ }
+
+ if ((servertype & SV_TYPE_DOMAIN_ENUM) !=
+ (s->type & SV_TYPE_DOMAIN_ENUM))
+ {
+ DEBUG(4, ("s: dom mismatch "));
+ ok = False;
+ }
+
+ if (!strequal(domain, s->domain)
+ && !(servertype & SV_TYPE_DOMAIN_ENUM))
+ {
+ ok = False;
+ }
+
+ /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
+ s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ if (ok)
+ {
+ DEBUG(4, ("**SV** %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+
+ s->server_added = True;
+ count++;
+ }
+ else
+ {
+ DEBUG(4, ("%20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+ }
+ }
+
+ fclose(f);
+ return (count);
}
/*******************************************************************
fill in a server info structure
******************************************************************/
-static int fill_srv_info(struct srv_info_struct *service,
- int uLevel, char **buf, int *buflen,
+static int fill_srv_info(struct srv_info_struct *service,
+ int uLevel, char **buf, int *buflen,
char **stringbuf, int *stringspace, char *baseaddr)
{
- int struct_len;
- char* p;
- char* p2;
- int l2;
- int len;
-
- switch (uLevel) {
- case 0: struct_len = 16; break;
- case 1: struct_len = 26; break;
- default: return -1;
- }
-
- if (!buf)
- {
- len = 0;
- switch (uLevel)
- {
- case 1:
- len = strlen(service->comment)+1;
- break;
- }
-
- if (buflen) *buflen = struct_len;
- if (stringspace) *stringspace = len;
- return struct_len + len;
- }
-
- len = struct_len;
- p = *buf;
- if (*buflen < struct_len) return -1;
- if (stringbuf)
- {
- p2 = *stringbuf;
- l2 = *stringspace;
- }
- else
- {
- p2 = p + struct_len;
- l2 = *buflen - struct_len;
- }
- if (!baseaddr) baseaddr = p;
-
- switch (uLevel)
- {
- case 0:
- StrnCpy(p,service->name,15);
- break;
-
- case 1:
- StrnCpy(p,service->name,15);
- SIVAL(p,18,service->type);
- SIVAL(p,22,PTR_DIFF(p2,baseaddr));
- len += CopyAndAdvance(&p2,service->comment,&l2);
- break;
- }
-
- if (stringbuf)
- {
- *buf = p + struct_len;
- *buflen -= struct_len;
- *stringbuf = p2;
- *stringspace = l2;
- }
- else
- {
- *buf = p2;
- *buflen -= len;
- }
- return len;
+ int struct_len;
+ char *p;
+ char *p2;
+ int l2;
+ int len;
+
+ switch (uLevel)
+ {
+ case 0:
+ struct_len = 16;
+ break;
+ case 1:
+ struct_len = 26;
+ break;
+ default:
+ return -1;
+ }
+
+ if (!buf)
+ {
+ len = 0;
+ switch (uLevel)
+ {
+ case 1:
+ len = strlen(service->comment) + 1;
+ break;
+ }
+
+ if (buflen)
+ *buflen = struct_len;
+ if (stringspace)
+ *stringspace = len;
+ return struct_len + len;
+ }
+
+ len = struct_len;
+ p = *buf;
+ if (*buflen < struct_len)
+ return -1;
+ if (stringbuf)
+ {
+ p2 = *stringbuf;
+ l2 = *stringspace;
+ }
+ else
+ {
+ p2 = p + struct_len;
+ l2 = *buflen - struct_len;
+ }
+ if (!baseaddr)
+ baseaddr = p;
+
+ switch (uLevel)
+ {
+ case 0:
+ StrnCpy(p, service->name, 15);
+ break;
+
+ case 1:
+ StrnCpy(p, service->name, 15);
+ SIVAL(p, 18, service->type);
+ SIVAL(p, 22, PTR_DIFF(p2, baseaddr));
+ len += CopyAndAdvance(&p2, service->comment, &l2);
+ break;
+ }
+
+ if (stringbuf)
+ {
+ *buf = p + struct_len;
+ *buflen -= struct_len;
+ *stringbuf = p2;
+ *stringspace = l2;
+ }
+ else
+ {
+ *buf = p2;
+ *buflen -= len;
+ }
+ return len;
}
-static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
+static BOOL srv_comp(struct srv_info_struct *s1, struct srv_info_struct *s2)
{
- return(strcmp(s1->name,s2->name));
+ return (strcmp(s1->name, s2->name));
}
/****************************************************************************
view list of servers available (or possibly domains). The info is
extracted from lists saved by nmbd on the local host
****************************************************************************/
-static BOOL api_RNetServerEnum(connection_struct *conn, uint16 vuid, char *param, char *data,
- int mdrcnt, int mprcnt, char **rdata,
- char **rparam, int *rdata_len, int *rparam_len)
+static BOOL api_RNetServerEnum(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel = SVAL(p,0);
- int buf_len = SVAL(p,2);
- uint32 servertype = IVAL(p,4);
- char *p2;
- int data_len, fixed_len, string_len;
- int f_len = 0, s_len = 0;
- struct srv_info_struct *servers=NULL;
- int counted=0,total=0;
- int i,missed;
- fstring domain;
- BOOL domain_request;
- BOOL local_request;
-
- /* If someone sets all the bits they don't really mean to set
- DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
- known servers. */
-
- if (servertype == SV_TYPE_ALL)
- servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
-
- /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
- any other bit (they may just set this bit on it's own) they
- want all the locally seen servers. However this bit can be
- set on its own so set the requested servers to be
- ALL - DOMAIN_ENUM. */
-
- if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
- servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
-
- domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
- local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
-
- p += 8;
-
- if (!prefix_ok(str1,"WrLehD")) return False;
- if (!check_server_info(uLevel,str2)) return False;
-
- DEBUG(4, ("server request level: %s %8x ", str2, servertype));
- DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
- DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
-
- if (strcmp(str1, "WrLehDz") == 0) {
- StrnCpy(domain, p, sizeof(fstring)-1);
- } else {
- StrnCpy(domain, global_myworkgroup, sizeof(fstring)-1);
- }
-
- if (lp_browse_list())
- total = get_server_info(servertype,&servers,domain);
-
- data_len = fixed_len = string_len = 0;
- missed = 0;
-
- qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
-
- {
- char *lastname=NULL;
-
- for (i=0;i<total;i++)
- {
- struct srv_info_struct *s = &servers[i];
- if (lastname && strequal(lastname,s->name)) continue;
- lastname = s->name;
- data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
- DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
- s->name, s->type, s->comment, s->domain));
-
- if (data_len <= buf_len) {
- counted++;
- fixed_len += f_len;
- string_len += s_len;
- } else {
- missed++;
- }
- }
- }
-
- *rdata_len = fixed_len + string_len;
- *rdata = REALLOC(*rdata,*rdata_len);
- memset(*rdata, 0, *rdata_len);
-
- p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
- p = *rdata;
- f_len = fixed_len;
- s_len = string_len;
-
- {
- char *lastname=NULL;
- int count2 = counted;
- for (i = 0; i < total && count2;i++)
- {
- struct srv_info_struct *s = &servers[i];
- if (lastname && strequal(lastname,s->name)) continue;
- lastname = s->name;
- fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
- DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
- s->name, s->type, s->comment, s->domain));
- count2--;
- }
- }
-
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,counted);
- SSVAL(*rparam,6,counted+missed);
-
- if (servers) free(servers);
-
- DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
- domain,uLevel,counted,counted+missed));
-
- return(True);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ int uLevel = SVAL(p, 0);
+ int buf_len = SVAL(p, 2);
+ uint32 servertype = IVAL(p, 4);
+ char *p2;
+ int data_len, fixed_len, string_len;
+ int f_len = 0, s_len = 0;
+ struct srv_info_struct *servers = NULL;
+ int counted = 0, total = 0;
+ int i, missed;
+ fstring domain;
+ BOOL domain_request;
+ BOOL local_request;
+
+ /* If someone sets all the bits they don't really mean to set
+ DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
+ known servers. */
+
+ if (servertype == SV_TYPE_ALL)
+ servertype &=
+ ~(SV_TYPE_DOMAIN_ENUM | SV_TYPE_LOCAL_LIST_ONLY);
+
+ /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
+ any other bit (they may just set this bit on it's own) they
+ want all the locally seen servers. However this bit can be
+ set on its own so set the requested servers to be
+ ALL - DOMAIN_ENUM. */
+
+ if ((servertype & SV_TYPE_LOCAL_LIST_ONLY)
+ && !(servertype & SV_TYPE_DOMAIN_ENUM))
+ servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
+
+ domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
+ local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
+
+ p += 8;
+
+ if (!prefix_ok(str1, "WrLehD"))
+ return False;
+ if (!check_server_info(uLevel, str2))
+ return False;
+
+ DEBUG(4, ("server request level: %s %8x ", str2, servertype));
+ DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
+ DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
+
+ if (strcmp(str1, "WrLehDz") == 0)
+ {
+ StrnCpy(domain, p, sizeof(fstring) - 1);
+ }
+ else
+ {
+ StrnCpy(domain, global_myworkgroup, sizeof(fstring) - 1);
+ }
+
+ if (lp_browse_list())
+ total = get_server_info(servertype, &servers, domain);
+
+ data_len = fixed_len = string_len = 0;
+ missed = 0;
+
+ qsort(servers, total, sizeof(servers[0]), QSORT_CAST srv_comp);
+
+ {
+ char *lastname = NULL;
+
+ for (i = 0; i < total; i++)
+ {
+ struct srv_info_struct *s = &servers[i];
+ if (lastname && strequal(lastname, s->name))
+ continue;
+ lastname = s->name;
+ data_len +=
+ fill_srv_info(s, uLevel, 0, &f_len, 0, &s_len,
+ 0);
+ DEBUG(4,
+ ("fill_srv_info %20s %8x %25s %15s\n", s->name,
+ s->type, s->comment, s->domain));
+
+ if (data_len <= buf_len)
+ {
+ counted++;
+ fixed_len += f_len;
+ string_len += s_len;
+ }
+ else
+ {
+ missed++;
+ }
+ }
+ }
+
+ *rdata_len = fixed_len + string_len;
+ *rdata = REALLOC(*rdata, *rdata_len);
+ memset(*rdata, 0, *rdata_len);
+
+ p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */
+ p = *rdata;
+ f_len = fixed_len;
+ s_len = string_len;
+
+ {
+ char *lastname = NULL;
+ int count2 = counted;
+ for (i = 0; i < total && count2; i++)
+ {
+ struct srv_info_struct *s = &servers[i];
+ if (lastname && strequal(lastname, s->name))
+ continue;
+ lastname = s->name;
+ fill_srv_info(s, uLevel, &p, &f_len, &p2, &s_len,
+ *rdata);
+ DEBUG(4,
+ ("fill_srv_info %20s %8x %25s %15s\n", s->name,
+ s->type, s->comment, s->domain));
+ count2--;
+ }
+ }
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVAL(*rparam, 0, (missed == 0 ? NERR_Success : ERRmoredata));
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, counted);
+ SSVAL(*rparam, 6, counted + missed);
+
+ if (servers)
+ free(servers);
+
+ DEBUG(3, ("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
+ domain, uLevel, counted, counted + missed));
+
+ return (True);
}
/****************************************************************************
command 0x34 - suspected of being a "Lookup Names" stub api
****************************************************************************/
-static BOOL api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid, char *param, char *data,
- int mdrcnt, int mprcnt, char **rdata,
- char **rparam, int *rdata_len, int *rparam_len)
+static BOOL api_RNetGroupGetUsers(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel = SVAL(p,0);
- int buf_len = SVAL(p,2);
- int counted=0;
- int missed=0;
-
- DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n",
- str1, str2, p, uLevel, buf_len));
-
- if (!prefix_ok(str1,"zWrLeh")) return False;
-
- *rdata_len = 0;
- *rdata = NULL;
-
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- SSVAL(*rparam,0,0x08AC); /* informational warning message */
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,counted);
- SSVAL(*rparam,6,counted+missed);
-
- return(True);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ int uLevel = SVAL(p, 0);
+ int buf_len = SVAL(p, 2);
+ int counted = 0;
+ int missed = 0;
+
+ DEBUG(5, ("RNetGroupGetUsers: %s %s %s %d %d\n",
+ str1, str2, p, uLevel, buf_len));
+
+ if (!prefix_ok(str1, "zWrLeh"))
+ return False;
+
+ *rdata_len = 0;
+ *rdata = NULL;
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam, *rparam_len);
+
+ SSVAL(*rparam, 0, 0x08AC); /* informational warning message */
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, counted);
+ SSVAL(*rparam, 6, counted + missed);
+
+ return (True);
}
/****************************************************************************
get info about a share
****************************************************************************/
-static BOOL check_share_info(int uLevel, char* id)
+static BOOL check_share_info(int uLevel, char *id)
{
- switch( uLevel ) {
- case 0:
- if (strcmp(id,"B13") != 0) return False;
- break;
- case 1:
- if (strcmp(id,"B13BWz") != 0) return False;
- break;
- case 2:
- if (strcmp(id,"B13BWzWWWzB9B") != 0) return False;
- break;
- case 91:
- if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False;
- break;
- default: return False;
- }
- return True;
+ switch (uLevel)
+ {
+ case 0:
+ if (strcmp(id, "B13") != 0)
+ return False;
+ break;
+ case 1:
+ if (strcmp(id, "B13BWz") != 0)
+ return False;
+ break;
+ case 2:
+ if (strcmp(id, "B13BWzWWWzB9B") != 0)
+ return False;
+ break;
+ case 91:
+ if (strcmp(id, "B13BWzWWWzB9BB9BWzWWzWW") != 0)
+ return False;
+ break;
+ default:
+ return False;
+ }
+ return True;
}
-static int fill_share_info(connection_struct *conn, const vuser_key *key,
- int snum, int uLevel,
- char** buf, int* buflen,
- char** stringbuf, int* stringspace, char* baseaddr)
+static int fill_share_info(connection_struct * conn, const vuser_key * key,
+ int snum, int uLevel,
+ char **buf, int *buflen,
+ char **stringbuf, int *stringspace, char *baseaddr)
{
- int struct_len;
- char* p;
- char* p2;
- int l2;
- int len;
-
- switch( uLevel ) {
- case 0: struct_len = 13; break;
- case 1: struct_len = 20; break;
- case 2: struct_len = 40; break;
- case 91: struct_len = 68; break;
- default: return -1;
- }
-
-
- if (!buf)
- {
- len = 0;
- if (uLevel > 0) len += StrlenExpanded(conn,key,snum,lp_comment(snum));
- if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1;
- if (buflen) *buflen = struct_len;
- if (stringspace) *stringspace = len;
- return struct_len + len;
- }
-
- len = struct_len;
- p = *buf;
- if ((*buflen) < struct_len) return -1;
- if (stringbuf)
- {
- p2 = *stringbuf;
- l2 = *stringspace;
- }
- else
- {
- p2 = p + struct_len;
- l2 = (*buflen) - struct_len;
- }
- if (!baseaddr) baseaddr = p;
-
- StrnCpy(p,lp_servicename(snum),13);
-
- if (uLevel > 0)
- {
- int type;
- CVAL(p,13) = 0;
- type = STYPE_DISKTREE;
- if (lp_print_ok(snum)) type = STYPE_PRINTQ;
- if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC;
- SSVAL(p,14,type); /* device type */
- SIVAL(p,16,PTR_DIFF(p2,baseaddr));
- len += CopyExpanded(conn,key, snum,&p2,lp_comment(snum),&l2);
- }
-
- if (uLevel > 1)
- {
- SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
- SSVALS(p,22,-1); /* max uses */
- SSVAL(p,24,1); /* current uses */
- SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */
- len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
- memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
- }
-
- if (uLevel > 2)
- {
- memset(p+40,0,SHPWLEN+2);
- SSVAL(p,50,0);
- SIVAL(p,52,0);
- SSVAL(p,56,0);
- SSVAL(p,58,0);
- SIVAL(p,60,0);
- SSVAL(p,64,0);
- SSVAL(p,66,0);
- }
-
- if (stringbuf)
- {
- (*buf) = p + struct_len;
- (*buflen) -= struct_len;
- (*stringbuf) = p2;
- (*stringspace) = l2;
- }
- else
- {
- (*buf) = p2;
- (*buflen) -= len;
- }
- return len;
+ int struct_len;
+ char *p;
+ char *p2;
+ int l2;
+ int len;
+
+ switch (uLevel)
+ {
+ case 0:
+ struct_len = 13;
+ break;
+ case 1:
+ struct_len = 20;
+ break;
+ case 2:
+ struct_len = 40;
+ break;
+ case 91:
+ struct_len = 68;
+ break;
+ default:
+ return -1;
+ }
+
+
+ if (!buf)
+ {
+ len = 0;
+ if (uLevel > 0)
+ len +=
+ StrlenExpanded(conn, key, snum,
+ lp_comment(snum));
+ if (uLevel > 1)
+ len += strlen(lp_pathname(snum)) + 1;
+ if (buflen)
+ *buflen = struct_len;
+ if (stringspace)
+ *stringspace = len;
+ return struct_len + len;
+ }
+
+ len = struct_len;
+ p = *buf;
+ if ((*buflen) < struct_len)
+ return -1;
+ if (stringbuf)
+ {
+ p2 = *stringbuf;
+ l2 = *stringspace;
+ }
+ else
+ {
+ p2 = p + struct_len;
+ l2 = (*buflen) - struct_len;
+ }
+ if (!baseaddr)
+ baseaddr = p;
+
+ StrnCpy(p, lp_servicename(snum), 13);
+
+ if (uLevel > 0)
+ {
+ int type;
+ CVAL(p, 13) = 0;
+ type = STYPE_DISKTREE;
+ if (lp_print_ok(snum))
+ type = STYPE_PRINTQ;
+ if (strequal("IPC$", lp_servicename(snum)))
+ type = STYPE_IPC;
+ SSVAL(p, 14, type); /* device type */
+ SIVAL(p, 16, PTR_DIFF(p2, baseaddr));
+ len +=
+ CopyExpanded(conn, key, snum, &p2, lp_comment(snum),
+ &l2);
+ }
+
+ if (uLevel > 1)
+ {
+ SSVAL(p, 20, ACCESS_READ | ACCESS_WRITE | ACCESS_CREATE); /* permissions */
+ SSVALS(p, 22, -1); /* max uses */
+ SSVAL(p, 24, 1); /* current uses */
+ SIVAL(p, 26, PTR_DIFF(p2, baseaddr)); /* local pathname */
+ len += CopyAndAdvance(&p2, lp_pathname(snum), &l2);
+ memset(p + 30, 0, SHPWLEN + 2); /* passwd (reserved), pad field */
+ }
+
+ if (uLevel > 2)
+ {
+ memset(p + 40, 0, SHPWLEN + 2);
+ SSVAL(p, 50, 0);
+ SIVAL(p, 52, 0);
+ SSVAL(p, 56, 0);
+ SSVAL(p, 58, 0);
+ SIVAL(p, 60, 0);
+ SSVAL(p, 64, 0);
+ SSVAL(p, 66, 0);
+ }
+
+ if (stringbuf)
+ {
+ (*buf) = p + struct_len;
+ (*buflen) -= struct_len;
+ (*stringbuf) = p2;
+ (*stringspace) = l2;
+ }
+ else
+ {
+ (*buf) = p2;
+ (*buflen) -= len;
+ }
+ return len;
}
-static BOOL api_RNetShareGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_RNetShareGetInfo(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *netname = skip_string(str2,1);
- char *p = skip_string(netname,1);
- int uLevel = SVAL(p,0);
- int snum = find_service(netname);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *netname = skip_string(str2, 1);
+ char *p = skip_string(netname, 1);
+ int uLevel = SVAL(p, 0);
+ int snum = find_service(netname);
VUSER_KEY;
-
- if (snum < 0) return False;
-
- /* check it's a supported varient */
- if (!prefix_ok(str1,"zWrLh")) return False;
- if (!check_share_info(uLevel,str2)) return False;
-
- *rdata = REALLOC(*rdata,mdrcnt);
- p = *rdata;
- *rdata_len = fill_share_info(conn,&key,snum,uLevel,&p,&mdrcnt,0,0,0);
- if (*rdata_len < 0) return False;
-
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
- SSVAL(*rparam,4,*rdata_len);
-
- return(True);
+
+ if (snum < 0)
+ return False;
+
+ /* check it's a supported varient */
+ if (!prefix_ok(str1, "zWrLh"))
+ return False;
+ if (!check_share_info(uLevel, str2))
+ return False;
+
+ *rdata = REALLOC(*rdata, mdrcnt);
+ p = *rdata;
+ *rdata_len =
+ fill_share_info(conn, &key, snum, uLevel, &p, &mdrcnt, 0, 0,
+ 0);
+ if (*rdata_len < 0)
+ return False;
+
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVAL(*rparam, 0, NERR_Success);
+ SSVAL(*rparam, 2, 0); /* converter word */
+ SSVAL(*rparam, 4, *rdata_len);
+
+ return (True);
}
/****************************************************************************
view list of shares available
****************************************************************************/
-static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_RNetShareEnum(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt, int mprcnt,
+ char **rdata, char **rparam, int *rdata_len,
+ int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel = SVAL(p,0);
- int buf_len = SVAL(p,2);
- char *p2;
- int count=lp_numservices();
- int total=0,counted=0;
- BOOL missed = False;
- int i;
- int data_len, fixed_len, string_len;
- int f_len = 0, s_len = 0;
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ int uLevel = SVAL(p, 0);
+ int buf_len = SVAL(p, 2);
+ char *p2;
+ int count = lp_numservices();
+ int total = 0, counted = 0;
+ BOOL missed = False;
+ int i;
+ int data_len, fixed_len, string_len;
+ int f_len = 0, s_len = 0;
VUSER_KEY;
-
- if (!prefix_ok(str1,"WrLeh")) return False;
- if (!check_share_info(uLevel,str2)) return False;
-
- data_len = fixed_len = string_len = 0;
- for (i=0;i<count;i++)
- if (lp_browseable(i) && lp_snum_ok(i))
- {
- total++;
- data_len += fill_share_info(conn,&key,i,uLevel,0,&f_len,0,&s_len,0);
- if (data_len <= buf_len)
- {
- counted++;
- fixed_len += f_len;
- string_len += s_len;
- }
- else
- missed = True;
- }
- *rdata_len = fixed_len + string_len;
- *rdata = REALLOC(*rdata,*rdata_len);
- memset(*rdata,0,*rdata_len);
-
- p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
- p = *rdata;
- f_len = fixed_len;
- s_len = string_len;
- for (i = 0; i < count;i++)
- if (lp_browseable(i) && lp_snum_ok(i))
- if (fill_share_info(conn,&key,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0)
- break;
-
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,counted);
- SSVAL(*rparam,6,total);
-
- DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
- counted,total,uLevel,
- buf_len,*rdata_len,mdrcnt));
- return(True);
+
+ if (!prefix_ok(str1, "WrLeh"))
+ return False;
+ if (!check_share_info(uLevel, str2))
+ return False;
+
+ data_len = fixed_len = string_len = 0;
+ for (i = 0; i < count; i++)
+ if (lp_browseable(i) && lp_snum_ok(i))
+ {
+ total++;
+ data_len +=
+ fill_share_info(conn, &key, i, uLevel, 0,
+ &f_len, 0, &s_len, 0);
+ if (data_len <= buf_len)
+ {
+ counted++;
+ fixed_len += f_len;
+ string_len += s_len;
+ }
+ else
+ missed = True;
+ }
+ *rdata_len = fixed_len + string_len;
+ *rdata = REALLOC(*rdata, *rdata_len);
+ memset(*rdata, 0, *rdata_len);
+
+ p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */
+ p = *rdata;
+ f_len = fixed_len;
+ s_len = string_len;
+ for (i = 0; i < count; i++)
+ if (lp_browseable(i) && lp_snum_ok(i))
+ if (fill_share_info
+ (conn, &key, i, uLevel, &p, &f_len, &p2, &s_len,
+ *rdata) < 0)
+ break;
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVAL(*rparam, 0, missed ? ERRmoredata : NERR_Success);
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, counted);
+ SSVAL(*rparam, 6, total);
+
+ DEBUG(3, ("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
+ counted, total, uLevel, buf_len, *rdata_len, mdrcnt));
+ return (True);
}
@@ -1482,313 +1735,351 @@ static BOOL api_RNetShareEnum(connection_struct *conn,uint16 vuid, char *param,c
/****************************************************************************
get the time of day info
****************************************************************************/
-static BOOL api_NetRemoteTOD(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_NetRemoteTOD(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt, int mprcnt,
+ char **rdata, char **rparam, int *rdata_len,
+ int *rparam_len)
{
- char *p;
- *rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- *rdata_len = 21;
- *rdata = REALLOC(*rdata,*rdata_len);
-
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
-
- p = *rdata;
+ char *p;
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam, *rparam_len);
- {
- struct tm *t;
- time_t unixdate = time(NULL);
+ *rdata_len = 21;
+ *rdata = REALLOC(*rdata, *rdata_len);
- put_dos_date3(p,0,unixdate); /* this is the time that is looked at
- by NT in a "net time" operation,
- it seems to ignore the one below */
+ SSVAL(*rparam, 0, NERR_Success);
+ SSVAL(*rparam, 2, 0); /* converter word */
- /* the client expects to get localtime, not GMT, in this bit
- (I think, this needs testing) */
- t = LocalTime(&unixdate);
+ p = *rdata;
- SIVAL(p,4,0); /* msecs ? */
- CVAL(p,8) = t->tm_hour;
- CVAL(p,9) = t->tm_min;
- CVAL(p,10) = t->tm_sec;
- CVAL(p,11) = 0; /* hundredths of seconds */
- SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */
- SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */
- CVAL(p,16) = t->tm_mday;
- CVAL(p,17) = t->tm_mon + 1;
- SSVAL(p,18,1900+t->tm_year);
- CVAL(p,20) = t->tm_wday;
- }
+ {
+ struct tm *t;
+ time_t unixdate = time(NULL);
+
+ put_dos_date3(p, 0, unixdate); /* this is the time that is looked at
+ by NT in a "net time" operation,
+ it seems to ignore the one below */
+
+ /* the client expects to get localtime, not GMT, in this bit
+ (I think, this needs testing) */
+ t = LocalTime(&unixdate);
+
+ SIVAL(p, 4, 0); /* msecs ? */
+ CVAL(p, 8) = t->tm_hour;
+ CVAL(p, 9) = t->tm_min;
+ CVAL(p, 10) = t->tm_sec;
+ CVAL(p, 11) = 0; /* hundredths of seconds */
+ SSVALS(p, 12, TimeDiff(unixdate) / 60); /* timezone in minutes from GMT */
+ SSVAL(p, 14, 10000); /* timer interval in 0.0001 of sec */
+ CVAL(p, 16) = t->tm_mday;
+ CVAL(p, 17) = t->tm_mon + 1;
+ SSVAL(p, 18, 1900 + t->tm_year);
+ CVAL(p, 20) = t->tm_wday;
+ }
- return(True);
+ return (True);
}
/****************************************************************************
set the user password
****************************************************************************/
-static BOOL api_SetUserPassword(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_SetUserPassword(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *p = skip_string(param+2,2);
- fstring user;
- fstring pass1,pass2;
- uchar pwbuf[516];
- uchar nt_pw[16];
- uchar lm_pw[16];
-
- fstrcpy(user,p);
+ char *p = skip_string(param + 2, 2);
+ fstring user;
+ fstring pass1, pass2;
+ uchar pwbuf[516];
+ uchar nt_pw[16];
+ uchar lm_pw[16];
- p = skip_string(p,1);
+ fstrcpy(user, p);
- memcpy(pass1,p,16);
- memcpy(pass2,p+16,16);
+ p = skip_string(p, 1);
- *rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
+ memcpy(pass1, p, 16);
+ memcpy(pass2, p + 16, 16);
- *rdata_len = 0;
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam, *rparam_len);
- SSVAL(*rparam,0,NERR_badpass);
- SSVAL(*rparam,2,0); /* converter word */
+ *rdata_len = 0;
- DEBUG(3,("Set password for <%s>\n",user));
+ SSVAL(*rparam, 0, NERR_badpass);
+ SSVAL(*rparam, 2, 0); /* converter word */
- /*
- * Pass the user through the NT -> unix user mapping
- * function.
- */
+ DEBUG(3, ("Set password for <%s>\n", user));
- (void)map_username(user);
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
- /*
- * Do any UNIX username case mangling.
- */
- (void)Get_Pwnam( user, True);
+ (void)map_username(user);
- if (strequal(param + 2, "zb16b16WW"))
- {
- /*
- * attempt the encrypted pw change. NT will generate this
- * after trying the samr method.
- */
+ /*
+ * Do any UNIX username case mangling.
+ */
+ (void)Get_Pwnam(user, True);
- if (SVAL(*rparam,0) != NERR_Success)
+ if (strequal(param + 2, "zb16b16WW"))
{
- if (make_oem_passwd_hash(pwbuf, pass1, 16, NULL, False) &&
- msrpc_sam_ntpasswd_set("\\\\.", user, NULL,
- pwbuf, pass2, /* lm pw */
- NULL, NULL)) /* nt pw */
+ /*
+ * attempt the encrypted pw change. NT will generate this
+ * after trying the samr method.
+ */
+
+ if (SVAL(*rparam, 0) != NERR_Success)
{
- SSVAL(*rparam,0,NERR_Success);
+ if (make_oem_passwd_hash
+ (pwbuf, pass1, 16, NULL, False)
+ && msrpc_sam_ntpasswd_set("\\\\.", user, NULL,
+ pwbuf, pass2, /* lm pw */
+ NULL, NULL)) /* nt pw */
+ {
+ SSVAL(*rparam, 0, NERR_Success);
+ }
}
}
- }
- else
- {
- /*
- * Attempt the plaintext password change first.
- * Older versions of Windows seem to do this.
- */
-
- nt_lm_owf_gen(pass1, nt_pw, lm_pw);
- if (msrpc_sam_ntchange_pwd("\\\\.", user, global_sam_name,
- lm_pw, nt_pw, pass2))
+ else
{
- SSVAL(*rparam,0,NERR_Success);
+ /*
+ * Attempt the plaintext password change first.
+ * Older versions of Windows seem to do this.
+ */
+
+ nt_lm_owf_gen(pass1, nt_pw, lm_pw);
+ if (msrpc_sam_ntchange_pwd("\\\\.", user, global_sam_name,
+ lm_pw, nt_pw, pass2))
+ {
+ SSVAL(*rparam, 0, NERR_Success);
+ }
}
- }
ZERO_STRUCT(pwbuf);
ZERO_STRUCT(pass1);
ZERO_STRUCT(pass2);
- return(True);
+ return (True);
}
/****************************************************************************
Set the user password (SamOEM version - gets plaintext).
****************************************************************************/
-static BOOL api_SamOEMChangePassword(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_SamOEMChangePassword(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- fstring user;
- char *p = param + 2;
- *rparam_len = 2;
- *rparam = REALLOC(*rparam,*rparam_len);
+ fstring user;
+ char *p = param + 2;
+ *rparam_len = 2;
+ *rparam = REALLOC(*rparam, *rparam_len);
- *rdata_len = 0;
+ *rdata_len = 0;
- SSVAL(*rparam,0,NERR_badpass);
+ SSVAL(*rparam, 0, NERR_badpass);
- /*
- * Check the parameter definition is correct.
- */
- if (!strequal(param + 2, "zsT")) {
- DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", param + 2));
- return False;
- }
- p = skip_string(p, 1);
-
- if (!strequal(p, "B516B16")) {
- DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p));
- return False;
- }
- p = skip_string(p,1);
-
- fstrcpy(user,p);
- p = skip_string(p,1);
-
- DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user));
-
- if (msrpc_sam_ntpasswd_set("\\\\.", user, NULL,
- (uchar*) data, (uchar *)&data[516], /* lm pw */
- NULL, NULL)) /* nt pw */
- {
- SSVAL(*rparam,0,NERR_Success);
- }
-
- return(True);
+ /*
+ * Check the parameter definition is correct.
+ */
+ if (!strequal(param + 2, "zsT"))
+ {
+ DEBUG(0,
+ ("api_SamOEMChangePassword: Invalid parameter string %s\n",
+ param + 2));
+ return False;
+ }
+ p = skip_string(p, 1);
+
+ if (!strequal(p, "B516B16"))
+ {
+ DEBUG(0,
+ ("api_SamOEMChangePassword: Invalid data parameter string %s\n",
+ p));
+ return False;
+ }
+ p = skip_string(p, 1);
+
+ fstrcpy(user, p);
+ p = skip_string(p, 1);
+
+ DEBUG(3,
+ ("api_SamOEMChangePassword: Change password for <%s>\n", user));
+
+ if (msrpc_sam_ntpasswd_set("\\\\.", user, NULL,
+ (uchar *) data, (uchar *) & data[516], /* lm pw */
+ NULL, NULL)) /* nt pw */
+ {
+ SSVAL(*rparam, 0, NERR_Success);
+ }
+
+ return (True);
}
/****************************************************************************
delete a print job
Form: <W> <>
****************************************************************************/
-static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_RDosPrintJobDel(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- int function = SVAL(param,0);
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int jobid, snum;
- int i, count;
+ int function = SVAL(param, 0);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ int jobid, snum;
+ int i, count;
VUSER_KEY;
- printjob_decode(SVAL(p,0), &snum, &jobid);
-
- /* check it's a supported varient */
- if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
- return(False);
-
- *rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- *rdata_len = 0;
-
- SSVAL(*rparam,0,NERR_Success);
-
- if (snum >= 0 && VALID_SNUM(snum))
- {
- print_queue_struct *queue=NULL;
- lpq_reset(snum);
- count = get_printqueue(snum,conn,&key,&queue,NULL);
-
- for (i=0;i<count;i++)
- if ((queue[i].job&0xFF) == jobid)
- {
- switch (function) {
- case 81: /* delete */
- DEBUG(3,("Deleting queue entry %d\n",queue[i].job));
- del_printqueue(conn,&key,snum,queue[i].job);
- break;
- case 82: /* pause */
- case 83: /* resume */
- DEBUG(3,("%s queue entry %d\n",
- (function==82?"pausing":"resuming"),queue[i].job));
- status_printjob(conn,&key,snum,queue[i].job,
- (function==82?LPQ_PAUSED:LPQ_QUEUED));
- break;
- }
- break;
- }
-
- if (i==count)
- SSVAL(*rparam,0,NERR_JobNotFound);
-
- if (queue) free(queue);
- }
-
- SSVAL(*rparam,2,0); /* converter word */
-
- return(True);
+ printjob_decode(SVAL(p, 0), &snum, &jobid);
+
+ /* check it's a supported varient */
+ if (!(strcsequal(str1, "W") && strcsequal(str2, "")))
+ return (False);
+
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam, *rparam_len);
+
+ *rdata_len = 0;
+
+ SSVAL(*rparam, 0, NERR_Success);
+
+ if (snum >= 0 && VALID_SNUM(snum))
+ {
+ print_queue_struct *queue = NULL;
+ lpq_reset(snum);
+ count = get_printqueue(snum, conn, &key, &queue, NULL);
+
+ for (i = 0; i < count; i++)
+ if ((queue[i].job & 0xFF) == jobid)
+ {
+ switch (function)
+ {
+ case 81: /* delete */
+ DEBUG(3,
+ ("Deleting queue entry %d\n",
+ queue[i].job));
+ del_printqueue(conn, &key,
+ snum,
+ queue[i].job);
+ break;
+ case 82: /* pause */
+ case 83: /* resume */
+ DEBUG(3,
+ ("%s queue entry %d\n",
+ (function ==
+ 82 ? "pausing" :
+ "resuming"),
+ queue[i].job));
+ status_printjob(conn, &key,
+ snum,
+ queue[i].job,
+ (function ==
+ 82 ?
+ LPQ_PAUSED :
+ LPQ_QUEUED));
+ break;
+ }
+ break;
+ }
+
+ if (i == count)
+ SSVAL(*rparam, 0, NERR_JobNotFound);
+
+ if (queue)
+ free(queue);
+ }
+
+ SSVAL(*rparam, 2, 0); /* converter word */
+
+ return (True);
}
/****************************************************************************
Purge a print queue - or pause or resume it.
****************************************************************************/
-static BOOL api_WPrintQueuePurge(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_WPrintQueuePurge(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- int function = SVAL(param,0);
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *QueueName = skip_string(str2,1);
- int snum;
+ int function = SVAL(param, 0);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *QueueName = skip_string(str2, 1);
+ int snum;
VUSER_KEY;
- /* check it's a supported varient */
- if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
- return(False);
-
- *rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- *rdata_len = 0;
-
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
-
- snum = lp_servicenumber(QueueName);
- if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
- int pnum = lp_servicenumber(PRINTERS_NAME);
- if (pnum >= 0) {
- lp_add_printer(QueueName,pnum);
- snum = lp_servicenumber(QueueName);
- }
- }
-
- if (snum >= 0 && VALID_SNUM(snum)) {
- lpq_reset(snum);
-
- switch (function) {
- case 74: /* Pause queue */
- case 75: /* Resume queue */
- {
- status_printqueue(conn,&key,snum,(function==74?LPSTAT_STOPPED:LPSTAT_OK));
- DEBUG(3,("Print queue %s, queue=%s\n",
- (function==74?"pause":"resume"),QueueName));
- break;
- }
- case 103: /* Purge */
- {
- print_queue_struct *queue=NULL;
- int i, count;
- count = get_printqueue(snum,conn,&key,&queue,NULL);
- for (i = 0; i < count; i++)
- del_printqueue(conn,&key,snum,queue[i].job);
-
- if (queue) free(queue);
- DEBUG(3,("Print queue purge, queue=%s\n",QueueName));
- break;
- }
- }
- }
-
- return(True);
+ /* check it's a supported varient */
+ if (!(strcsequal(str1, "z") && strcsequal(str2, "")))
+ return (False);
+
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam, *rparam_len);
+
+ *rdata_len = 0;
+
+ SSVAL(*rparam, 0, NERR_Success);
+ SSVAL(*rparam, 2, 0); /* converter word */
+
+ snum = lp_servicenumber(QueueName);
+ if (snum < 0 && pcap_printername_ok(QueueName, NULL))
+ {
+ int pnum = lp_servicenumber(PRINTERS_NAME);
+ if (pnum >= 0)
+ {
+ lp_add_printer(QueueName, pnum);
+ snum = lp_servicenumber(QueueName);
+ }
+ }
+
+ if (snum >= 0 && VALID_SNUM(snum))
+ {
+ lpq_reset(snum);
+
+ switch (function)
+ {
+ case 74: /* Pause queue */
+ case 75: /* Resume queue */
+ {
+ status_printqueue(conn, &key, snum,
+ (function ==
+ 74 ? LPSTAT_STOPPED :
+ LPSTAT_OK));
+ DEBUG(3,
+ ("Print queue %s, queue=%s\n",
+ (function == 74 ? "pause" : "resume"),
+ QueueName));
+ break;
+ }
+ case 103: /* Purge */
+ {
+ print_queue_struct *queue = NULL;
+ int i, count;
+ count =
+ get_printqueue(snum, conn, &key,
+ &queue, NULL);
+ for (i = 0; i < count; i++)
+ del_printqueue(conn, &key, snum,
+ queue[i].job);
+
+ if (queue)
+ free(queue);
+ DEBUG(3,
+ ("Print queue purge, queue=%s\n",
+ QueueName));
+ break;
+ }
+ }
+ }
+
+ return (True);
}
@@ -1799,311 +2090,376 @@ static BOOL api_WPrintQueuePurge(connection_struct *conn,uint16 vuid, char *para
Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz>
or <WWsTP> <WB21BB16B10zWWzDDz>
****************************************************************************/
-static int check_printjob_info(struct pack_desc* desc,
- int uLevel, char* id)
+static int check_printjob_info(struct pack_desc *desc, int uLevel, char *id)
{
- desc->subformat = NULL;
- switch( uLevel ) {
- case 0: desc->format = "W"; break;
- case 1: desc->format = "WB21BB16B10zWWzDDz"; break;
- case 2: desc->format = "WWzWWDDzz"; break;
- case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break;
- default: return False;
- }
- if (strcmp(desc->format,id) != 0) return False;
- return True;
+ desc->subformat = NULL;
+ switch (uLevel)
+ {
+ case 0:
+ desc->format = "W";
+ break;
+ case 1:
+ desc->format = "WB21BB16B10zWWzDDz";
+ break;
+ case 2:
+ desc->format = "WWzWWDDzz";
+ break;
+ case 3:
+ desc->format = "WWzWWDDzzzzzzzzzzlz";
+ break;
+ default:
+ return False;
+ }
+ if (strcmp(desc->format, id) != 0)
+ return False;
+ return True;
}
-static BOOL api_PrintJobInfo(connection_struct *conn,uint16 vuid,char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_PrintJobInfo(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt, int mprcnt,
+ char **rdata, char **rparam, int *rdata_len,
+ int *rparam_len)
{
struct pack_desc desc;
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
int jobid, snum;
- int uLevel = SVAL(p,2);
- int function = SVAL(p,4); /* what is this ?? */
+ int uLevel = SVAL(p, 2);
+ int function = SVAL(p, 4); /* what is this ?? */
int i;
char *s = data;
files_struct *fsp;
VUSER_KEY;
- printjob_decode(SVAL(p,0), &snum, &jobid);
-
+ printjob_decode(SVAL(p, 0), &snum, &jobid);
+
*rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
-
+ *rparam = REALLOC(*rparam, *rparam_len);
+
*rdata_len = 0;
-
+
/* check it's a supported varient */
- if ((strcmp(str1,"WWsTP")) ||
- (!check_printjob_info(&desc,uLevel,str2)))
- return(False);
-
- switch (function) {
- case 0x6: /* change job place in the queue,
- data gives the new place */
- if (snum >= 0 && VALID_SNUM(snum)) {
- print_queue_struct *queue=NULL;
- int count;
-
- lpq_reset(snum);
- count = get_printqueue(snum,conn,&key,&queue,NULL);
- for (i=0;i<count;i++) /* find job */
- if ((queue[i].job&0xFF) == jobid) break;
-
- if (i==count) {
- desc.errcode=NERR_JobNotFound;
- if (queue) free(queue);
- } else {
- desc.errcode=NERR_Success;
- i++;
-#if 0
+ if ((strcmp(str1, "WWsTP")) ||
+ (!check_printjob_info(&desc, uLevel, str2)))
+ return (False);
+
+ switch (function)
+ {
+ case 0x6: /* change job place in the queue,
+ data gives the new place */
+ if (snum >= 0 && VALID_SNUM(snum))
+ {
+ print_queue_struct *queue = NULL;
+ int count;
+
+ lpq_reset(snum);
+ count =
+ get_printqueue(snum, conn, &key,
+ &queue, NULL);
+ for (i = 0; i < count; i++) /* find job */
+ if ((queue[i].job & 0xFF) == jobid)
+ break;
+
+ if (i == count)
{
- int place= SVAL(data,0);
- /* we currently have no way of
- doing this. Can any unix do it? */
- if (i < place) /* move down */;
- else if (i > place ) /* move up */;
+ desc.errcode = NERR_JobNotFound;
+ if (queue)
+ free(queue);
}
+ else
+ {
+ desc.errcode = NERR_Success;
+ i++;
+#if 0
+ {
+ int place = SVAL(data, 0);
+ /* we currently have no way of
+ doing this. Can any unix do it? */
+ if (i <
+ place) /* move down */ ;
+ else if (i > place) /* move up */
+ ;
+ }
#endif
- desc.errcode=NERR_notsupported; /* not yet
- supported */
- if (queue) free(queue);
+ desc.errcode = NERR_notsupported; /* not yet
+ supported */
+ if (queue)
+ free(queue);
+ }
}
- } else {
- desc.errcode=NERR_JobNotFound;
- }
- break;
-
- case 0xb: /* change print job name, data gives the name */
- /* jobid, snum should be zero */
- if (isalpha((int)*s)) {
- pstring name;
- int l = 0;
- while (l<64 && *s) {
- if (issafe(*s)) name[l++] = *s;
- s++;
- }
- name[l] = 0;
-
- DEBUG(3,("Setting print name to %s\n",name));
-
- fsp = file_find_print();
-
- if (fsp) {
- connection_struct *fconn = fsp->conn;
- unbecome_user();
-
- if (!become_user(fconn,vuid) ||
- !become_service(fconn,True))
+ else
+ {
+ desc.errcode = NERR_JobNotFound;
+ }
+ break;
+
+ case 0xb: /* change print job name, data gives the name */
+ /* jobid, snum should be zero */
+ if (isalpha((int)*s))
+ {
+ pstring name;
+ int l = 0;
+ while (l < 64 && *s)
+ {
+ if (issafe(*s))
+ name[l++] = *s;
+ s++;
+ }
+ name[l] = 0;
+
+ DEBUG(3,
+ ("Setting print name to %s\n", name));
+
+ fsp = file_find_print();
+
+ if (fsp)
+ {
+ pstring zfrom, zto;
+ connection_struct *fconn = fsp->conn;
+ unbecome_user();
+
+ if (!become_user(fconn, vuid) ||
+ !become_service(fconn, True))
+ break;
+
+ pstrcpy(zfrom,
+ dos_to_unix(fsp->fsp_name,
+ False));
+ pstrcpy(zto,
+ dos_to_unix(name, False));
+
+ if (fsp->conn->
+ vfs_ops.rename(zfrom, zto) == 0)
+ {
+ string_set(&fsp->fsp_name,
+ name);
+ }
break;
-
- if (conn->vfs_ops.rename(dos_to_unix(fsp->fsp_name,False),name) == 0) {
- string_set(&fsp->fsp_name,name);
}
- break;
}
- }
- desc.errcode=NERR_Success;
- break;
+ desc.errcode = NERR_Success;
+ break;
- default: /* not implemented */
- return False;
+ default: /* not implemented */
+ return False;
}
-
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0); /* converter word */
-
- return(True);
+
+ SSVALS(*rparam, 0, desc.errcode);
+ SSVAL(*rparam, 2, 0); /* converter word */
+
+ return (True);
}
/****************************************************************************
get info about the server
****************************************************************************/
-static BOOL api_RNetServerGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_RNetServerGetInfo(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel = SVAL(p,0);
- char *p2;
- int struct_len;
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ int uLevel = SVAL(p, 0);
+ char *p2;
+ int struct_len;
VUSER_KEY;
- DEBUG(4,("NetServerGetInfo level %d\n",uLevel));
-
- /* check it's a supported varient */
- if (!prefix_ok(str1,"WrLh")) return False;
- switch( uLevel ) {
- case 0:
- if (strcmp(str2,"B16") != 0) return False;
- struct_len = 16;
- break;
- case 1:
- if (strcmp(str2,"B16BBDz") != 0) return False;
- struct_len = 26;
- break;
- case 2:
- if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
- != 0) return False;
- struct_len = 134;
- break;
- case 3:
- if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
- != 0) return False;
- struct_len = 144;
- break;
- case 20:
- if (strcmp(str2,"DN") != 0) return False;
- struct_len = 6;
- break;
- case 50:
- if (strcmp(str2,"B16BBDzWWzzz") != 0) return False;
- struct_len = 42;
- break;
- default: return False;
- }
-
- *rdata_len = mdrcnt;
- *rdata = REALLOC(*rdata,*rdata_len);
-
- p = *rdata;
- p2 = p + struct_len;
- if (uLevel != 20) {
- StrnCpy(p,local_machine,16);
- strupper(p);
- }
- p += 16;
- if (uLevel > 0)
- {
- struct srv_info_struct *servers=NULL;
- int i,count;
- pstring comment;
- uint32 servertype= lp_default_server_announce();
-
- pstrcpy(comment,lp_serverstring());
-
- if ((count=get_server_info(SV_TYPE_ALL,&servers,global_myworkgroup))>0) {
- for (i=0;i<count;i++)
- if (strequal(servers[i].name,local_machine))
- {
- servertype = servers[i].type;
- pstrcpy(comment,servers[i].comment);
- }
- }
- if (servers) free(servers);
-
- SCVAL(p,0,lp_major_announce_version());
- SCVAL(p,1,lp_minor_announce_version());
- SIVAL(p,2,servertype);
-
- if (mdrcnt == struct_len) {
- SIVAL(p,6,0);
- } else {
- user_struct *vuser = get_valid_user_struct(&key);
- SIVAL(p,6,PTR_DIFF(p2,*rdata));
- standard_sub(conn,vuser, comment);
- StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
- p2 = skip_string(p2,1);
- vuid_free_user_struct(vuser);
+ DEBUG(4, ("NetServerGetInfo level %d\n", uLevel));
+
+ /* check it's a supported varient */
+ if (!prefix_ok(str1, "WrLh"))
+ return False;
+ switch (uLevel)
+ {
+ case 0:
+ if (strcmp(str2, "B16") != 0)
+ return False;
+ struct_len = 16;
+ break;
+ case 1:
+ if (strcmp(str2, "B16BBDz") != 0)
+ return False;
+ struct_len = 26;
+ break;
+ case 2:
+ if (strcmp
+ (str2,
+ "B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")
+ != 0)
+ return False;
+ struct_len = 134;
+ break;
+ case 3:
+ if (strcmp
+ (str2,
+ "B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz")
+ != 0)
+ return False;
+ struct_len = 144;
+ break;
+ case 20:
+ if (strcmp(str2, "DN") != 0)
+ return False;
+ struct_len = 6;
+ break;
+ case 50:
+ if (strcmp(str2, "B16BBDzWWzzz") != 0)
+ return False;
+ struct_len = 42;
+ break;
+ default:
+ return False;
+ }
+
+ *rdata_len = mdrcnt;
+ *rdata = REALLOC(*rdata, *rdata_len);
+
+ p = *rdata;
+ p2 = p + struct_len;
+ if (uLevel != 20)
+ {
+ StrnCpy(p, local_machine, 16);
+ strupper(p);
+ }
+ p += 16;
+ if (uLevel > 0)
+ {
+ struct srv_info_struct *servers = NULL;
+ int i, count;
+ pstring comment;
+ uint32 servertype = lp_default_server_announce();
+
+ 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++)
+ if (strequal(servers[i].name, local_machine))
+ {
+ servertype = servers[i].type;
+ pstrcpy(comment, servers[i].comment);
+ }
+ }
+ if (servers)
+ free(servers);
- }
- }
- if (uLevel > 1)
- {
- return False; /* not yet implemented */
- }
+ SCVAL(p, 0, lp_major_announce_version());
+ SCVAL(p, 1, lp_minor_announce_version());
+ SIVAL(p, 2, servertype);
+
+ if (mdrcnt == struct_len)
+ {
+ SIVAL(p, 6, 0);
+ }
+ else
+ {
+ user_struct *vuser = get_valid_user_struct(&key);
+ SIVAL(p, 6, PTR_DIFF(p2, *rdata));
+ standard_sub(conn, vuser, comment);
+ StrnCpy(p2, comment, MAX(mdrcnt - struct_len, 0));
+ p2 = skip_string(p2, 1);
+ vuid_free_user_struct(vuser);
+
+ }
+ }
+ if (uLevel > 1)
+ {
+ return False; /* not yet implemented */
+ }
- *rdata_len = PTR_DIFF(p2,*rdata);
+ *rdata_len = PTR_DIFF(p2, *rdata);
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
- SSVAL(*rparam,4,*rdata_len);
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVAL(*rparam, 0, NERR_Success);
+ SSVAL(*rparam, 2, 0); /* converter word */
+ SSVAL(*rparam, 4, *rdata_len);
- return(True);
+ return (True);
}
/****************************************************************************
get info about the server
****************************************************************************/
-static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_NetWkstaGetInfo(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- char *p2;
- extern pstring sesssetup_user;
- int level = SVAL(p,0);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ char *p2;
+ extern pstring sesssetup_user;
+ int level = SVAL(p, 0);
- DEBUG(4,("NetWkstaGetInfo level %d\n",level));
+ DEBUG(4, ("NetWkstaGetInfo level %d\n", level));
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam, *rparam_len);
- /* check it's a supported varient */
- if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz")))
- return(False);
+ /* check it's a supported varient */
+ if (!
+ (level == 10 && strcsequal(str1, "WrLh")
+ && strcsequal(str2, "zzzBBzz")))
+ return (False);
- *rdata_len = mdrcnt + 1024;
- *rdata = REALLOC(*rdata,*rdata_len);
+ *rdata_len = mdrcnt + 1024;
+ *rdata = REALLOC(*rdata, *rdata_len);
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
+ SSVAL(*rparam, 0, NERR_Success);
+ SSVAL(*rparam, 2, 0); /* converter word */
- p = *rdata;
- p2 = p + 22;
+ p = *rdata;
+ p2 = p + 22;
- SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
- pstrcpy(p2,local_machine);
- strupper(p2);
- p2 = skip_string(p2,1);
- p += 4;
+ SIVAL(p, 0, PTR_DIFF(p2, *rdata)); /* host name */
+ pstrcpy(p2, local_machine);
+ strupper(p2);
+ p2 = skip_string(p2, 1);
+ p += 4;
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
- pstrcpy(p2,sesssetup_user);
- p2 = skip_string(p2,1);
- p += 4;
+ SIVAL(p, 0, PTR_DIFF(p2, *rdata));
+ pstrcpy(p2, sesssetup_user);
+ p2 = skip_string(p2, 1);
+ p += 4;
- SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
- pstrcpy(p2,global_myworkgroup);
- strupper(p2);
- p2 = skip_string(p2,1);
- p += 4;
+ SIVAL(p, 0, PTR_DIFF(p2, *rdata)); /* login domain */
+ pstrcpy(p2, global_myworkgroup);
+ strupper(p2);
+ p2 = skip_string(p2, 1);
+ p += 4;
- SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
- SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
- p += 2;
+ SCVAL(p, 0, lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
+ SCVAL(p, 1, lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
+ p += 2;
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
- pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
- p2 = skip_string(p2,1);
- p += 4;
+ SIVAL(p, 0, PTR_DIFF(p2, *rdata));
+ pstrcpy(p2, global_myworkgroup); /* don't know. login domain?? */
+ p2 = skip_string(p2, 1);
+ p += 4;
- SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
- pstrcpy(p2,"");
- p2 = skip_string(p2,1);
- p += 4;
+ SIVAL(p, 0, PTR_DIFF(p2, *rdata)); /* don't know */
+ pstrcpy(p2, "");
+ p2 = skip_string(p2, 1);
+ p += 4;
- *rdata_len = PTR_DIFF(p2,*rdata);
+ *rdata_len = PTR_DIFF(p2, *rdata);
- SSVAL(*rparam,4,*rdata_len);
+ SSVAL(*rparam, 4, *rdata_len);
- return(True);
+ return (True);
}
/****************************************************************************
@@ -2241,7 +2597,7 @@ There is no auxiliary data in the response.
****************************************************************************/
-#define usri11_name 0
+#define usri11_name 0
#define usri11_pad 21
#define usri11_comment 22
#define usri11_usr_comment 26
@@ -2268,22 +2624,22 @@ There is no auxiliary data in the response.
#define USER_PRIV_USER 1
#define USER_PRIV_ADMIN 2
-#define AF_OP_PRINT 0
+#define AF_OP_PRINT 0
#define AF_OP_COMM 1
#define AF_OP_SERVER 2
#define AF_OP_ACCOUNTS 3
-static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_RNetUserGetInfo(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *UserName = skip_string(str2,1);
- char *p = skip_string(UserName,1);
- int uLevel = SVAL(p,0);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *UserName = skip_string(str2, 1);
+ char *p = skip_string(UserName, 1);
+ int uLevel = SVAL(p, 0);
char *p2;
fstring nt_name;
@@ -2292,27 +2648,38 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param
fstring home_dir;
fstring logon_srv;
- /* get NIS home of a previously validated user - simeon */
- /* With share level security vuid will always be zero.
- Don't depend on vuser being non-null !!. JRA */
- user_struct *vuser = NULL;
- /* moved here due to initialization code (req for IRIX cc) */
+ /* get NIS home of a previously validated user - simeon */
+ /* With share level security vuid will always be zero.
+ Don't depend on vuser being non-null !!. JRA */
+ user_struct *vuser = NULL;
+ /* moved here due to initialization code (req for IRIX cc) */
VUSER_KEY;
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam, *rparam_len);
+
+ DEBUG(4, ("RNetUserGetInfo level=%d\n", uLevel));
- DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
-
/* check it's a supported variant */
- if (strcmp(str1,"zWrLh") != 0) return False;
- switch( uLevel )
- {
- case 0: p2 = "B21"; break;
- case 1: p2 = "B21BB16DWzzWz"; break;
- case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
- case 10: p2 = "B21Bzzz"; break;
- case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
+ if (strcmp(str1, "zWrLh") != 0)
+ return False;
+ switch (uLevel)
+ {
+ case 0:
+ p2 = "B21";
+ break;
+ case 1:
+ p2 = "B21BB16DWzzWz";
+ break;
+ case 2:
+ p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW";
+ break;
+ case 10:
+ p2 = "B21Bzzz";
+ break;
+ case 11:
+ p2 = "B21BzzzWDDzzDDWWzWzDWb21W";
+ break;
default:
{
vuid_free_user_struct(vuser);
@@ -2320,788 +2687,888 @@ static BOOL api_RNetUserGetInfo(connection_struct *conn,uint16 vuid, char *param
}
}
- if (strcmp(p2,str2) != 0)
+ if (strcmp(p2, str2) != 0)
+ {
+ return False;
+ }
+
+ vuser = get_valid_user_struct(&key);
+ if (vuser != NULL)
+ {
+ DEBUG(3,
+ (" Username of UID %d is %s\n", (int)vuser->uid,
+ vuser->name));
+ }
+ else
{
return False;
}
- vuser = get_valid_user_struct(&key);
- if (vuser != NULL)
- {
- DEBUG(3,(" Username of UID %d is %s\n", (int)vuser->uid, vuser->name));
- }
- else
- {
- return False;
- }
-
- unistr2_to_ascii(full_name, &vuser->usr.uni_full_name, sizeof(full_name)-1);
- unistr2_to_ascii(home_dir, &vuser->usr.uni_home_dir, sizeof(home_dir)-1);
- unistr2_to_ascii(nt_name, &vuser->usr.uni_user_name, sizeof(nt_name)-1);
- unistr2_to_ascii(logon_path, &vuser->usr.uni_logon_script, sizeof(logon_path)-1);
+ unistr2_to_ascii(full_name, &vuser->usr.uni_full_name,
+ sizeof(full_name) - 1);
+ unistr2_to_ascii(home_dir, &vuser->usr.uni_home_dir,
+ sizeof(home_dir) - 1);
+ unistr2_to_ascii(nt_name, &vuser->usr.uni_user_name,
+ sizeof(nt_name) - 1);
+ unistr2_to_ascii(logon_path, &vuser->usr.uni_logon_script,
+ sizeof(logon_path) - 1);
fstrcpy(logon_srv, "\\\\");
- unistr2_to_ascii(&logon_srv[2], &vuser->usr.uni_logon_srv, sizeof(logon_srv)-3);
+ unistr2_to_ascii(&logon_srv[2], &vuser->usr.uni_logon_srv,
+ sizeof(logon_srv) - 3);
*rdata_len = mdrcnt + 1024;
- *rdata = REALLOC(*rdata,*rdata_len);
+ *rdata = REALLOC(*rdata, *rdata_len);
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
+ SSVAL(*rparam, 0, NERR_Success);
+ SSVAL(*rparam, 2, 0); /* converter word */
p = *rdata;
p2 = p + usri11_end;
- memset(p,0,21);
- fstrcpy(p+usri11_name,nt_name); /* 21 bytes - user name */
+ memset(p, 0, 21);
+ fstrcpy(p + usri11_name, nt_name); /* 21 bytes - user name */
if (uLevel > 0)
{
- SCVAL(p,usri11_pad,0); /* padding - 1 byte */
+ SCVAL(p, usri11_pad, 0); /* padding - 1 byte */
*p2 = 0;
}
if (uLevel >= 10)
{
- SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
+ SIVAL(p, usri11_comment, PTR_DIFF(p2, p)); /* comment */
pstrcpy(p2, "");
- p2 = skip_string(p2,1);
+ p2 = skip_string(p2, 1);
- SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
+ SIVAL(p, usri11_usr_comment, PTR_DIFF(p2, p)); /* user_comment */
pstrcpy(p2, "");
- p2 = skip_string(p2,1);
+ p2 = skip_string(p2, 1);
/* EEK! the cifsrap.txt doesn't have this in!!!! */
- SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
+ SIVAL(p, usri11_full_name, PTR_DIFF(p2, p)); /* full name */
pstrcpy(p2, full_name);
- p2 = skip_string(p2,1);
+ p2 = skip_string(p2, 1);
}
- if (uLevel == 11) /* modelled after NTAS 3.51 reply */
- {
- SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
- 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 */
+ if (uLevel == 11) /* modelled after NTAS 3.51 reply */
+ {
+ SSVAL(p, usri11_priv,
+ conn->admin_user ? USER_PRIV_ADMIN : USER_PRIV_USER);
+ 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, home_dir);
- p2 = skip_string(p2,1);
- SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
- pstrcpy(p2,"");
- p2 = skip_string(p2,1);
- SIVAL(p,usri11_last_logon,0); /* last logon */
- SIVAL(p,usri11_last_logoff,0); /* last logoff */
- SSVALS(p,usri11_bad_pw_count,vuser->usr.bad_pw_count); /* bad pw counts */
- SSVALS(p,usri11_num_logons,vuser->usr.logon_count); /* num logons */
- SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
- pstrcpy(p2,logon_srv);
- p2 = skip_string(p2,1);
- SSVAL(p,usri11_country_code,0); /* country code */
-
- SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
+ p2 = skip_string(p2, 1);
+ SIVAL(p, usri11_parms, PTR_DIFF(p2, p)); /* parms */
+ pstrcpy(p2, "");
+ p2 = skip_string(p2, 1);
+ SIVAL(p, usri11_last_logon, 0); /* last logon */
+ SIVAL(p, usri11_last_logoff, 0); /* last logoff */
+ SSVALS(p, usri11_bad_pw_count, vuser->usr.bad_pw_count); /* bad pw counts */
+ SSVALS(p, usri11_num_logons, vuser->usr.logon_count); /* num logons */
+ SIVAL(p, usri11_logon_server, PTR_DIFF(p2, p)); /* logon server */
+ pstrcpy(p2, logon_srv);
+ p2 = skip_string(p2, 1);
+ SSVAL(p, usri11_country_code, 0); /* country code */
+
+ SIVAL(p, usri11_workstations, PTR_DIFF(p2, p)); /* workstations */
pstrcpy(p2, "");
- p2 = skip_string(p2,1);
+ p2 = skip_string(p2, 1);
- SIVALS(p,usri11_max_storage,-1); /* max storage */
- SSVAL(p,usri11_units_per_week,168); /* units per week */
- SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
+ SIVALS(p, usri11_max_storage, -1); /* max storage */
+ SSVAL(p, usri11_units_per_week, 168); /* units per week */
+ SIVAL(p, usri11_logon_hours, PTR_DIFF(p2, p)); /* logon hours */
/* a simple way to get logon hours at all times. */
- memset(p2,0xff,21);
- SCVAL(p2,21,0); /* fix zero termination */
- p2 = skip_string(p2,1);
+ memset(p2, 0xff, 21);
+ SCVAL(p2, 21, 0); /* fix zero termination */
+ p2 = skip_string(p2, 1);
- SSVAL(p,usri11_code_page,0); /* code page */
+ SSVAL(p, usri11_code_page, 0); /* code page */
}
if (uLevel == 1 || uLevel == 2)
{
- memset(p+22,' ',16); /* password */
- SIVALS(p,38,-1); /* password age */
- SSVAL(p,42,
- conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
- SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
- pstrcpy(p2,logon_path);
- p2 = skip_string(p2,1);
- SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
+ memset(p + 22, ' ', 16); /* password */
+ SIVALS(p, 38, -1); /* password age */
+ SSVAL(p, 42,
+ conn->admin_user ? USER_PRIV_ADMIN : USER_PRIV_USER);
+ SIVAL(p, 44, PTR_DIFF(p2, *rdata)); /* home dir */
+ pstrcpy(p2, logon_path);
+ 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 */
+ SSVAL(p, 52, 0); /* flags */
+ SIVAL(p, 54, 0); /* script_path */
if (uLevel == 2)
{
- SIVAL(p,60,0); /* auth_flags */
- SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
- pstrcpy(p2, nt_name);
- p2 = skip_string(p2,1);
- SIVAL(p,68,0); /* urs_comment */
- SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
- pstrcpy(p2,"");
- p2 = skip_string(p2,1);
- SIVAL(p,76,0); /* workstations */
- SIVAL(p,80,0); /* last_logon */
- SIVAL(p,84,0); /* last_logoff */
- SIVALS(p,88,-1); /* acct_expires */
- SIVALS(p,92,-1); /* max_storage */
- SSVAL(p,96,168); /* units_per_week */
- SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
- memset(p2,-1,21);
+ SIVAL(p, 60, 0); /* auth_flags */
+ SIVAL(p, 64, PTR_DIFF(p2, *rdata)); /* full_name */
+ pstrcpy(p2, nt_name);
+ p2 = skip_string(p2, 1);
+ SIVAL(p, 68, 0); /* urs_comment */
+ SIVAL(p, 72, PTR_DIFF(p2, *rdata)); /* parms */
+ pstrcpy(p2, "");
+ p2 = skip_string(p2, 1);
+ SIVAL(p, 76, 0); /* workstations */
+ SIVAL(p, 80, 0); /* last_logon */
+ SIVAL(p, 84, 0); /* last_logoff */
+ SIVALS(p, 88, -1); /* acct_expires */
+ SIVALS(p, 92, -1); /* max_storage */
+ SSVAL(p, 96, 168); /* units_per_week */
+ SIVAL(p, 98, PTR_DIFF(p2, *rdata)); /* logon_hours */
+ memset(p2, -1, 21);
p2 += 21;
- SSVALS(p,102,vuser->usr.bad_pw_count); /* bad_pw_count */
- SSVALS(p,104,vuser->usr.logon_count); /* num_logons */
- SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
- pstrcpy(p2,logon_srv);
- p2 = skip_string(p2,1);
- SSVAL(p,110,49); /* country_code */
- SSVAL(p,112,860); /* code page */
+ SSVALS(p, 102, vuser->usr.bad_pw_count); /* bad_pw_count */
+ SSVALS(p, 104, vuser->usr.logon_count); /* num_logons */
+ SIVAL(p, 106, PTR_DIFF(p2, *rdata)); /* logon_server */
+ pstrcpy(p2, logon_srv);
+ p2 = skip_string(p2, 1);
+ SSVAL(p, 110, 49); /* country_code */
+ SSVAL(p, 112, 860); /* code page */
}
}
- *rdata_len = PTR_DIFF(p2,*rdata);
+ *rdata_len = PTR_DIFF(p2, *rdata);
- SSVAL(*rparam,4,*rdata_len); /* is this right?? */
+ SSVAL(*rparam, 4, *rdata_len); /* is this right?? */
vuid_free_user_struct(vuser);
- return(True);
+ return (True);
}
/*******************************************************************
get groups that a user is a member of
******************************************************************/
-static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_NetUserGetGroups(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *UserName = skip_string(str2,1);
- char *p = skip_string(UserName,1);
- int uLevel = SVAL(p,0);
- char *p2;
- int count=0;
-
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- /* check it's a supported varient */
- if (strcmp(str1,"zWrLeh") != 0) return False;
- switch( uLevel ) {
- case 0: p2 = "B21"; break;
- default: return False;
- }
- if (strcmp(p2,str2) != 0) return False;
-
- *rdata_len = mdrcnt + 1024;
- *rdata = REALLOC(*rdata,*rdata_len);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *UserName = skip_string(str2, 1);
+ char *p = skip_string(UserName, 1);
+ int uLevel = SVAL(p, 0);
+ char *p2;
+ int count = 0;
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam, *rparam_len);
- p = *rdata;
+ /* check it's a supported varient */
+ if (strcmp(str1, "zWrLeh") != 0)
+ return False;
+ switch (uLevel)
+ {
+ case 0:
+ p2 = "B21";
+ break;
+ default:
+ return False;
+ }
+ if (strcmp(p2, str2) != 0)
+ return False;
- /* XXXX we need a real SAM database some day */
- pstrcpy(p,"Users"); p += 21; count++;
- pstrcpy(p,"Domain Users"); p += 21; count++;
- pstrcpy(p,"Guests"); p += 21; count++;
- pstrcpy(p,"Domain Guests"); p += 21; count++;
+ *rdata_len = mdrcnt + 1024;
+ *rdata = REALLOC(*rdata, *rdata_len);
- *rdata_len = PTR_DIFF(p,*rdata);
+ SSVAL(*rparam, 0, NERR_Success);
+ SSVAL(*rparam, 2, 0); /* converter word */
- SSVAL(*rparam,4,count); /* is this right?? */
- SSVAL(*rparam,6,count); /* is this right?? */
+ p = *rdata;
- return(True);
+ /* XXXX we need a real SAM database some day */
+ pstrcpy(p, "Users");
+ p += 21;
+ count++;
+ pstrcpy(p, "Domain Users");
+ p += 21;
+ count++;
+ pstrcpy(p, "Guests");
+ p += 21;
+ count++;
+ pstrcpy(p, "Domain Guests");
+ p += 21;
+ count++;
+
+ *rdata_len = PTR_DIFF(p, *rdata);
+
+ SSVAL(*rparam, 4, count); /* is this right?? */
+ SSVAL(*rparam, 6, count); /* is this right?? */
+
+ return (True);
}
-static BOOL api_WWkstaUserLogon(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_WWkstaUserLogon(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel;
- struct pack_desc desc;
- char* name;
- user_struct *vuser;
- VUSER_KEY;
- vuser = get_valid_user_struct(&key); /* moved due to VUSER_KEY initialization */
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ int uLevel;
+ struct pack_desc desc;
+ char *name;
+ user_struct *vuser;
+ VUSER_KEY;
+ vuser = get_valid_user_struct(&key); /* moved due to VUSER_KEY initialization */
if (vuser == NULL)
{
return False;
}
- uLevel = SVAL(p,0);
- name = p + 2;
-
- ZERO_STRUCT(desc);
-
- DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name));
-
- /* check it's a supported varient */
- if (strcmp(str1,"OOWb54WrLh") != 0) return False;
- if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False;
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- desc.subformat = NULL;
- desc.format = str2;
-
- if (init_package(&desc,1,0))
- {
- fstring nt_name;
- fstring logon_script;
- fstring logon_srv;
- fstring logon_dom;
-
- unistr2_to_ascii(nt_name, &vuser->usr.uni_user_name, sizeof(nt_name)-1);
- unistr2_to_ascii(logon_script, &vuser->usr.uni_logon_script, sizeof(logon_script)-1);
- unistr2_to_ascii(logon_dom, &vuser->usr.uni_logon_dom, sizeof(logon_dom)-1);
- fstrcpy(logon_srv, "\\\\");
- unistr2_to_ascii(&logon_srv[2], &vuser->usr.uni_logon_srv, sizeof(logon_srv)-3);
-
- PACKI(&desc,"W",0); /* code */
- PACKS(&desc,"B21",nt_name); /* eff. name */
- PACKS(&desc,"B",""); /* pad */
- PACKI(&desc,"W",
- conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
- PACKI(&desc,"D",0); /* auth flags XXX */
- PACKI(&desc,"W",0); /* num logons */
- PACKI(&desc,"W",0); /* bad pw count */
- PACKI(&desc,"D",0); /* last logon */
- PACKI(&desc,"D",-1); /* last logoff */
- PACKI(&desc,"D",-1); /* logoff time */
- PACKI(&desc,"D",-1); /* kickoff time */
- PACKI(&desc,"D",0); /* password age */
- PACKI(&desc,"D",0); /* password can change */
- PACKI(&desc,"D",-1); /* password must change */
- {
- PACKS(&desc,"z",logon_srv); /* computer */
- }
- PACKS(&desc,"z",logon_dom);/* domain */
- PACKS(&desc,"z", logon_script); /* script path */
-
- PACKI(&desc,"D",0x00000000); /* reserved */
- }
-
- *rdata_len = desc.usedlen;
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,desc.neededlen);
-
- DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode));
- vuid_free_user_struct(vuser);
-
- return(True);
+ uLevel = SVAL(p, 0);
+ name = p + 2;
+
+ ZERO_STRUCT(desc);
+
+ DEBUG(3, ("WWkstaUserLogon uLevel=%d name=%s\n", uLevel, name));
+
+ /* check it's a supported varient */
+ if (strcmp(str1, "OOWb54WrLh") != 0)
+ return False;
+ if (uLevel != 1 || strcmp(str2, "WB21BWDWWDDDDDDDzzzD") != 0)
+ return False;
+ if (mdrcnt > 0)
+ *rdata = REALLOC(*rdata, mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ desc.subformat = NULL;
+ desc.format = str2;
+
+ if (init_package(&desc, 1, 0))
+ {
+ fstring nt_name;
+ fstring logon_script;
+ fstring logon_srv;
+ fstring logon_dom;
+
+ unistr2_to_ascii(nt_name, &vuser->usr.uni_user_name,
+ sizeof(nt_name) - 1);
+ unistr2_to_ascii(logon_script, &vuser->usr.uni_logon_script,
+ sizeof(logon_script) - 1);
+ unistr2_to_ascii(logon_dom, &vuser->usr.uni_logon_dom,
+ sizeof(logon_dom) - 1);
+ fstrcpy(logon_srv, "\\\\");
+ unistr2_to_ascii(&logon_srv[2], &vuser->usr.uni_logon_srv,
+ sizeof(logon_srv) - 3);
+
+ PACKI(&desc, "W", 0); /* code */
+ PACKS(&desc, "B21", nt_name); /* eff. name */
+ PACKS(&desc, "B", ""); /* pad */
+ PACKI(&desc, "W",
+ conn->admin_user ? USER_PRIV_ADMIN : USER_PRIV_USER);
+ PACKI(&desc, "D", 0); /* auth flags XXX */
+ PACKI(&desc, "W", 0); /* num logons */
+ PACKI(&desc, "W", 0); /* bad pw count */
+ PACKI(&desc, "D", 0); /* last logon */
+ PACKI(&desc, "D", -1); /* last logoff */
+ PACKI(&desc, "D", -1); /* logoff time */
+ PACKI(&desc, "D", -1); /* kickoff time */
+ PACKI(&desc, "D", 0); /* password age */
+ PACKI(&desc, "D", 0); /* password can change */
+ PACKI(&desc, "D", -1); /* password must change */
+ {
+ PACKS(&desc, "z", logon_srv); /* computer */
+ }
+ PACKS(&desc, "z", logon_dom); /* domain */
+ PACKS(&desc, "z", logon_script); /* script path */
+
+ PACKI(&desc, "D", 0x00000000); /* reserved */
+ }
+
+ *rdata_len = desc.usedlen;
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVALS(*rparam, 0, desc.errcode);
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, desc.neededlen);
+
+ DEBUG(4, ("WWkstaUserLogon: errorcode %d\n", desc.errcode));
+ vuid_free_user_struct(vuser);
+
+ return (True);
}
/****************************************************************************
api_WAccessGetUserPerms
****************************************************************************/
-static BOOL api_WAccessGetUserPerms(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_WAccessGetUserPerms(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *user = skip_string(str2,1);
- char *resource = skip_string(user,1);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *user = skip_string(str2, 1);
+ char *resource = skip_string(user, 1);
- DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource));
+ DEBUG(3,
+ ("WAccessGetUserPerms user=%s resource=%s\n", user, resource));
- /* check it's a supported varient */
- if (strcmp(str1,"zzh") != 0) return False;
- if (strcmp(str2,"") != 0) return False;
+ /* check it's a supported varient */
+ if (strcmp(str1, "zzh") != 0)
+ return False;
+ if (strcmp(str2, "") != 0)
+ return False;
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,0); /* errorcode */
- SSVAL(*rparam,2,0); /* converter word */
- SSVAL(*rparam,4,0x7f); /* permission flags */
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVALS(*rparam, 0, 0); /* errorcode */
+ SSVAL(*rparam, 2, 0); /* converter word */
+ SSVAL(*rparam, 4, 0x7f); /* permission flags */
- return(True);
+ return (True);
}
/****************************************************************************
api_WPrintJobEnumerate
****************************************************************************/
-static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_WPrintJobGetInfo(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel;
- int count;
- int i;
- int snum;
- int job;
- struct pack_desc desc;
- print_queue_struct *queue=NULL;
- print_status_struct status;
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ int uLevel;
+ int count;
+ int i;
+ int snum;
+ int job;
+ struct pack_desc desc;
+ print_queue_struct *queue = NULL;
+ print_status_struct status;
VUSER_KEY;
- uLevel = SVAL(p,2);
+ uLevel = SVAL(p, 2);
- ZERO_STRUCT(desc);
- ZERO_STRUCT(status);
+ ZERO_STRUCT(desc);
+ ZERO_STRUCT(status);
- DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
+ DEBUG(3,
+ ("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n", uLevel,
+ SVAL(p, 0)));
- /* check it's a supported varient */
- if (strcmp(str1,"WWrLh") != 0) return False;
- if (!check_printjob_info(&desc,uLevel,str2)) return False;
+ /* check it's a supported varient */
+ if (strcmp(str1, "WWrLh") != 0)
+ return False;
+ if (!check_printjob_info(&desc, uLevel, str2))
+ return False;
- printjob_decode(SVAL(p,0), &snum, &job);
+ printjob_decode(SVAL(p, 0), &snum, &job);
- if (snum < 0 || !VALID_SNUM(snum)) return(False);
+ if (snum < 0 || !VALID_SNUM(snum))
+ return (False);
- count = get_printqueue(snum,conn,&key,&queue,&status);
- for (i = 0; i < count; i++) {
- if ((queue[i].job & 0xFF) == job) break;
- }
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
+ count = get_printqueue(snum, conn, &key, &queue, &status);
+ for (i = 0; i < count; i++)
+ {
+ if ((queue[i].job & 0xFF) == job)
+ break;
+ }
+ if (mdrcnt > 0)
+ *rdata = REALLOC(*rdata, mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
- if (init_package(&desc,1,0)) {
- if (i < count) {
- fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
- *rdata_len = desc.usedlen;
- }
- else {
- desc.errcode = NERR_JobNotFound;
- *rdata_len = 0;
- }
- }
+ if (init_package(&desc, 1, 0))
+ {
+ if (i < count)
+ {
+ fill_printjob_info(conn, snum, uLevel, &desc,
+ &queue[i], i);
+ *rdata_len = desc.usedlen;
+ }
+ else
+ {
+ desc.errcode = NERR_JobNotFound;
+ *rdata_len = 0;
+ }
+ }
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,desc.neededlen);
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVALS(*rparam, 0, desc.errcode);
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, desc.neededlen);
- if (queue) free(queue);
+ if (queue)
+ free(queue);
- DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode));
- return(True);
+ DEBUG(4, ("WPrintJobGetInfo: errorcode %d\n", desc.errcode));
+ return (True);
}
-static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_WPrintJobEnumerate(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- char* name = p;
- int uLevel;
- int count;
- int i, succnt=0;
- int snum;
- struct pack_desc desc;
- print_queue_struct *queue=NULL;
- print_status_struct status;
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ char *name = p;
+ int uLevel;
+ int count;
+ int i, succnt = 0;
+ int snum;
+ struct pack_desc desc;
+ print_queue_struct *queue = NULL;
+ print_status_struct status;
VUSER_KEY;
- ZERO_STRUCT(desc);
- ZERO_STRUCT(status);
+ ZERO_STRUCT(desc);
+ ZERO_STRUCT(status);
- p = skip_string(p,1);
- uLevel = SVAL(p,0);
+ p = skip_string(p, 1);
+ uLevel = SVAL(p, 0);
- DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
+ DEBUG(3, ("WPrintJobEnumerate uLevel=%d name=%s\n", uLevel, name));
- /* check it's a supported varient */
- if (strcmp(str1,"zWrLeh") != 0) return False;
- if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
- if (!check_printjob_info(&desc,uLevel,str2)) return False;
+ /* check it's a supported varient */
+ if (strcmp(str1, "zWrLeh") != 0)
+ return False;
+ if (uLevel > 2)
+ return False; /* defined only for uLevel 0,1,2 */
+ if (!check_printjob_info(&desc, uLevel, str2))
+ return False;
- snum = lp_servicenumber(name);
- if (snum < 0 && pcap_printername_ok(name,NULL)) {
- int pnum = lp_servicenumber(PRINTERS_NAME);
- if (pnum >= 0) {
- lp_add_printer(name,pnum);
- snum = lp_servicenumber(name);
- }
- }
+ snum = lp_servicenumber(name);
+ if (snum < 0 && pcap_printername_ok(name, NULL))
+ {
+ int pnum = lp_servicenumber(PRINTERS_NAME);
+ if (pnum >= 0)
+ {
+ lp_add_printer(name, pnum);
+ snum = lp_servicenumber(name);
+ }
+ }
- if (snum < 0 || !VALID_SNUM(snum)) return(False);
+ if (snum < 0 || !VALID_SNUM(snum))
+ return (False);
- count = get_printqueue(snum,conn,&key,&queue,&status);
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
+ count = get_printqueue(snum, conn, &key, &queue, &status);
+ if (mdrcnt > 0)
+ *rdata = REALLOC(*rdata, mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
- if (init_package(&desc,count,0)) {
- succnt = 0;
- for (i = 0; i < count; i++) {
- fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
- if (desc.errcode == NERR_Success) succnt = i+1;
- }
- }
+ if (init_package(&desc, count, 0))
+ {
+ succnt = 0;
+ for (i = 0; i < count; i++)
+ {
+ fill_printjob_info(conn, snum, uLevel, &desc,
+ &queue[i], i);
+ if (desc.errcode == NERR_Success)
+ succnt = i + 1;
+ }
+ }
- *rdata_len = desc.usedlen;
+ *rdata_len = desc.usedlen;
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,succnt);
- SSVAL(*rparam,6,count);
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVALS(*rparam, 0, desc.errcode);
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, succnt);
+ SSVAL(*rparam, 6, count);
- if (queue) free(queue);
+ if (queue)
+ free(queue);
- DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode));
- return(True);
+ DEBUG(4, ("WPrintJobEnumerate: errorcode %d\n", desc.errcode));
+ return (True);
}
-static int check_printdest_info(struct pack_desc* desc,
- int uLevel, char* id)
+static int check_printdest_info(struct pack_desc *desc, int uLevel, char *id)
{
- desc->subformat = NULL;
- switch( uLevel ) {
- case 0: desc->format = "B9"; break;
- case 1: desc->format = "B9B21WWzW"; break;
- case 2: desc->format = "z"; break;
- case 3: desc->format = "zzzWWzzzWW"; break;
- default: return False;
- }
- if (strcmp(desc->format,id) != 0) return False;
- return True;
+ desc->subformat = NULL;
+ switch (uLevel)
+ {
+ case 0:
+ desc->format = "B9";
+ break;
+ case 1:
+ desc->format = "B9B21WWzW";
+ break;
+ case 2:
+ desc->format = "z";
+ break;
+ case 3:
+ desc->format = "zzzWWzzzWW";
+ break;
+ default:
+ return False;
+ }
+ if (strcmp(desc->format, id) != 0)
+ return False;
+ return True;
}
-static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
- struct pack_desc* desc)
+static void fill_printdest_info(connection_struct * conn, int snum,
+ int uLevel, struct pack_desc *desc)
{
- char buf[100];
- strncpy(buf,SERVICE(snum),sizeof(buf)-1);
- buf[sizeof(buf)-1] = 0;
- strupper(buf);
- if (uLevel <= 1) {
- PACKS(desc,"B9",buf); /* szName */
- if (uLevel == 1) {
- PACKS(desc,"B21",""); /* szUserName */
- PACKI(desc,"W",0); /* uJobId */
- PACKI(desc,"W",0); /* fsStatus */
- PACKS(desc,"z",""); /* pszStatus */
- PACKI(desc,"W",0); /* time */
- }
- }
- if (uLevel == 2 || uLevel == 3) {
- PACKS(desc,"z",buf); /* pszPrinterName */
- if (uLevel == 3) {
- PACKS(desc,"z",""); /* pszUserName */
- PACKS(desc,"z",""); /* pszLogAddr */
- PACKI(desc,"W",0); /* uJobId */
- PACKI(desc,"W",0); /* fsStatus */
- PACKS(desc,"z",""); /* pszStatus */
- PACKS(desc,"z",""); /* pszComment */
- PACKS(desc,"z","NULL"); /* pszDrivers */
- PACKI(desc,"W",0); /* time */
- PACKI(desc,"W",0); /* pad1 */
- }
- }
+ char buf[100];
+ strncpy(buf, SERVICE(snum), sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+ strupper(buf);
+ if (uLevel <= 1)
+ {
+ PACKS(desc, "B9", buf); /* szName */
+ if (uLevel == 1)
+ {
+ PACKS(desc, "B21", ""); /* szUserName */
+ PACKI(desc, "W", 0); /* uJobId */
+ PACKI(desc, "W", 0); /* fsStatus */
+ PACKS(desc, "z", ""); /* pszStatus */
+ PACKI(desc, "W", 0); /* time */
+ }
+ }
+ if (uLevel == 2 || uLevel == 3)
+ {
+ PACKS(desc, "z", buf); /* pszPrinterName */
+ if (uLevel == 3)
+ {
+ PACKS(desc, "z", ""); /* pszUserName */
+ PACKS(desc, "z", ""); /* pszLogAddr */
+ PACKI(desc, "W", 0); /* uJobId */
+ PACKI(desc, "W", 0); /* fsStatus */
+ PACKS(desc, "z", ""); /* pszStatus */
+ PACKS(desc, "z", ""); /* pszComment */
+ PACKS(desc, "z", "NULL"); /* pszDrivers */
+ PACKI(desc, "W", 0); /* time */
+ PACKI(desc, "W", 0); /* pad1 */
+ }
+ }
}
-static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_WPrintDestGetInfo(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- char* PrinterName = p;
- int uLevel;
- struct pack_desc desc;
- int snum;
-
- ZERO_STRUCT(desc);
-
- p = skip_string(p,1);
- uLevel = SVAL(p,0);
-
- DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
-
- /* check it's a supported varient */
- if (strcmp(str1,"zWrLh") != 0) return False;
- if (!check_printdest_info(&desc,uLevel,str2)) return False;
-
- snum = lp_servicenumber(PrinterName);
- if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
- int pnum = lp_servicenumber(PRINTERS_NAME);
- if (pnum >= 0) {
- lp_add_printer(PrinterName,pnum);
- snum = lp_servicenumber(PrinterName);
- }
- }
-
- if (snum < 0) {
- *rdata_len = 0;
- desc.errcode = NERR_DestNotFound;
- desc.neededlen = 0;
- }
- else {
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- if (init_package(&desc,1,0)) {
- fill_printdest_info(conn,snum,uLevel,&desc);
- }
- *rdata_len = desc.usedlen;
- }
-
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,desc.neededlen);
-
- DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode));
- return(True);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ char *PrinterName = p;
+ int uLevel;
+ struct pack_desc desc;
+ int snum;
+
+ ZERO_STRUCT(desc);
+
+ p = skip_string(p, 1);
+ uLevel = SVAL(p, 0);
+
+ DEBUG(3,
+ ("WPrintDestGetInfo uLevel=%d PrinterName=%s\n", uLevel,
+ PrinterName));
+
+ /* check it's a supported varient */
+ if (strcmp(str1, "zWrLh") != 0)
+ return False;
+ if (!check_printdest_info(&desc, uLevel, str2))
+ return False;
+
+ snum = lp_servicenumber(PrinterName);
+ if (snum < 0 && pcap_printername_ok(PrinterName, NULL))
+ {
+ int pnum = lp_servicenumber(PRINTERS_NAME);
+ if (pnum >= 0)
+ {
+ lp_add_printer(PrinterName, pnum);
+ snum = lp_servicenumber(PrinterName);
+ }
+ }
+
+ if (snum < 0)
+ {
+ *rdata_len = 0;
+ desc.errcode = NERR_DestNotFound;
+ desc.neededlen = 0;
+ }
+ else
+ {
+ if (mdrcnt > 0)
+ *rdata = REALLOC(*rdata, mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ if (init_package(&desc, 1, 0))
+ {
+ fill_printdest_info(conn, snum, uLevel, &desc);
+ }
+ *rdata_len = desc.usedlen;
+ }
+
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVALS(*rparam, 0, desc.errcode);
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, desc.neededlen);
+
+ DEBUG(4, ("WPrintDestGetInfo: errorcode %d\n", desc.errcode));
+ return (True);
}
-static BOOL api_WPrintDestEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_WPrintDestEnum(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel;
- int queuecnt;
- int i, n, succnt=0;
- struct pack_desc desc;
- int services = lp_numservices();
-
- ZERO_STRUCT(desc);
-
- uLevel = SVAL(p,0);
-
- DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
-
- /* check it's a supported varient */
- if (strcmp(str1,"WrLeh") != 0) return False;
- if (!check_printdest_info(&desc,uLevel,str2)) return False;
-
- queuecnt = 0;
- for (i = 0; i < services; i++)
- if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
- queuecnt++;
-
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- if (init_package(&desc,queuecnt,0)) {
- succnt = 0;
- n = 0;
- for (i = 0; i < services; i++) {
- if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) {
- fill_printdest_info(conn,i,uLevel,&desc);
- n++;
- if (desc.errcode == NERR_Success) succnt = n;
- }
- }
- }
-
- *rdata_len = desc.usedlen;
-
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,succnt);
- SSVAL(*rparam,6,queuecnt);
-
- DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode));
- return(True);
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ int uLevel;
+ int queuecnt;
+ int i, n, succnt = 0;
+ struct pack_desc desc;
+ int services = lp_numservices();
+
+ ZERO_STRUCT(desc);
+
+ uLevel = SVAL(p, 0);
+
+ DEBUG(3, ("WPrintDestEnum uLevel=%d\n", uLevel));
+
+ /* check it's a supported varient */
+ if (strcmp(str1, "WrLeh") != 0)
+ return False;
+ if (!check_printdest_info(&desc, uLevel, str2))
+ return False;
+
+ queuecnt = 0;
+ for (i = 0; i < services; i++)
+ if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i))
+ queuecnt++;
+
+ if (mdrcnt > 0)
+ *rdata = REALLOC(*rdata, mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ if (init_package(&desc, queuecnt, 0))
+ {
+ succnt = 0;
+ n = 0;
+ for (i = 0; i < services; i++)
+ {
+ if (lp_snum_ok(i) && lp_print_ok(i)
+ && lp_browseable(i))
+ {
+ fill_printdest_info(conn, i, uLevel, &desc);
+ n++;
+ if (desc.errcode == NERR_Success)
+ succnt = n;
+ }
+ }
+ }
+
+ *rdata_len = desc.usedlen;
+
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVALS(*rparam, 0, desc.errcode);
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, succnt);
+ SSVAL(*rparam, 6, queuecnt);
+
+ DEBUG(4, ("WPrintDestEnumerate: errorcode %d\n", desc.errcode));
+ return (True);
}
-static BOOL api_WPrintDriverEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_WPrintDriverEnum(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel;
- int succnt;
- struct pack_desc desc;
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ int uLevel;
+ int succnt;
+ struct pack_desc desc;
- ZERO_STRUCT(desc);
+ ZERO_STRUCT(desc);
- uLevel = SVAL(p,0);
+ uLevel = SVAL(p, 0);
- DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel));
+ DEBUG(3, ("WPrintDriverEnum uLevel=%d\n", uLevel));
- /* check it's a supported varient */
- if (strcmp(str1,"WrLeh") != 0) return False;
- if (uLevel != 0 || strcmp(str2,"B41") != 0) return False;
+ /* check it's a supported varient */
+ if (strcmp(str1, "WrLeh") != 0)
+ return False;
+ if (uLevel != 0 || strcmp(str2, "B41") != 0)
+ return False;
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- if (init_package(&desc,1,0)) {
- PACKS(&desc,"B41","NULL");
- }
+ if (mdrcnt > 0)
+ *rdata = REALLOC(*rdata, mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ if (init_package(&desc, 1, 0))
+ {
+ PACKS(&desc, "B41", "NULL");
+ }
- succnt = (desc.errcode == NERR_Success ? 1 : 0);
+ succnt = (desc.errcode == NERR_Success ? 1 : 0);
- *rdata_len = desc.usedlen;
+ *rdata_len = desc.usedlen;
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,succnt);
- SSVAL(*rparam,6,1);
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVALS(*rparam, 0, desc.errcode);
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, succnt);
+ SSVAL(*rparam, 6, 1);
- DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode));
- return(True);
+ DEBUG(4, ("WPrintDriverEnum: errorcode %d\n", desc.errcode));
+ return (True);
}
-static BOOL api_WPrintQProcEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_WPrintQProcEnum(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel;
- int succnt;
- struct pack_desc desc;
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ int uLevel;
+ int succnt;
+ struct pack_desc desc;
- ZERO_STRUCT(desc);
+ ZERO_STRUCT(desc);
- uLevel = SVAL(p,0);
+ uLevel = SVAL(p, 0);
- DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel));
+ DEBUG(3, ("WPrintQProcEnum uLevel=%d\n", uLevel));
- /* check it's a supported varient */
- if (strcmp(str1,"WrLeh") != 0) return False;
- if (uLevel != 0 || strcmp(str2,"B13") != 0) return False;
+ /* check it's a supported varient */
+ if (strcmp(str1, "WrLeh") != 0)
+ return False;
+ if (uLevel != 0 || strcmp(str2, "B13") != 0)
+ return False;
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- desc.format = str2;
- if (init_package(&desc,1,0)) {
- PACKS(&desc,"B13","lpd");
- }
+ if (mdrcnt > 0)
+ *rdata = REALLOC(*rdata, mdrcnt);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ desc.format = str2;
+ if (init_package(&desc, 1, 0))
+ {
+ PACKS(&desc, "B13", "lpd");
+ }
- succnt = (desc.errcode == NERR_Success ? 1 : 0);
+ succnt = (desc.errcode == NERR_Success ? 1 : 0);
- *rdata_len = desc.usedlen;
+ *rdata_len = desc.usedlen;
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,succnt);
- SSVAL(*rparam,6,1);
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVALS(*rparam, 0, desc.errcode);
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, succnt);
+ SSVAL(*rparam, 6, 1);
- DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode));
- return(True);
+ DEBUG(4, ("WPrintQProcEnum: errorcode %d\n", desc.errcode));
+ return (True);
}
-static BOOL api_WPrintPortEnum(connection_struct *conn,uint16 vuid, char *param,char *data,
- int mdrcnt,int mprcnt,
- char **rdata,char **rparam,
- int *rdata_len,int *rparam_len)
+static BOOL api_WPrintPortEnum(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt,
+ int mprcnt, char **rdata, char **rparam,
+ int *rdata_len, int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *p = skip_string(str2,1);
- int uLevel;
- int succnt;
- struct pack_desc desc;
+ char *str1 = param + 2;
+ char *str2 = skip_string(str1, 1);
+ char *p = skip_string(str2, 1);
+ int uLevel;
+ int succnt;
+ struct pack_desc desc;
- ZERO_STRUCT(desc);
+ ZERO_STRUCT(desc);
- uLevel = SVAL(p,0);
+ uLevel = SVAL(p, 0);
- DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel));
+ DEBUG(3, ("WPrintPortEnum uLevel=%d\n", uLevel));
- /* check it's a supported varient */
- if (strcmp(str1,"WrLeh") != 0) return False;
- if (uLevel != 0 || strcmp(str2,"B9") != 0) return False;
+ /* check it's a supported varient */
+ if (strcmp(str1, "WrLeh") != 0)
+ return False;
+ if (uLevel != 0 || strcmp(str2, "B9") != 0)
+ return False;
- if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
- ZERO_STRUCT(desc);
- desc.base = *rdata;
- desc.buflen = mdrcnt;
- desc.format = str2;
- if (init_package(&desc,1,0)) {
- PACKS(&desc,"B13","lp0");
- }
+ if (mdrcnt > 0)
+ *rdata = REALLOC(*rdata, mdrcnt);
+ ZERO_STRUCT(desc);
+ desc.base = *rdata;
+ desc.buflen = mdrcnt;
+ desc.format = str2;
+ if (init_package(&desc, 1, 0))
+ {
+ PACKS(&desc, "B13", "lp0");
+ }
- succnt = (desc.errcode == NERR_Success ? 1 : 0);
+ succnt = (desc.errcode == NERR_Success ? 1 : 0);
- *rdata_len = desc.usedlen;
+ *rdata_len = desc.usedlen;
- *rparam_len = 8;
- *rparam = REALLOC(*rparam,*rparam_len);
- SSVALS(*rparam,0,desc.errcode);
- SSVAL(*rparam,2,0);
- SSVAL(*rparam,4,succnt);
- SSVAL(*rparam,6,1);
+ *rparam_len = 8;
+ *rparam = REALLOC(*rparam, *rparam_len);
+ SSVALS(*rparam, 0, desc.errcode);
+ SSVAL(*rparam, 2, 0);
+ SSVAL(*rparam, 4, succnt);
+ SSVAL(*rparam, 6, 1);
- DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode));
- return(True);
+ DEBUG(4, ("WPrintPortEnum: errorcode %d\n", desc.errcode));
+ return (True);
}
/****************************************************************************
- 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,
- int *rdata_len,int *rparam_len)
+static BOOL api_TooSmall(connection_struct * conn, uint16 vuid, char *param,
+ char *data, int mdrcnt, int mprcnt, char **rdata,
+ char **rparam, int *rdata_len, int *rparam_len)
{
- *rparam_len = MIN(*rparam_len,mprcnt);
- *rparam = REALLOC(*rparam,*rparam_len);
+ *rparam_len = MIN(*rparam_len, mprcnt);
+ *rparam = REALLOC(*rparam, *rparam_len);
- *rdata_len = 0;
+ *rdata_len = 0;
- SSVAL(*rparam,0,NERR_BufTooSmall);
+ SSVAL(*rparam, 0, NERR_BufTooSmall);
- DEBUG(3,("Supplied buffer too small in API command\n"));
+ DEBUG(3, ("Supplied buffer too small in API command\n"));
- return(True);
+ return (True);
}
/****************************************************************************
- 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,
- int *rdata_len,int *rparam_len)
+static BOOL api_Unsupported(connection_struct * conn, uint16 vuid,
+ char *param, char *data, int mdrcnt, int mprcnt,
+ char **rdata, char **rparam, int *rdata_len,
+ int *rparam_len)
{
- *rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam, *rparam_len);
- *rdata_len = 0;
+ *rdata_len = 0;
- SSVAL(*rparam,0,NERR_notsupported);
- SSVAL(*rparam,2,0); /* converter word */
+ SSVAL(*rparam, 0, NERR_notsupported);
+ SSVAL(*rparam, 2, 0); /* converter word */
- DEBUG(3,("Unsupported API command\n"));
+ DEBUG(3, ("Unsupported API command\n"));
- return(True);
+ return (True);
}
@@ -3109,111 +3576,179 @@ static BOOL api_Unsupported(connection_struct *conn,uint16 vuid, char *param,cha
struct
{
- char *name;
- int id;
- BOOL (*fn)(connection_struct *,uint16,char *,char *,
- int,int,char **,char **,int *,int *);
- int flags;
-} api_commands[] = {
- {"RNetShareEnum", 0, api_RNetShareEnum,0},
- {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
- {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
- {"RNetGroupGetUsers", 52, api_RNetGroupGetUsers,0},
- {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
- {"NetUserGetGroups", 59, api_NetUserGetGroups,0},
- {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
- {"DosPrintQEnum", 69, api_DosPrintQEnum,0},
- {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
- {"WPrintQueuePause", 74, api_WPrintQueuePurge,0},
- {"WPrintQueueResume", 75, api_WPrintQueuePurge,0},
- {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
- {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
- {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
- {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
- {"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
- {"WPrintDestEnum", 84, api_WPrintDestEnum,0},
- {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
- {"NetRemoteTOD", 91, api_NetRemoteTOD,0},
- {"WPrintQueuePurge", 103, api_WPrintQueuePurge,0},
- {"NetServerEnum", 104, api_RNetServerEnum,0},
- {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
- {"SetUserPassword", 115, api_SetUserPassword,0},
- {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
- {"PrintJobInfo", 147, api_PrintJobInfo,0},
- {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
- {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
- {"WPrintPortEnum", 207, api_WPrintPortEnum,0},
- {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
- {NULL, -1, api_Unsupported,0}};
+ char *name;
+ int id;
+ BOOL (*fn) (connection_struct *, uint16, char *, char *,
+ int, int, char **, char **, int *, int *);
+ int flags;
+} api_commands[] =
+{
+ {
+ "RNetShareEnum", 0, api_RNetShareEnum, 0}
+ ,
+ {
+ "RNetShareGetInfo", 1, api_RNetShareGetInfo, 0}
+ ,
+ {
+ "RNetServerGetInfo", 13, api_RNetServerGetInfo, 0}
+ ,
+ {
+ "RNetGroupGetUsers", 52, api_RNetGroupGetUsers, 0}
+ ,
+ {
+ "RNetUserGetInfo", 56, api_RNetUserGetInfo, 0}
+ ,
+ {
+ "NetUserGetGroups", 59, api_NetUserGetGroups, 0}
+ ,
+ {
+ "NetWkstaGetInfo", 63, api_NetWkstaGetInfo, 0}
+ ,
+ {
+ "DosPrintQEnum", 69, api_DosPrintQEnum, 0}
+ ,
+ {
+ "DosPrintQGetInfo", 70, api_DosPrintQGetInfo, 0}
+ ,
+ {
+ "WPrintQueuePause", 74, api_WPrintQueuePurge, 0}
+ ,
+ {
+ "WPrintQueueResume", 75, api_WPrintQueuePurge, 0}
+ ,
+ {
+ "WPrintJobEnumerate", 76, api_WPrintJobEnumerate, 0}
+ ,
+ {
+ "WPrintJobGetInfo", 77, api_WPrintJobGetInfo, 0}
+ ,
+ {
+ "RDosPrintJobDel", 81, api_RDosPrintJobDel, 0}
+ ,
+ {
+ "RDosPrintJobPause", 82, api_RDosPrintJobDel, 0}
+ ,
+ {
+ "RDosPrintJobResume", 83, api_RDosPrintJobDel, 0}
+ ,
+ {
+ "WPrintDestEnum", 84, api_WPrintDestEnum, 0}
+ ,
+ {
+ "WPrintDestGetInfo", 85, api_WPrintDestGetInfo, 0}
+ ,
+ {
+ "NetRemoteTOD", 91, api_NetRemoteTOD, 0}
+ ,
+ {
+ "WPrintQueuePurge", 103, api_WPrintQueuePurge, 0}
+ ,
+ {
+ "NetServerEnum", 104, api_RNetServerEnum, 0}
+ ,
+ {
+ "WAccessGetUserPerms", 105, api_WAccessGetUserPerms, 0}
+ ,
+ {
+ "SetUserPassword", 115, api_SetUserPassword, 0}
+ ,
+ {
+ "WWkstaUserLogon", 132, api_WWkstaUserLogon, 0}
+ ,
+ {
+ "PrintJobInfo", 147, api_PrintJobInfo, 0}
+ ,
+ {
+ "WPrintDriverEnum", 205, api_WPrintDriverEnum, 0}
+ ,
+ {
+ "WPrintQProcEnum", 206, api_WPrintQProcEnum, 0}
+ ,
+ {
+ "WPrintPortEnum", 207, api_WPrintPortEnum, 0}
+ ,
+ {
+ "SamOEMChangePassword", 214, api_SamOEMChangePassword, 0}
+ ,
+ {
+ NULL, -1, api_Unsupported, 0}
+};
/****************************************************************************
- handle remote api calls
+ Handle remote api calls
****************************************************************************/
-int api_reply(connection_struct *conn,uint16 vuid,char *outbuf,char *data,char *params,
- int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
+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;
- prs_struct rdata_buf;
- prs_struct rparam_buf;
- char *rdata = NULL;
- char *rparam = NULL;
- int rdata_len = 0;
- int rparam_len = 0;
- BOOL reply=False;
- int i;
-
- SMB_ASSERT(params != 0);
-
- api_command = SVAL(params,0);
-
- DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
- api_command,
- params+2,
- skip_string(params+2,1),
- tdscnt,tpscnt,mdrcnt,mprcnt));
-
- for (i=0;api_commands[i].name;i++)
- if (api_commands[i].id == api_command && api_commands[i].fn)
- {
- DEBUG(3,("Doing %s\n",api_commands[i].name));
- break;
- }
-
- rdata = (char *)malloc(1024); if (rdata) memset(rdata, 0, 1024);
- rparam = (char *)malloc(1024); if (rparam) memset(rparam, 0, 1024);
-
- if (!rdata || !rparam) {
- DEBUG(0,("api_reply: malloc fail !\n"));
- return -1;
- }
-
- reply = api_commands[i].fn(conn,vuid,params,data,mdrcnt,mprcnt,
- &rdata,&rparam,&rdata_len,&rparam_len);
-
-
- if (rdata_len > mdrcnt ||
- 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);
-
- prs_create(&rdata_buf , rdata , rdata_len , 0, False);
- prs_create(&rparam_buf, rparam, rparam_len, 0, False);
-
- /* now send the reply */
- send_trans_reply(outbuf, &rdata_buf, &rparam_buf, NULL, 0, 0, False);
-
- prs_free_data(&rdata_buf );
- prs_free_data(&rparam_buf);
-
- return(-1);
-}
+ int api_command;
+ prs_struct rdata_buf;
+ prs_struct rparam_buf;
+ char *rdata = NULL;
+ char *rparam = NULL;
+ int rdata_len = 0;
+ int rparam_len = 0;
+ BOOL reply = False;
+ int i;
+ if (params == 0)
+ {
+ DEBUG(0,("ERROR: NULL params in api_reply()\n"));
+ return 0;
+ }
+
+ api_command = SVAL(params, 0);
+
+ DEBUG(3,
+ ("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n",
+ api_command, params + 2, skip_string(params + 2, 1), tdscnt,
+ tpscnt, mdrcnt, mprcnt));
+
+ for (i = 0; api_commands[i].name; i++)
+ if (api_commands[i].id == api_command && api_commands[i].fn)
+ {
+ DEBUG(3, ("Doing %s\n", api_commands[i].name));
+ break;
+ }
+
+ rdata = (char *)malloc(1024);
+ if (rdata)
+ memset(rdata, 0, 1024);
+ rparam = (char *)malloc(1024);
+ if (rparam)
+ memset(rparam, 0, 1024);
+
+ if (!rdata || !rparam)
+ {
+ DEBUG(0, ("api_reply: malloc fail !\n"));
+ return -1;
+ }
+
+ reply = api_commands[i].fn(conn, vuid, params, data, mdrcnt, mprcnt,
+ &rdata, &rparam, &rdata_len, &rparam_len);
+
+
+ if (rdata_len > mdrcnt || 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);
+
+ prs_create(&rdata_buf, rdata, rdata_len, 0, False);
+ prs_create(&rparam_buf, rparam, rparam_len, 0, False);
+
+ /* now send the reply */
+ send_trans_reply(outbuf, &rdata_buf, &rparam_buf, NULL, 0, 0, False);
+
+ prs_free_data(&rdata_buf);
+ prs_free_data(&rparam_buf);
+
+ return (-1);
+}
diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c
index 6f63760819c..e47bcd896f6 100644
--- a/source/smbd/mangle.c
+++ b/source/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,18 +112,19 @@ 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 )
#define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_MASK )
-static ubi_cacheRoot mangled_cache[1] = { { { 0 }, 0, 0, 0, 0, 0, 0} };
+static ubi_cacheRoot mangled_cache[1] = { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 } };
static BOOL mc_initialized = False;
#define MANGLED_CACHE_MAX_ENTRIES 0
#define MANGLED_CACHE_MAX_MEMORY 16384
@@ -148,7 +151,7 @@ static void init_chartest( void )
char *illegalchars = "*\\/?<>|\":";
unsigned char *s;
- memset( (char *)chartest, 0, 256 );
+ memset( (char *)chartest, '\0', 256 );
for( s = (unsigned char *)illegalchars; *s; s++ )
chartest[*s] = ILLEGAL_MASK;
@@ -252,7 +255,7 @@ static BOOL is_illegal_name( char *name )
s = (unsigned char *)name;
while( *s )
{
- skip = skip_multibyte_char( *s );
+ skip = get_character_len( *s );
if( skip != 0 )
{
s += skip;
@@ -371,7 +374,7 @@ BOOL is_8_3( char *fname, BOOL check_case )
dot_pos = NULL;
while( *p )
{
- if( (skip = skip_multibyte_char( *p )) != 0 )
+ if( (skip = get_character_len( *p )) != 0 )
p += skip;
else
{
@@ -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 );
@@ -844,7 +878,7 @@ void mangle_name_83( char *s)
*p++ = 0;
while( *p && extlen < 3 )
{
- skip = skip_multibyte_char( *p );
+ skip = get_character_len( *p );
switch( skip )
{
case 2:
@@ -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;
@@ -878,7 +912,7 @@ void mangle_name_83( char *s)
while( *p && baselen < 5 )
{
- skip = skip_multibyte_char(*p);
+ skip = get_character_len(*p);
switch( skip )
{
case 2:
@@ -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/source/smbd/message.c b/source/smbd/message.c
index d13dfda1e02..cc329d61a65 100644
--- a/source/smbd/message.c
+++ b/source/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) {
@@ -62,6 +62,16 @@ static void msg_deliver(void)
return;
}
+ /*
+ * Incoming message is in DOS codepage format. Convert to UNIX in
+ * place.
+ */
+
+ if(msgpos > 0) {
+ msgbuf[msgpos] = '\0'; /* Ensure null terminated. */
+ dos_to_unix(msgbuf,True);
+ }
+
for (i=0;i<msgpos;) {
if (msgbuf[i]=='\r' && i<(msgpos-1) && msgbuf[i+1]=='\n') {
i++; continue;
@@ -74,10 +84,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 +112,6 @@ int reply_sends(connection_struct *conn,
msgpos = 0;
-
if (! (*lp_msg_command()))
return(ERROR(ERRSRV,ERRmsgoff));
@@ -113,7 +125,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 +154,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 +187,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 +217,3 @@ int reply_sendend(connection_struct *conn,
return(outsize);
}
-
diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c
index c077ed5e9aa..55e2e42d665 100644
--- a/source/smbd/negprot.c
+++ b/source/smbd/negprot.c
@@ -26,7 +26,6 @@ extern int Protocol;
extern int max_recv;
extern fstring global_myworkgroup;
extern fstring remote_machine;
-extern dfs_internal dfs_struct;
/****************************************************************************
reply for the core protocol
@@ -150,6 +149,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);
@@ -157,27 +166,6 @@ 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 (doencrypt) {
crypt_len = 8;
@@ -188,6 +176,11 @@ static int reply_nt1(char *outbuf)
capabilities |= CAP_RAW_MODE;
}
+#ifdef MS_DFS
+ if(lp_host_msdfs())
+ capabilities |= CAP_DFS;
+#endif
+
if (lp_security() >= SEC_USER) secword |= 1;
if (doencrypt) secword |= 2;
@@ -242,6 +235,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]
@@ -255,29 +256,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
+ 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 {
@@ -295,7 +298,7 @@ static struct {
{"MICROSOFT NETWORKS 3.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
{"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
{"PC NETWORK PROGRAM 1.0", "CORE", reply_corep, PROTOCOL_CORE},
- {NULL,NULL},
+ {NULL,NULL,NULL,0},
};
@@ -320,17 +323,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"))
@@ -354,8 +357,14 @@ int reply_negprot(connection_struct *conn,
set_remote_arch(RA_WIN95);
break;
case ARCH_WINNT:
+ if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE)
+ set_remote_arch(RA_WIN2K);
+ else
set_remote_arch(RA_WINNT);
break;
+ case ARCH_WIN2K:
+ set_remote_arch(RA_WIN2K);
+ break;
case ARCH_OS2:
set_remote_arch(RA_OS2);
break;
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
index b72507d4883..fd4d529b4b1 100644
--- a/source/smbd/nttrans.c
+++ b/source/smbd/nttrans.c
@@ -21,13 +21,13 @@
#include "includes.h"
#include "nterr.h"
+#include "sids.h"
extern int DEBUGLEVEL;
extern int Protocol;
extern int Client;
extern int smb_read_error;
extern int global_oplock_break;
-extern int chain_size;
extern BOOL case_sensitive;
extern BOOL case_preserve;
extern BOOL short_case_preserve;
@@ -37,10 +37,8 @@ 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",
@@ -58,7 +56,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 +76,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.
@@ -240,16 +245,15 @@ static int send_nt_replies(char *outbuf, int bufsize, char *params,
strings in NT calls AND DOESN'T SET THE UNICODE BIT !!!!!!!
****************************************************************************/
-static void my_wcstombs(char *dst, uint16 *src, size_t len)
+static void get_filename( char *fname, char *inbuf, int data_offset, int data_len, int fname_len)
{
- size_t i;
+ /*
+ * We need various heuristics here to detect a unicode string... JRA.
+ */
- for(i = 0; i < len; i++)
- dst[i] = (char)SVAL(src,i*2);
-}
+ DEBUG(10,("get_filename: data_offset = %d, data_len = %d, fname_len = %d\n",
+ data_offset, data_len, fname_len ));
-static void get_filename( char *fname, char *inbuf, int data_offset, int data_len, int fname_len)
-{
if(data_len - fname_len > 1) {
/*
* NT 5.0 Beta 2 has kindly sent us a UNICODE string
@@ -261,11 +265,46 @@ static void get_filename( char *fname, char *inbuf, int data_offset, int data_le
fname_len = fname_len/2;
if(data_offset & 1)
data_offset++;
- my_wcstombs( fname, (uint16 *)(inbuf+data_offset), fname_len);
+ pstrcpy(fname, dos_unistrn2((uint16 *)(inbuf+data_offset), fname_len));
} else {
StrnCpy(fname,inbuf+data_offset,fname_len);
+ fname[fname_len] = '\0';
+ }
+}
+
+/****************************************************************************
+ Fix bugs in Win2000 final release. In trans calls this OS sends unicode
+ strings AND DOESN'T SET THE UNICODE BIT !!!!!!!
+****************************************************************************/
+
+static void get_filename_transact( char *fname, char *inbuf, int data_offset, int data_len, int fname_len)
+{
+ /*
+ * We need various heuristics here to detect a unicode string... JRA.
+ */
+
+ DEBUG(10,("get_filename_transact: data_offset = %d, data_len = %d, fname_len = %d\n",
+ data_offset, data_len, fname_len ));
+
+ /*
+ * Win2K sends a unicode filename plus one extra alingment byte.
+ * WinNT4.x send an ascii string with multiple garbage bytes on
+ * the end here.
+ */
+
+ if((data_len - fname_len == 1) || (inbuf[data_offset] == '\0')) {
+ /*
+ * Ensure that the data offset is aligned
+ * on a 2 byte boundary - add one if not.
+ */
+ fname_len = fname_len/2;
+ if(data_offset & 1)
+ data_offset++;
+ pstrcpy(fname, dos_unistrn2((uint16 *)(inbuf+data_offset), fname_len));
+ } else {
+ StrnCpy(fname,inbuf+data_offset,fname_len);
+ fname[fname_len] = '\0';
}
- fname[fname_len] = '\0';
}
/****************************************************************************
@@ -355,18 +394,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 +432,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,20 +514,48 @@ 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.
****************************************************************************/
static int nt_open_pipe(char *fname, connection_struct *conn,
char *inbuf, char *outbuf, int *ppnum)
{
- vuser_key key;
pipes_struct *p = NULL;
-
+ vuser_key key;
uint16 vuid = SVAL(inbuf, smb_uid);
int i;
@@ -488,32 +566,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));
key.pid = getpid();
@@ -550,7 +611,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;
@@ -559,6 +620,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
@@ -579,8 +641,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.
@@ -598,31 +675,27 @@ int reply_ntcreate_and_X(connection_struct *conn,
dir_name_len++;
}
+ /*
+ * This next calculation can refuse a correct filename if we're dealing
+ * with the Win2k unicode bug, but that would be rare. JRA.
+ */
+
if(fname_len + dir_name_len >= sizeof(pstring))
return(ERROR(ERRSRV,ERRfilespecs));
get_filename(&fname[dir_name_len], inbuf, smb_buf(inbuf)-inbuf,
smb_buflen(inbuf),fname_len);
-#if 0
- StrnCpy(&fname[dir_name_len], smb_buf(inbuf),fname_len);
- fname[dir_name_len+fname_len] = '\0';
-#endif
} else {
get_filename(fname, inbuf, smb_buf(inbuf)-inbuf,
smb_buflen(inbuf),fname_len);
-
-#if 0
- StrnCpy(fname,smb_buf(inbuf),fname_len);
- fname[fname_len] = '\0';
-#endif
}
/* If it's an IPC, use the pipe handler. */
- if (IS_IPC(conn) && 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;
@@ -656,12 +729,15 @@ int reply_ntcreate_and_X(connection_struct *conn,
* Now contruct the smb_open_mode value from the filename,
* desired access and the share access.
*/
-
- if((smb_open_mode = map_share_mode(fname, desired_access,
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ 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.
@@ -673,11 +749,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) {
@@ -697,11 +769,8 @@ int reply_ntcreate_and_X(connection_struct *conn,
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
- unixmode = unix_mode(conn,smb_attr | aARCH);
+ unixmode = unix_mode(conn,smb_attr | aARCH, fname);
- 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.
*/
@@ -709,8 +778,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);
@@ -736,13 +805,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
@@ -755,21 +823,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;
@@ -785,15 +886,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(conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name, False), &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 (conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
close_file(fsp,False);
restore_case_semantics(file_attributes);
return(ERROR(ERRDOS,ERRnoaccess));
@@ -820,9 +919,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;
@@ -831,8 +930,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;
@@ -864,26 +969,15 @@ 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,
- char **ppsetup, char **ppparams,
- char **ppdata)
+ char *inbuf, char *outbuf, int length,
+ int bufsize, char **ppsetup, char **ppparams,
+ char **ppdata)
{
pstring fname;
char *params = *ppparams;
- uint32 flags = IVAL(params,0);
- uint32 desired_access = IVAL(params,8);
- uint32 file_attributes = IVAL(params,20);
- uint32 share_access = IVAL(params,24);
- uint32 create_disposition = IVAL(params,28);
- uint32 create_options = IVAL(params,32);
- uint32 fname_len = MIN(((uint32)IVAL(params,44)),
- ((uint32)sizeof(fname)-1));
- uint16 root_dir_fid = (uint16)IVAL(params,4);
- int smb_ofun;
- int smb_open_mode;
- int smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK);
+ int total_parameter_count = (int)IVAL(inbuf, smb_nt_TotalParameterCount);
/* Breakout the oplock request bits so we can set the
reply bits separately. */
int oplock_request = 0;
@@ -896,6 +990,39 @@ 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;
+ uint32 flags;
+ uint32 desired_access;
+ uint32 file_attributes;
+ uint32 share_access;
+ uint32 create_disposition;
+ uint32 create_options;
+ uint32 fname_len;
+ uint16 root_dir_fid;
+ int smb_ofun;
+ int smb_open_mode;
+ int smb_attr;
+
+ DEBUG(5,("call_nt_transact_create\n"));
+
+ /*
+ * Ensure minimum number of parameters sent.
+ */
+
+ if(total_parameter_count < 54) {
+ DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)total_parameter_count));
+ return(ERROR(ERRDOS,ERRbadaccess));
+ }
+
+ flags = IVAL(params,0);
+ desired_access = IVAL(params,8);
+ file_attributes = IVAL(params,20);
+ share_access = IVAL(params,24);
+ create_disposition = IVAL(params,28);
+ create_options = IVAL(params,32);
+ fname_len = MIN(((uint32)IVAL(params,44)),((uint32)sizeof(fname)-1));
+ root_dir_fid = (uint16)IVAL(params,4);
+ smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK);
/*
* We need to construct the open_and_X ofun value from the
@@ -903,7 +1030,7 @@ static int call_nt_transact_create(connection_struct *conn,
*/
if((smb_ofun = map_create_disposition( create_disposition )) == -1)
- return(ERROR(ERRDOS,ERRbadaccess));
+ return(ERROR(ERRDOS,ERRbadmem));
/*
* Get the file name.
@@ -917,8 +1044,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.
+ */
+
+ get_filename_transact(&fname[0], params, 53,
+ total_parameter_count - 53 - fname_len, 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.
@@ -936,15 +1079,20 @@ static int call_nt_transact_create(connection_struct *conn,
dir_name_len++;
}
+ /*
+ * This next calculation can refuse a correct filename if we're dealing
+ * with the Win2k unicode bug, but that would be rare. JRA.
+ */
+
if(fname_len + dir_name_len >= sizeof(pstring))
return(ERROR(ERRSRV,ERRfilespecs));
- StrnCpy(&fname[dir_name_len], params+53, fname_len);
- fname[dir_name_len+fname_len] = '\0';
+ get_filename_transact(&fname[dir_name_len], params, 53,
+ total_parameter_count - 53 - fname_len, fname_len);
} else {
- StrnCpy(fname,params+53,fname_len);
- fname[fname_len] = '\0';
+ get_filename_transact(&fname[0], params, 53,
+ total_parameter_count - 53 - fname_len, fname_len);
}
/* If it's an IPC, use the pipe handler. */
@@ -954,17 +1102,28 @@ 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);
+
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
- 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) {
@@ -984,19 +1143,8 @@ static int call_nt_transact_create(connection_struct *conn,
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
- unixmode = unix_mode(conn,smb_attr | aARCH);
+ unixmode = unix_mode(conn,smb_attr | aARCH, fname);
- 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.
*/
@@ -1015,37 +1163,97 @@ 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(conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name, False),
+ &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(conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name,False), &sbuf) != 0) {
+ close_file(fsp,True);
+ restore_case_semantics(file_attributes);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+ if (!fsp->stat_open && conn->vfs_ops.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)
@@ -1066,7 +1274,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;
}
}
@@ -1078,8 +1286,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);
@@ -1121,8 +1337,10 @@ static int call_nt_transact_create(connection_struct *conn,
SOFF_T(p,0,file_len);
}
+ DEBUG(5,("call_nt_transact_create: open name = %s\n", fname));
+
/* 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;
}
@@ -1159,6 +1377,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,
@@ -1182,7 +1401,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));
@@ -1194,6 +1413,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).
@@ -1204,9 +1435,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;
@@ -1247,8 +1478,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 );
@@ -1289,19 +1604,48 @@ static void remove_pending_change_notify_requests_by_mid(int mid)
}
/****************************************************************************
+ 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,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);
+ }
+}
+
+/****************************************************************************
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
@@ -1309,8 +1653,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);
@@ -1346,9 +1689,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.
*/
@@ -1359,13 +1702,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));
@@ -1381,22 +1723,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);
@@ -1417,28 +1771,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
@@ -1455,43 +1803,798 @@ 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;
+ }
+ make_sec_access(&sa,nt_mask);
+ return sa;
+}
+
+/****************************************************************************
+ Function to create owner and group SIDs from a SMB_STRUCT_STAT.
+****************************************************************************/
+
+static BOOL create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
+{
+ POSIX_ID id;
+
+ ZERO_STRUCTP(powner_sid);
+ ZERO_STRUCTP(pgroup_sid);
+ DEBUG(0,("TODO: create_file_sids: not ok to assume gid is NT group\n"));
+
+ id.type = SURS_POSIX_UID_AS_USR;
+ id.id = (uint32)psbuf->st_uid;
+
+ if (!surs_unixid_to_sam_sid(&id, powner_sid, False))
+ {
+ DEBUG(3,("create_file_sids: map uid %d failed\n",
+ (int)psbuf->st_uid));
+ return False;
+ }
+
+ id.type = SURS_POSIX_GID_AS_GRP;
+ id.id = (uint32)psbuf->st_gid;
+
+ if (!surs_unixid_to_sam_sid(&id, pgroup_sid, False))
+ {
+ DEBUG(3,("create_file_sids: map gid %d to group failed\n",
+ (int)psbuf->st_gid));
+
+ id.type = SURS_POSIX_GID_AS_ALS;
+ id.id = (uint32)psbuf->st_gid;
+
+ if (surs_unixid_to_sam_sid(&id, pgroup_sid, False))
+ {
+ return True;
+ }
+ DEBUG(3,("create_file_sids: map gid %d to alias failed\n",
+ (int)psbuf->st_gid));
+ return False;
+ }
+ return True;
+}
+
+/****************************************************************************
+ 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)
+{
+ SMB_STRUCT_STAT sbuf;
+ SEC_ACE *ace_list = NULL;
+ 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_everyone);
+ sid_copy( &group_sid, global_sid_everyone);
+ } else {
+
+ if(fsp->is_directory || fsp->fd_ptr == NULL) {
+ if(dos_stat(fsp->fsp_name, &sbuf) != 0)
+ {
+ return 0;
+ }
+ } else {
+ if(fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ return 0;
+ }
+ }
+
+ /*
+ * Get the owner, group and world SIDs.
+ */
+
+ if (!create_file_sids(&sbuf, &owner_sid, &group_sid))
+ {
+ DEBUG(3,("create_file_sids: uid or gid not mapped to SIDS\n"));
+ return 0;
+ }
+
+ /*
+ * 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)
+ {
+ ace_list = g_renew(SEC_ACE, ace_list, num_acls+1);
+ if (ace_list == NULL)
+ {
+ return 0;
+ }
+ make_sec_ace(&ace_list[num_acls++], &owner_sid, owner_acl_type,
+ owner_access, 0);
+ }
+
+ if(group_access.mask)
+ {
+ ace_list = g_renew(SEC_ACE, ace_list, num_acls+1);
+ if (ace_list == NULL)
+ {
+ return 0;
+ }
+
+ make_sec_ace(&ace_list[num_acls++], &group_sid, grp_acl_type,
+ group_access, 0);
+ }
+
+ if(other_access.mask)
+ {
+ ace_list = g_renew(SEC_ACE, ace_list, num_acls+1);
+ if (ace_list == NULL)
+ {
+ return 0;
+ }
+
+ make_sec_ace(&ace_list[num_acls++], global_sid_everyone, 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, fsp->fsp_name);
+
+ 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)
+ {
+ ace_list = g_renew(SEC_ACE, ace_list, num_acls+1);
+ if (ace_list == NULL)
+ {
+ return 0;
+ }
+
+ make_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)
+ {
+ ace_list = g_renew(SEC_ACE, ace_list, num_acls+1);
+ if (ace_list == NULL)
+ {
+ return 0;
+ }
+
+ make_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)
+ {
+ ace_list = g_renew(SEC_ACE, ace_list, num_acls+1);
+ if (ace_list == NULL)
+ {
+ return 0;
+ }
+
+ make_sec_ace(&ace_list[num_acls++], global_sid_everyone, other_acl_type,
+ other_access, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
+ }
+ }
+
+ if(num_acls)
+ {
+ psa = g_new(SEC_ACL, 1);
+ if (psa == NULL)
+ {
+ safe_free(ace_list);
+ }
+ if (!make_sec_acl( psa, 3, num_acls, ace_list))
+ {
+ DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
+ safe_free(ace_list);
+ safe_free(psa);
+ return 0;
+ }
+ }
+ }
+
+ (*ppdesc) = g_new(SEC_DESC, 1);
+
+ if((*ppdesc) == NULL)
+ {
+ DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
+ sec_desc_size = 0;
+ free_sec_acl(psa);
+ safe_free(psa);
+ return 0;
+ }
+
+ sec_desc_size = make_sec_desc( (*ppdesc), 1,
+ SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
+ sid_dup(&owner_sid),
+ sid_dup(&group_sid),
+ NULL, 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 = NULL;
+ 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);
+ safe_free(psd);
+
+ send_nt_replies(inbuf, outbuf, bufsize, 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);
+ safe_free(psd);
+ return(ERROR(ERRDOS,ERRnomem));
+ }
+
+ memset(data, '\0', sec_desc_size);
+
+ /*
+ * Init the parse struct we will marshall into.
+ */
+
+ prs_init(&pd, sec_desc_size, 4, MARSHALL);
+
+ /*
+ * Finally, linearize into the outgoing buffer.
+ */
+
+ if(!sec_io_desc( "sd data", psd, &pd, 1))
+ {
+ free_sec_desc(psd);
+ safe_free(psd);
+ prs_mem_free(&pd);
+ 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));
+ }
+
+ /*
+ * copy the data out of the marshalled structure
+ */
+
+ prs_link(NULL, &pd, NULL);
+ prs_buf_copy(data, &pd, 0, sec_desc_size);
+
+ /*
+ * Now we can delete the security descriptor.
+ */
+
+ prs_mem_free(&pd);
+ free_sec_desc(psd);
+ safe_free(psd);
+
+ send_nt_replies(inbuf, outbuf, bufsize, 0, params, 4, data, (int)sec_desc_size);
+ return -1;
+}
+
+/****************************************************************************
+ 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(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, mode_t *pmode,
+ uint32 security_info_sent, SEC_DESC *psd, BOOL is_directory)
+{
+ DOM_SID file_owner_sid;
+ DOM_SID file_grp_sid;
+ SEC_ACL *dacl = psd->dacl;
+ BOOL all_aces_are_inherit_only = (is_directory ? True : False);
+ int i;
+ POSIX_ID id;
+
+ *pmode = 0;
+ *puser = (uid_t)-1;
+ *pgrp = (gid_t)-1;
+
+ if(security_info_sent == 0) {
+ DEBUG(0,("unpack_nt_permissions: no security info sent !\n"));
+ return False;
+ }
+
+ /*
+ * Windows 2000 sends the owner and group SIDs as the logged in
+ * user, not the connected user. But it still sends the file
+ * owner SIDs on an ACL set. So we need to check for the file
+ * owner and group SIDs as well as the owner SIDs. JRA.
+ */
+
+ if (!create_file_sids(psbuf, &file_owner_sid, &file_grp_sid))
+ {
+ DEBUG(3,("create_file_sids: uid or gid not mapped to SIDS\n"));
+ return 0;
+ }
+
+ /*
+ * Don't immediately fail if the owner sid cannot be validated.
+ * This may be a group chown only set.
+ */
+
+ DEBUG(0,("TODO: LsaLookupSids to find type of owner_sid\n"));
+
+ if (security_info_sent & OWNER_SECURITY_INFORMATION &&
+ surs_sam_sid_to_unixid( psd->owner_sid, &id, False) &&
+ id.type == SURS_POSIX_UID_AS_USR)
+ {
+ *puser = (uid_t)id.id;
+ }
+
+ /*
+ * Don't immediately fail if the group sid cannot be validated.
+ * This may be an owner chown only set.
+ */
+
+ /*
+ * assume support for RID_TYPE_ALIAS and RID_TYPE_GROUP only.
+ * also assume that calls to sur_sam_sid_to_unixid are exclusive
+ * and one will fail where the other succeeds
+ */
+ if (security_info_sent & GROUP_SECURITY_INFORMATION &&
+ surs_sam_sid_to_unixid( psd->grp_sid, &id, False) &&
+ (id.type == SURS_POSIX_GID_AS_GRP || id.type == SURS_POSIX_GID_AS_ALS))
+ {
+ *pgrp = (gid_t)id.id;
+ }
+
+ /*
+ * 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[i];
+
+ if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) &&
+ (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
+ DEBUG(3,("unpack_nt_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_nt_permissions: ignoring inherit only ACE.\n"));
+ continue;
+ }
+
+ /*
+ * At least one of the ACE entries wasn't inherit only.
+ * Flag this so we know the returned mode is valid.
+ */
+
+ all_aces_are_inherit_only = False;
+ }
+
+ /*
+ * Windows 2000 sets these flags even on *file* ACE's. This is wrong
+ * but we can ignore them for now. Revisit this when we go to POSIX
+ * ACLs on directories.
+ */
+
+ psa->flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT);
+
+ if(psa->flags != 0) {
+ DEBUG(1,("unpack_nt_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, &file_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, &file_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_everyone)) {
+ /*
+ * 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_nt_permissions: unknown SID used in ACL.\n"));
+ return False;
+ }
+ }
+
+ if (is_directory && all_aces_are_inherit_only) {
+ /*
+ * Windows 2000 is doing one of these weird 'inherit acl'
+ * traverses to conserve NTFS ACL resources. Just pretend
+ * there was no DACL sent. JRA.
+ */
+
+ DEBUG(10,("unpack_nt_permissions: Win2k inherit acl traverse. Ignoring DACL.\n"));
+ free_sec_acl(psd->dacl);
+ safe_free(psd->dacl);
+ psd->dacl = NULL;
+ }
+
+ return True;
+}
+
/****************************************************************************
- Reply to set a security descriptor - currently this is not implemented (it
- is planned to be though).
+ 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;
+ 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 with a copy of the memory we just
+ * allocated. unmarshall from the beginning.
+ */
+
+ prs_append_data(&pd, data, total_data_count);
+
+ /*
+ * Finally, unmarshall from the data buffer.
+ */
+
+ if(!sec_io_desc( "sd data", &psd, &pd, 1))
+ {
+ free_sec_desc(&psd);
+ prs_mem_free(&pd);
+ 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));
+
+ /*
+ * finished with the marshalling structure, already
+ */
+
+ prs_mem_free(&pd);
+
+ /*
+ * Get the current state of the file.
+ */
+
+ if(fsp->is_directory) {
+ if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
+ free_sec_desc(&psd);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+
+ int ret;
+
+ if(fsp->fd_ptr == NULL)
+ ret = conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name,False), &sbuf);
+ else
+ ret = conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf);
+
+ if(ret != 0) {
+ free_sec_desc(&psd);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+
+ /*
+ * Unpack the user/group/world id's and permissions.
+ */
+
+ if(!unpack_nt_permissions( &sbuf, &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);
+
+ /*
+ * 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 = conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name,False), &sbuf);
+ else
+ ret = conn->vfs_ops.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(conn->vfs_ops.chmod(dos_to_unix(fsp->fsp_name, False), 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;
}
/****************************************************************************
@@ -1678,7 +2781,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/source/smbd/open.c b/source/smbd/open.c
index d63de45c7e0..ec092badc1d 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -25,7 +25,7 @@ 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
@@ -71,8 +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(dos_to_unix(fname,False),flags,mode))
- == -1)
+ if ((fd = conn->vfs_ops.open(dos_to_unix(fname,False),flags,mode)) == -1)
p[max_len] = tmp;
}
}
@@ -84,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))
@@ -95,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;
@@ -112,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;
@@ -121,14 +123,15 @@ 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)
+
+static void fd_attempt_reopen(char *fname, mode_t mode, files_struct *fsp)
{
- int fd = dos_open( fname, O_RDWR, mode);
+ int fd = fsp->conn->vfs_ops.open(dos_to_unix(fname, False), O_RDWR, mode);
+ file_fd_struct *fd_ptr = fsp->fd_ptr;
if(fd == -1)
return;
@@ -146,18 +149,21 @@ 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(files_struct *fsp, int *err_ret)
{
extern struct current_user current_user;
- file_fd_struct *fd_ptr = fsp->fd_ptr;
+ file_fd_struct *fd_ptr;
uint16 ret_ref;
- if (fd_ptr != NULL) {
- ret_ref = fd_ptr->ref_count;
- } else {
+ *err_ret = 0;
+
+ if ((fsp == NULL) || (fsp->fd_ptr == NULL)) {
return 0;
}
+ fd_ptr = fsp->fd_ptr;
+ ret_ref = fd_ptr->ref_count;
+
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,
fd_ptr->real_open_flags,
@@ -169,12 +175,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(fsp->conn->vfs_ops.close(fd_ptr->fd) < 0)
+ *err_ret = errno;
+ }
+
+ if(fd_ptr->fd_readonly != -1) {
+ if(fsp->conn->vfs_ops.close(fd_ptr->fd_readonly) < 0) {
+ if(*err_ret == 0)
+ *err_ret = errno;
+ }
+ }
+
+ if(fd_ptr->fd_writeonly != -1) {
+ if(fsp->conn->vfs_ops.close(fd_ptr->fd_writeonly) < 0) {
+ if(*err_ret == 0)
+ *err_ret = errno;
+ }
+ }
+
/*
* Delete this fd_ptr.
*/
@@ -183,7 +203,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;
}
/****************************************************************************
@@ -199,8 +219,16 @@ static BOOL check_access_allowed_for_current_user(struct connection_struct
{
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;
}
@@ -210,11 +238,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);
@@ -250,7 +290,7 @@ static BOOL check_access_allowed_for_current_user(struct connection_struct
/* Access denied. */
_exit(EACCES);
}
- close(fd);
+ conn->vfs_ops.close(fd);
DEBUG(9,("check_access_allowed_for_current_user: Child - returning ok.\n"));
_exit(0);
}
@@ -261,11 +301,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));
@@ -277,6 +318,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)
{
@@ -288,7 +330,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);
@@ -305,7 +347,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));
@@ -397,7 +439,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
* between the last open and now.
*/
if(fd_ptr->real_open_flags != O_RDWR)
- fd_attempt_reopen(fname, mode, fd_ptr);
+ fd_attempt_reopen(fname, mode, fsp);
/*
* Ensure that if we wanted write access
@@ -459,10 +501,11 @@ 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(dos_to_unix(dname,False),&dum1,&dum2,&dum3) <
+ if (conn->vfs_ops.disk_free(dos_to_unix(dname,False),False,&dum1,&dum2,&dum3) <
(SMB_BIG_UINT)lp_minprintspace(SNUM(conn))) {
- if(fd_attempt_close(fsp) == 0)
- conn->vfs_ops.unlink(dos_to_unix(fname,False));
+ int err;
+ if(fd_attempt_close(fsp, &err) == 0)
+ conn->vfs_ops.unlink(dos_to_unix(fname, False));
fsp->fd_ptr = 0;
errno = ENOSPC;
return;
@@ -471,10 +514,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(fsp,&err);
check_for_pipe(fname);
return;
}
@@ -484,11 +528,12 @@ 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) {
+ 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(fsp,&err);
return;
}
sbuf = &statbuf;
@@ -506,17 +551,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
@@ -527,6 +572,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
@@ -549,47 +595,19 @@ 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,
+
+static void truncate_unless_locked(files_struct *fsp, connection_struct *conn, int token,
BOOL *share_locked)
{
if (fsp->can_write){
SMB_OFF_T mask2 = ((SMB_OFF_T)0x3) << (SMB_OFF_T_BITS-4);
SMB_OFF_T mask = (mask2<<2);
- if (is_locked(fsp,conn,~mask,0,F_WRLCK)){
+ if (is_locked(fsp,conn,~mask,0,WRITE_LOCK)){
/* If share modes are in force for this connection we
have the share entry locked. Unlock it before closing. */
if (*share_locked && lp_share_modes(SNUM(conn)))
@@ -608,63 +626,121 @@ static void truncate_unless_locked(files_struct *fsp, connection_struct *conn,
}
+/*******************************************************************
+return True if the filename is one of the special executable types
+********************************************************************/
+static BOOL is_executable(char *fname)
+{
+ if ((fname = strrchr(fname,'.'))) {
+ if (strequal(fname,".com") ||
+ strequal(fname,".dll") ||
+ strequal(fname,".exe") ||
+ strequal(fname,".sym")) {
+ return True;
+ }
+ }
+ return False;
+}
+
enum {AFAIL,AREAD,AWRITE,AALL};
/*******************************************************************
reproduce the share mode access table
+this is horrendoously complex, and really can't be justified on any
+rational grounds except that this is _exactly_ what NT does. See
+the DENY1 and DENY2 tests in smbtorture for a comprehensive set of
+test routines.
********************************************************************/
static int access_table(int new_deny,int old_deny,int old_mode,
- int share_pid,char *fname)
+ BOOL same_pid, BOOL isexe)
{
- if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL);
-
- if (new_deny == DENY_DOS || old_deny == DENY_DOS) {
- int pid = getpid();
- if (old_deny == new_deny && share_pid == pid)
- return(AALL);
-
- if (old_mode == 0) return(AREAD);
-
- /* the new smbpub.zip spec says that if the file extension is
- .com, .dll, .exe or .sym then allow the open. I will force
- it to read-only as this seems sensible although the spec is
- a little unclear on this. */
- if ((fname = strrchr(fname,'.'))) {
- if (strequal(fname,".com") ||
- strequal(fname,".dll") ||
- strequal(fname,".exe") ||
- strequal(fname,".sym"))
- return(AREAD);
- }
+ if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL);
- return(AFAIL);
- }
+ if (same_pid) {
+ if (isexe && old_mode == DOS_OPEN_RDONLY &&
+ old_deny == DENY_DOS && new_deny == DENY_READ) {
+ return AFAIL;
+ }
+ if (!isexe && old_mode == DOS_OPEN_RDONLY &&
+ old_deny == DENY_DOS && new_deny == DENY_DOS) {
+ return AREAD;
+ }
+ if (new_deny == DENY_FCB && old_deny == DENY_DOS) {
+ if (isexe) return AFAIL;
+ if (old_mode == DOS_OPEN_RDONLY) return AFAIL;
+ return AALL;
+ }
+ if (old_mode == DOS_OPEN_RDONLY && old_deny == DENY_DOS) {
+ if (new_deny == DENY_FCB || new_deny == DENY_READ) {
+ if (isexe) return AREAD;
+ return AFAIL;
+ }
+ }
+ if (old_deny == DENY_FCB) {
+ if (new_deny == DENY_DOS || new_deny == DENY_FCB) return AALL;
+ return AFAIL;
+ }
+ }
- switch (new_deny)
- {
- case DENY_WRITE:
- if (old_deny==DENY_WRITE && old_mode==0) return(AREAD);
- if (old_deny==DENY_READ && old_mode==0) return(AWRITE);
- if (old_deny==DENY_NONE && old_mode==0) return(AALL);
- return(AFAIL);
- case DENY_READ:
- if (old_deny==DENY_WRITE && old_mode==1) return(AREAD);
- if (old_deny==DENY_READ && old_mode==1) return(AWRITE);
- if (old_deny==DENY_NONE && old_mode==1) return(AALL);
- return(AFAIL);
- case DENY_NONE:
- if (old_deny==DENY_WRITE) return(AREAD);
- if (old_deny==DENY_READ) return(AWRITE);
- if (old_deny==DENY_NONE) return(AALL);
- return(AFAIL);
- }
- return(AFAIL);
+ if (old_deny == DENY_DOS || new_deny == DENY_DOS ||
+ old_deny == DENY_FCB || new_deny == DENY_FCB) {
+ if (isexe) {
+ if (old_deny == DENY_FCB || new_deny == DENY_FCB) {
+ return AFAIL;
+ }
+ if (old_deny == DENY_DOS) {
+ if (new_deny == DENY_READ &&
+ (old_mode == DOS_OPEN_RDONLY ||
+ old_mode == DOS_OPEN_RDWR)) {
+ return AFAIL;
+ }
+ if (new_deny == DENY_WRITE &&
+ (old_mode == DOS_OPEN_WRONLY ||
+ old_mode == DOS_OPEN_RDWR)) {
+ return AFAIL;
+ }
+ return AALL;
+ }
+ if (old_deny == DENY_NONE) return AALL;
+ if (old_deny == DENY_READ) return AWRITE;
+ if (old_deny == DENY_WRITE) return AREAD;
+ }
+ /* it isn't a exe, dll, sym or com file */
+ if (old_deny == new_deny && same_pid)
+ return(AALL);
+
+ if (old_deny == DENY_READ || new_deny == DENY_READ) return AFAIL;
+ if (old_mode == DOS_OPEN_RDONLY) return(AREAD);
+
+ return(AFAIL);
+ }
+
+ switch (new_deny)
+ {
+ case DENY_WRITE:
+ if (old_deny==DENY_WRITE && old_mode==DOS_OPEN_RDONLY) return(AREAD);
+ if (old_deny==DENY_READ && old_mode==DOS_OPEN_RDONLY) return(AWRITE);
+ if (old_deny==DENY_NONE && old_mode==DOS_OPEN_RDONLY) return(AALL);
+ return(AFAIL);
+ case DENY_READ:
+ if (old_deny==DENY_WRITE && old_mode==DOS_OPEN_WRONLY) return(AREAD);
+ if (old_deny==DENY_READ && old_mode==DOS_OPEN_WRONLY) return(AWRITE);
+ if (old_deny==DENY_NONE && old_mode==DOS_OPEN_WRONLY) return(AALL);
+ return(AFAIL);
+ case DENY_NONE:
+ if (old_deny==DENY_WRITE) return(AREAD);
+ if (old_deny==DENY_READ) return(AWRITE);
+ if (old_deny==DENY_NONE) return(AALL);
+ return(AFAIL);
+ }
+ 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)
@@ -686,29 +762,18 @@ static int check_share_mode( share_mode_entry *share, int deny_mode,
return False;
}
- if (old_deny_mode > 4 || old_open_mode > 2)
- {
- DEBUG(0,("Invalid share mode found (%d,%d,%d) on file %s\n",
- deny_mode,old_deny_mode,old_open_mode,fname));
-
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadshare;
-
- return False;
- }
-
{
int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
- share->pid,fname);
+ (share->pid == getpid()),is_executable(fname));
if ((access_allowed == AFAIL) ||
(!fcbopen && (access_allowed == AREAD && *flags == O_RDWR)) ||
- (access_allowed == AREAD && *flags == O_WRONLY) ||
- (access_allowed == AWRITE && *flags == O_RDONLY))
+ (access_allowed == AREAD && *flags != O_RDONLY) ||
+ (access_allowed == AWRITE && *flags != O_WRONLY))
{
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;
@@ -727,33 +792,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 = vfs_file_exist(conn, fname, &sbuf);
BOOL share_locked = False;
BOOL fcbopen = False;
+ 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,".+,;=[]."))
{
@@ -832,9 +903,6 @@ void open_file_shared(files_struct *fsp, connection_struct *conn,
return;
}
- if (deny_mode == DENY_FCB)
- deny_mode = DENY_DOS;
-
if (lp_share_modes(SNUM(conn)))
{
int i;
@@ -861,6 +929,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 +942,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 +965,10 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
}
lock_share_entry(conn, dev, inode);
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 +987,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, dev, inode, &old_shares);
+ oplock_contention_count++;
}
} while(broke_oplock);
}
@@ -921,6 +996,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 +1065,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;
}
@@ -998,14 +1086,7 @@ 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,&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);
+ truncate_unless_locked(fsp,conn,token,&share_locked);
}
if (share_locked && lp_share_modes(SNUM(conn)))
@@ -1013,6 +1094,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(conn->vfs_ops.stat(dos_to_unix(fname, False), 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.key.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 +1165,56 @@ 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(conn->vfs_ops.stat(dos_to_unix(fname, False), &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 {
- *action = FILE_WAS_CREATED;
+ /*
+ * Try and create the directory.
+ */
+
+ if(!CAN_WRITE(conn)) {
+ DEBUG(2,("open_directory: failing create on read-only share\n"));
+ errno = EACCES;
+ return -1;
+ }
+
+ if(conn->vfs_ops.mkdir(dos_to_unix(fname, False),
+ unix_mode(conn,aDIR, fname)) < 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 +1224,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 +1243,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 +1267,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)
@@ -1106,7 +1279,7 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)
share_mode_entry *old_shares = 0;
int num_share_modes;
SMB_STRUCT_STAT sbuf;
- int pid = getpid();
+ pid_t pid = getpid();
SMB_DEV_T dev;
SMB_INO_T inode;
@@ -1143,9 +1316,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
@@ -1175,6 +1355,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, \
@@ -1210,7 +1391,8 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
* if we can too.
*/
- if ((GET_DENY_MODE(share_entry->share_mode) != DENY_DOS) || (share_entry->pid != pid))
+ if ((GET_DENY_MODE(share_entry->share_mode) != DENY_DOS) ||
+ (share_entry->pid != pid))
goto free_and_exit;
} /* end for */
diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c
index 48d92c35699..4b6e3962b89 100644
--- a/source/smbd/oplock.c
+++ b/source/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;
@@ -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,NULL,&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,90 @@ 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)
+{
+ 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) == 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(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(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);
+ return ret;
}
/****************************************************************************
@@ -358,14 +459,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 +485,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 +502,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 +516,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 +528,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 +569,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 +594,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 +615,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 +625,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);
- ZERO_STRUCT(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 +634,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 +715,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 +733,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) == 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(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);
+
+ 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 +874,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 +900,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. */
- 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);
- /* 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 +946,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 +1000,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 +1038,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 +1064,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 +1092,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 +1104,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 */
- ZERO_STRUCT(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 +1139,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 +1152,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 +1192,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 +1203,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 +1224,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 +1302,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/source/smbd/password.c b/source/smbd/password.c
index a4229242b3d..e75f304c475 100644
--- a/source/smbd/password.c
+++ b/source/smbd/password.c
@@ -25,7 +25,7 @@ extern int DEBUGLEVEL;
extern int Protocol;
/* users from session setup */
-static pstring session_users="";
+static pstring session_users = "";
extern pstring scope;
extern pstring global_myname;
@@ -37,21 +37,23 @@ add a name to the session users list
****************************************************************************/
void add_session_user(char *user)
{
- fstring suser;
- StrnCpy(suser,user,sizeof(suser)-1);
+ fstring suser;
+ StrnCpy(suser, user, sizeof(suser) - 1);
- if (!Get_Pwnam(suser,True)) return;
+ if (!Get_Pwnam(suser, True))
+ return;
- if (suser && *suser && !in_list(suser,session_users,False))
- {
- if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
- DEBUG(1,("Too many session users??\n"));
- else
+ if (suser && *suser && !in_list(suser, session_users, False))
{
- pstrcat(session_users," ");
- pstrcat(session_users,suser);
+ if (strlen(suser) + strlen(session_users) + 2 >=
+ sizeof(pstring))
+ DEBUG(1, ("Too many session users??\n"));
+ else
+ {
+ pstrcat(session_users, " ");
+ pstrcat(session_users, suser);
+ }
}
- }
}
/****************************************************************************
@@ -60,10 +62,9 @@ database or the encrypted SMB password database
return True if the password is correct, False otherwise
****************************************************************************/
BOOL password_ok(const char *orig_user, const char *domain,
- const char *smb_apasswd, int smb_apasslen,
- const char *smb_ntpasswd, int smb_ntpasslen,
- struct passwd *pwd,
- NET_USER_INFO_3 *info3)
+ const char *smb_apasswd, int smb_apasslen,
+ const char *smb_ntpasswd, int smb_ntpasslen,
+ struct passwd *pwd, NET_USER_INFO_3 * info3)
{
uchar last_chal[8];
BOOL cleartext = smb_apasslen != 24 && smb_ntpasslen == 0;
@@ -71,7 +72,7 @@ BOOL password_ok(const char *orig_user, const char *domain,
if (info3 == NULL)
{
- DEBUG(0,("password_ok: no NET_USER_INFO_3 parameter!\n"));
+ DEBUG(0, ("password_ok: no NET_USER_INFO_3 parameter!\n"));
return False;
}
@@ -83,7 +84,7 @@ BOOL password_ok(const char *orig_user, const char *domain,
(lp_encrypted_passwords() && smb_apasslen == 0 &&
lp_null_passwords()))
{
- DEBUG(10,("password_ok: check SMB auth\n"));
+ DEBUG(10, ("password_ok: check SMB auth\n"));
/* check security = user / domain */
if ((!cleartext) && last_challenge(last_chal))
@@ -97,21 +98,22 @@ BOOL password_ok(const char *orig_user, const char *domain,
smb_ntpasswd, smb_ntpasslen,
info3) == 0x0)
{
- DEBUG(10,("password_ok: domain auth succeeded\n"));
+ DEBUG(10, ("password_ok: domain auth succeeded\n"));
return True;
}
}
- DEBUG(10,("password_ok: check Unix auth\n"));
+ DEBUG(10, ("password_ok: check Unix auth\n"));
/*
* unix password check
*/
if (!lp_update_encrypted())
{
- if (pass_check(orig_user, smb_apasswd, smb_apasslen, pwd, NULL))
+ if (pass_check
+ (orig_user, smb_apasswd, smb_apasslen, pwd, NULL))
{
- DEBUG(10,("password_ok: Unix auth succeeded\n"));
+ DEBUG(10, ("password_ok: Unix auth succeeded\n"));
return True;
}
}
@@ -119,126 +121,171 @@ BOOL password_ok(const char *orig_user, const char *domain,
}
-
-
/****************************************************************************
validate a group username entry. Return the username or NULL
****************************************************************************/
-static char *validate_group(char *group,char *password,int pwlen,int snum,
- NET_USER_INFO_3 *info3)
+static char *validate_group(char *group, char *password, int pwlen, int snum,
+ NET_USER_INFO_3 *info3)
{
-#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,NULL,password,pwlen,NULL,0,NULL,info3))
+#ifdef HAVE_NETGROUP
+ char *host, *user, *domain;
+#endif
+#ifdef HAVE_GETGRENT
+ struct group *gptr;
+ pstring member_list;
+ char *member;
+ size_t copied_len = 0;
+ int i;
+#endif
+
+#ifdef HAVE_NETGROUP
+
+ setnetgrent(group);
+ while (getnetgrent(&host, &user, &domain))
{
- endnetgrent();
- return(user);
+ if (user)
+ {
+ if (user_ok(user, snum) &&
+ password_ok(user, NULL, password, pwlen,
+ NULL, 0, NULL, info3))
+ {
+ 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,NULL,password,pwlen,NULL,0,NULL, info3))
- return(&name[0]);
- member++;
- }
-#ifdef GROUP_CHECK_PWENT
+
+#ifdef HAVE_GETGRENT
+
+ setgrent();
+ while ((gptr = (struct group *)getgrent()))
+ {
+ if (strequal(gptr->gr_name, group))
+ break;
+ }
+
+ /*
+ * As user_ok can recurse doing a getgrent(), we must
+ * copy the member list into a pstring on the stack before
+ * use. Bug pointed out by leon@eatworms.swmed.edu.
+ */
+
+ if (gptr == NULL)
+ {
+ endgrent();
+ return NULL;
+ }
+
+ *member_list = '\0';
+ member = member_list;
+
+ for (i = 0; gptr->gr_mem && gptr->gr_mem[i]; i++)
+ {
+ size_t member_len = strlen(gptr->gr_mem[i]) + 1;
+ if (copied_len + member_len < sizeof(pstring))
+ {
+
+ DEBUG(10,
+ ("validate_group: = gr_mem = %s\n",
+ gptr->gr_mem[i]));
+
+ safe_strcpy(member, gptr->gr_mem[i],
+ sizeof(pstring) - copied_len - 1);
+ copied_len += member_len;
+ member += copied_len;
+ }
+ else
+ {
+ *member = '\0';
+ }
+ }
+
+ endgrent();
+
+ member = member_list;
+ while (*member)
{
- 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, NULL, password, pwlen, NULL, 0, pwd, user_sess_key)) {
- fstrcpy(tm, pwd->pw_name);
- endpwent ();
- return tm;
- }
- }
- }
- endpwent ();
+ static fstring name;
+ fstrcpy(name, member);
+ if (user_ok(name, snum) &&
+ password_ok(name, NULL, password, pwlen,
+ NULL, 0, NULL, info3))
+ {
+ endgrent();
+ return (&name[0]);
+ }
+
+ DEBUG(10, ("validate_group = member = %s\n", member));
+
+ member += strlen(member) + 1;
}
-#endif /* GROUP_CHECK_PWENT */
- }
- }
#endif
- return(NULL);
+ return (NULL);
}
-
/****************************************************************************
check for authority to login to a service with a given username/password
****************************************************************************/
BOOL authorise_login(int snum, char *user, char *domain,
- char *password, int pwlen,
- BOOL *guest,BOOL *force,
- const vuser_key *key)
+ char *password, int pwlen,
+ BOOL *guest, BOOL *force, const vuser_key * key)
{
BOOL ok = False;
- DEBUG(0,("authorise_login: TODO. split function, it's 6 levels!\n"));
+ DEBUG(0, ("authorise_login: TODO. split function, it's 6 levels!\n"));
*guest = False;
#if DEBUG_PASSWORD
- DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
+ DEBUG(100,
+ ("checking authorisation on user=%s pass=%s\n", user,
+ password));
#endif
- /* there are several possibilities:
- 1) login as the given user with given password
- 2) login as a previously registered username with the given password
- 3) login as a session list username with the given password
- 4) login as a previously validated user/password pair
- 5) login as the "user =" user with given password
- 6) login as the "user =" user with no password (guest connection)
- 7) login as guest user with no password
+ /* there are several possibilities:
+ 1) login as the given user with given password
+ 2) login as a previously registered username with the given password
+ 3) login as a session list username with the given password
+ 4) login as a previously validated user/password pair
+ 5) login as the "user =" user with given password
+ 6) login as the "user =" user with no password (guest connection)
+ 7) login as guest user with no password
- if the service is guest_only then steps 1 to 5 are skipped
- */
+ if the service is guest_only then steps 1 to 5 are skipped
+ */
- if (GUEST_ONLY(snum)) *force = True;
+ if (GUEST_ONLY(snum))
+ *force = True;
if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
{
user_struct *vuser = get_valid_user_struct(key);
/* check the given username and password */
- if (!ok && (*user) && user_ok(user,snum))
+ if (!ok && (*user) && user_ok(user, snum))
{
- ok = password_ok(user,domain, password, pwlen, NULL, 0, NULL, &vuser->usr);
- if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
+ ok =
+ password_ok(user, domain, password, pwlen,
+ NULL, 0, NULL, &vuser->usr);
+ 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, domain, password, pwlen, NULL, 0, NULL, &vuser->usr))
+ {
+ if (user_ok(vuser->name, snum) &&
+ password_ok(vuser->name, domain, password, pwlen,
+ NULL, 0, NULL, &vuser->usr))
{
fstrcpy(user, vuser->name);
vuser->guest = False;
- DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
+ DEBUG(3,
+ ("ACCEPTED: given password with registered user %s\n",
+ user));
ok = True;
}
}
@@ -255,41 +302,44 @@ BOOL authorise_login(int snum, char *user, char *domain,
return False;
}
- for (auser=strtok(user_list,LIST_SEP);
- !ok && auser;
- auser = strtok(NULL,LIST_SEP))
+ for (auser = strtok(user_list, LIST_SEP);
+ !ok && auser; auser = strtok(NULL, LIST_SEP))
{
fstring user2;
- fstrcpy(user2,auser);
- if (!user_ok(user2,snum)) continue;
+ fstrcpy(user2, auser);
+ if (!user_ok(user2, snum))
+ continue;
- if (password_ok(user2, domain, password, pwlen, NULL, 0, NULL,
- &vuser->usr))
+ if (password_ok
+ (user2, domain, password, pwlen, NULL, 0,
+ NULL, &vuser->usr))
{
ok = True;
- fstrcpy(user,user2);
- DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
+ fstrcpy(user, user2);
+ DEBUG(3,
+ ("ACCEPTED: session list username and given password ok\n"));
}
}
free(user_list);
}
/* check for a previously validated username/password pair */
- if (!ok && (!lp_revalidate(snum) || lp_security() > SEC_SHARE) &&
- (vuser != 0) && !vuser->guest &&
- user_ok(vuser->name,snum))
+ if (!ok && (!lp_revalidate(snum) || lp_security() > SEC_SHARE)
+ && (vuser != 0) && !vuser->guest
+ && user_ok(vuser->name, snum))
{
- fstrcpy(user,vuser->name);
+ fstrcpy(user, vuser->name);
*guest = False;
- DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
+ DEBUG(3,
+ ("ACCEPTED: validated uid ok as non-guest\n"));
ok = True;
}
/* check for a rhosts entry */
- if (!ok && user_ok(user,snum) && check_hosts_equiv(user))
+ if (!ok && user_ok(user, snum) && check_hosts_equiv(user))
{
ok = True;
- DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
+ DEBUG(3, ("ACCEPTED: hosts equiv or rhosts entry\n"));
}
/* check the user= fields and the given password */
@@ -297,39 +347,46 @@ BOOL authorise_login(int snum, char *user, char *domain,
{
char *auser;
pstring user_list;
- StrnCpy(user_list,lp_username(snum),sizeof(pstring));
+ 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;
- auser = strtok(NULL,LIST_SEP))
+ for (auser = strtok(user_list, LIST_SEP);
+ auser && !ok; auser = strtok(NULL, LIST_SEP))
{
if (*auser == '@')
{
- auser = validate_group(auser+1,password,pwlen,snum, &vuser->usr);
+ auser =
+ validate_group(auser + 1,
+ password,
+ pwlen, snum,
+ &vuser->usr);
if (auser)
{
ok = True;
- fstrcpy(user,auser);
- DEBUG(3,("ACCEPTED: group username and given password ok\n"));
+ fstrcpy(user, auser);
+ DEBUG(3,
+ ("ACCEPTED: group username and given password ok\n"));
}
}
else
{
fstring user2;
- fstrcpy(user2,auser);
- if (user_ok(user2,snum) &&
- password_ok(user2,domain,password,pwlen,NULL, 0,
- NULL, &vuser->usr))
+ fstrcpy(user2, auser);
+ if (user_ok(user2, snum) &&
+ password_ok(user2, domain,
+ password, pwlen, NULL,
+ 0, NULL, &vuser->usr))
{
ok = True;
- fstrcpy(user,user2);
- DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
+ fstrcpy(user, user2);
+ DEBUG(3,
+ ("ACCEPTED: user list username and given password ok\n"));
}
}
}
- }
+ }
if (vuser != NULL)
{
@@ -337,137 +394,156 @@ BOOL authorise_login(int snum, char *user, char *domain,
}
vuid_free_user_struct(vuser);
- } /* not guest only */
+ } /* not guest only */
/* check for a normal guest connection */
if (!ok && GUEST_OK(snum))
{
fstring guestname;
- StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
- if (Get_Pwnam(guestname,True))
+ StrnCpy(guestname, lp_guestaccount(snum),
+ sizeof(guestname) - 1);
+ if (Get_Pwnam(guestname, True))
{
- fstrcpy(user,guestname);
+ fstrcpy(user, guestname);
ok = True;
- DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
+ DEBUG(3, ("ACCEPTED: guest account and guest ok\n"));
}
else
- DEBUG(0,("Invalid guest account %s??\n",guestname));
+ DEBUG(0, ("Invalid guest account %s??\n", guestname));
*guest = True;
*force = True;
}
- if (ok && !user_ok(user,snum))
+ if (ok && !user_ok(user, snum))
{
- DEBUG(0,("rejected invalid user %s\n",user));
+ DEBUG(0, ("rejected invalid user %s\n", user));
ok = False;
}
- return(ok);
+ return (ok);
}
-
-/****************************************************************************
-read the a hosts.equiv or .rhosts file and check if it
-allows this user from this machine
-****************************************************************************/
-static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
+BOOL check_user_equiv_line(char *buf, const char *user, const char *remote,
+ BOOL *plus_allowed, BOOL *ret)
{
- pstring buf;
- int plus_allowed = 1;
- char *file_host;
- char *file_user;
- FILE *fp = sys_fopen(equiv_file, "r");
- DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
- if (! fp) return False;
- while(fgets(buf, sizeof(buf), fp))
- {
- trim_string(buf," "," ");
-
- if (buf[0] != '#' && buf[0] != '\n')
- {
- BOOL is_group = False;
- int plus = 1;
- char *bp = buf;
- if (strcmp(buf, "NO_PLUS\n") == 0)
- {
- DEBUG(6, ("check_user_equiv NO_PLUS\n"));
- plus_allowed = 0;
- }
- else {
- if (buf[0] == '+')
+ BOOL is_group = False;
+ int plus = 1;
+ char *bp = buf;
+ char *file_host;
+ char *file_user;
+
+ if (strcmp(buf, "NO_PLUS\n") == 0)
{
- bp++;
- if (*bp == '\n' && plus_allowed)
- {
- /* a bare plus means everbody allowed */
- DEBUG(6, ("check_user_equiv everybody allowed\n"));
- fclose(fp);
- return True;
- }
+ DEBUG(6, ("check_user_equiv NO_PLUS\n"));
+ (*plus_allowed) = 0;
+ return False;
+ }
+
+ if (buf[0] == '+')
+ {
+ bp++;
+ if (*bp == '\n' && (*plus_allowed))
+ {
+ /* a bare plus means everbody allowed */
+ DEBUG(6, ("check_user_equiv everybody allowed\n"));
+ *ret = True;
+ return True;
+ }
}
else if (buf[0] == '-')
{
- bp++;
- plus = 0;
+ bp++;
+ plus = 0;
}
- if (*bp == '@')
+ if (*bp == '@')
{
- is_group = True;
- bp++;
+ is_group = True;
+ bp++;
}
+
file_host = strtok(bp, " \t\n");
file_user = strtok(NULL, " \t\n");
- DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)",
- file_user ? file_user : "(null)" ));
- if (file_host && *file_host)
- {
- BOOL host_ok = False;
+ DEBUG(7, ("check_user_equiv %s %s\n",
+ file_host ? file_host : "(null)",
+ file_user ? file_user : "(null)"));
+ if (file_host && *file_host)
+ {
+ BOOL host_ok = False;
#if defined(HAVE_NETGROUP) && defined(HAVE_YP_GET_DEFAULT_DOMAIN)
- if (is_group)
- {
- static char *mydomain = NULL;
- if (!mydomain)
- yp_get_default_domain(&mydomain);
- if (mydomain && innetgr(file_host,remote,user,mydomain))
- host_ok = True;
- }
+ if (is_group)
+ {
+ static char *mydomain = NULL;
+ if (!mydomain)
+ yp_get_default_domain(&mydomain);
+ if (mydomain && innetgr(file_host, remote, user,
+ mydomain)) host_ok = True;
+ }
#else
- if (is_group)
- {
- DEBUG(1,("Netgroups not configured\n"));
- continue;
- }
+ if (is_group)
+ {
+ DEBUG(1, ("Netgroups not configured\n"));
+ return False;
+ }
#endif
+ /* is it this host */
+ /* the fact that remote has come from a call of
+ * gethostbyaddr means that it may have the fully
+ * qualified domain name so we could look up the
+ * file version to get it into a canonical form,
+ * but I would rather just type it in full in the
+ * equiv file */
+ if (!host_ok && !is_group && strequal(remote, file_host))
+ {
+ host_ok = True;
+ }
+ if (!host_ok)
+ {
+ return False;
+ }
+ /* is it this user */
+ if (file_user == 0 || strequal(user, file_user))
+ {
+ DEBUG(5, ("check_user_equiv matched %s%s %s\n",
+ (plus ? "+" : "-"), file_host,
+ (file_user ? file_user : "")));
+ *ret = (plus ? True : False);
+ return True;
+ }
+ }
+
+ return False;
+}
+
+/****************************************************************************
+read the a hosts.equiv or .rhosts file and check if it
+allows this user from this machine
+****************************************************************************/
+static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
+{
+ pstring buf;
+ int plus_allowed = 1;
+ FILE *fp = sys_fopen(equiv_file, "r");
+ DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
+ if (!fp)
+ return False;
+ while (fgets(buf, sizeof(buf), fp))
+ {
+ trim_string(buf, " ", " ");
- /* is it this host */
- /* the fact that remote has come from a call of gethostbyaddr
- * means that it may have the fully qualified domain name
- * so we could look up the file version to get it into
- * a canonical form, but I would rather just type it
- * in full in the equiv file
- */
- if (!host_ok && !is_group && strequal(remote, file_host))
- host_ok = True;
-
- if (!host_ok)
- continue;
-
- /* is it this user */
- if (file_user == 0 || strequal(user, file_user))
- {
- fclose(fp);
- DEBUG(5, ("check_user_equiv matched %s%s %s\n",
- (plus ? "+" : "-"), file_host,
- (file_user ? file_user : "")));
- return (plus ? True : False);
- }
+ if (buf[0] != '#' && buf[0] != '\n')
+ {
+ BOOL ret;
+ if (check_user_equiv_line(buf, user, remote,
+ &plus_allowed, &ret))
+ {
+ fclose(fp);
+ return ret;
+ }
+ }
}
- }
- }
- }
- fclose(fp);
- return False;
+ fclose(fp);
+ return False;
}
@@ -476,32 +552,34 @@ check for a possible hosts equiv or rhosts entry for the user
****************************************************************************/
BOOL check_hosts_equiv(char *user)
{
- char *fname = NULL;
- pstring rhostsfile;
- const struct passwd *pass = Get_Pwnam(user,True);
-
- if (!pass)
- return False;
-
- fname = lp_hosts_equiv();
-
- /* note: don't allow hosts.equiv on root */
- if (fname && *fname && (pass->pw_uid != 0)) {
- if (check_user_equiv(user,client_connection_name(),fname))
- return(True);
- }
-
- if (lp_use_rhosts())
- {
- char *home = get_unixhome_dir(user);
- if (home) {
- slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
- if (check_user_equiv(user,client_connection_name(),rhostsfile))
- return(True);
- }
- }
-
- return False;
-}
+ char *fname = NULL;
+ pstring rhostsfile;
+ const struct passwd *pass = Get_Pwnam(user, True);
+
+ if (!pass)
+ return False;
+ fname = lp_hosts_equiv();
+ /* note: don't allow hosts.equiv on root */
+ if (fname && *fname && (pass->pw_uid != 0))
+ {
+ if (check_user_equiv(user, client_connection_name(), fname))
+ return (True);
+ }
+
+ if (lp_use_rhosts())
+ {
+ char *home = get_unixhome_dir(user);
+ if (home)
+ {
+ slprintf(rhostsfile, sizeof(rhostsfile) - 1,
+ "%s/.rhosts", home);
+ if (check_user_equiv
+ (user, client_connection_name(), rhostsfile))
+ return (True);
+ }
+ }
+
+ return False;
+}
diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c
index b4e3e3a0d17..71376b8a0a9 100644
--- a/source/smbd/pipes.c
+++ b/source/smbd/pipes.c
@@ -42,69 +42,71 @@ extern struct pipe_id_info pipe_names[];
This code is basically stolen from reply_open_and_X with some
wrinkles to handle pipes.
****************************************************************************/
-int reply_open_pipe_and_X(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
+int reply_open_pipe_and_X(connection_struct * conn,
+ char *inbuf, char *outbuf, int length, int bufsize)
{
pstring fname;
uint16 vuid = SVAL(inbuf, smb_uid);
pipes_struct *p;
- int smb_ofun = SVAL(inbuf,smb_vwv8);
- int size=0,fmode=0,mtime=0,rmode=0;
+ int smb_ofun = SVAL(inbuf, smb_vwv8);
+ int size = 0, fmode = 0, mtime = 0, rmode = 0;
int i;
vuser_key key;
/* XXXX we need to handle passed times, sattr and flags */
- pstrcpy(fname,smb_buf(inbuf));
+ pstrcpy(fname, smb_buf(inbuf));
/* If the name doesn't start \PIPE\ then this is directed */
/* at a mailslot or something we really, really don't understand, */
/* not just something we really don't understand. */
- if ( strncmp(fname,PIPE,PIPELEN) != 0 )
- return(ERROR(ERRSRV,ERRaccess));
+ if (strncmp(fname, PIPE, PIPELEN) != 0)
+ return (ERROR(ERRSRV, ERRaccess));
- DEBUG(4,("Opening pipe %s.\n", fname));
+ DEBUG(4, ("Opening pipe %s.\n", fname));
/* See if it is one we want to handle. */
- for( i = 0; pipe_names[i].client_pipe ; i++ )
- if( strequal(fname,pipe_names[i].client_pipe) )
+ for (i = 0; pipe_names[i].client_pipe; i++)
+ if (strequal(fname, pipe_names[i].client_pipe))
break;
if (pipe_names[i].client_pipe == NULL)
- return(ERROR(ERRSRV,ERRaccess));
+ return (ERROR(ERRSRV, ERRaccess));
/* Strip \PIPE\ off the name. */
- pstrcpy(fname,smb_buf(inbuf) + PIPELEN);
+ pstrcpy(fname, smb_buf(inbuf) + PIPELEN);
/* 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 */
+ DEBUG(3, ("Known pipe %s opening.\n", fname));
+ smb_ofun |= 0x10; /* Add Create it not exists flag */
key.pid = getpid();
key.vuid = vuid;
p = open_rpc_pipe_p(fname, &key, NULL);
- if (!p) return(ERROR(ERRSRV,ERRnofids));
+ if (!p)
+ return (ERROR(ERRSRV, ERRnofids));
/* Prepare the reply */
- set_message(outbuf,15,0,True);
+ set_message(outbuf, 15, 0, True);
/* Mark the opened file as an existing named pipe in message mode. */
- SSVAL(outbuf,smb_vwv9,2);
- SSVAL(outbuf,smb_vwv10,0xc700);
+ SSVAL(outbuf, smb_vwv9, 2);
+ SSVAL(outbuf, smb_vwv10, 0xc700);
- if (rmode == 2) {
- DEBUG(4,("Resetting open result to open from create.\n"));
+ if (rmode == 2)
+ {
+ DEBUG(4, ("Resetting open result to open from create.\n"));
rmode = 1;
}
- SSVAL(outbuf,smb_vwv2, p->pnum);
- SSVAL(outbuf,smb_vwv3,fmode);
- put_dos_date3(outbuf,smb_vwv4,mtime);
- SIVAL(outbuf,smb_vwv6,size);
- SSVAL(outbuf,smb_vwv8,rmode);
- SSVAL(outbuf,smb_vwv11,0x0001);
+ SSVAL(outbuf, smb_vwv2, p->pnum);
+ SSVAL(outbuf, smb_vwv3, fmode);
+ put_dos_date3(outbuf, smb_vwv4, mtime);
+ SIVAL(outbuf, smb_vwv6, size);
+ SSVAL(outbuf, smb_vwv8, rmode);
+ SSVAL(outbuf, smb_vwv11, 0x0001);
- return chain_reply(inbuf,outbuf,length,bufsize);
+ return chain_reply(inbuf, outbuf, length, bufsize);
}
/****************************************************************************
@@ -113,15 +115,16 @@ int reply_open_pipe_and_X(connection_struct *conn,
This code is basically stolen from reply_write with some
wrinkles to handle pipes.
****************************************************************************/
-int reply_pipe_write(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_pipe_write(char *inbuf, char *outbuf, int length, int bufsize)
{
- pipes_struct *p = get_rpc_pipe_p(inbuf,smb_vwv0);
- size_t numtowrite = SVAL(inbuf,smb_vwv1);
+ pipes_struct *p = get_rpc_pipe_p(inbuf, smb_vwv0);
+ size_t numtowrite = SVAL(inbuf, smb_vwv1);
int nwritten = -1;
char *data;
size_t outsize;
- if (!p) return(ERROR(ERRDOS,ERRbadfid));
+ if (!p)
+ return (ERROR(ERRDOS, ERRbadfid));
data = smb_buf(inbuf) + 3;
@@ -136,17 +139,16 @@ int reply_pipe_write(char *inbuf,char *outbuf,int length,int bufsize)
if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0))
{
- DEBUG(3,("reply_write_pipe: nwritten: %d numtowrite:%d\n",
- nwritten, numtowrite));
- return (UNIXERROR(ERRDOS,ERRnoaccess));
+ DEBUG(3, ("reply_write_pipe: nwritten: %d numtowrite:%d\n",
+ nwritten, numtowrite));
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
}
-
- outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,nwritten);
+ outsize = set_message(outbuf, 1, 0, True);
+
+ SSVAL(outbuf, smb_vwv0, nwritten);
- DEBUG(3,("write-IPC pnum=%04x nwritten=%d\n",
- p->pnum, nwritten));
+ DEBUG(3, ("write-IPC pnum=%04x nwritten=%d\n", p->pnum, nwritten));
return outsize;
}
@@ -157,16 +159,24 @@ int reply_pipe_write(char *inbuf,char *outbuf,int length,int bufsize)
This code is basically stolen from reply_write_and_X with some
wrinkles to handle pipes.
****************************************************************************/
-int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_pipe_write_and_X(char *inbuf, char *outbuf, int length, int bufsize)
{
- pipes_struct *p = get_rpc_pipe_p(inbuf,smb_vwv2);
- size_t numtowrite = SVAL(inbuf,smb_vwv10);
+ pipes_struct *p = get_rpc_pipe_p(inbuf, smb_vwv2);
+ size_t numtowrite = SVAL(inbuf, smb_vwv10);
int nwritten = -1;
int smb_doff = SVAL(inbuf, smb_vwv11);
int write_mode = SVAL(inbuf, smb_vwv7);
char *data;
- if (!p) return(ERROR(ERRDOS,ERRbadfid));
+ /*
+ * start of message mode pipe: indicates start of dce/rpc pdu.
+ */
+
+ BOOL msg;
+ msg = IS_BITS_SET_ALL(write_mode, PIPE_START_MESSAGE | PIPE_RAW_MODE);
+
+ if (!p)
+ return (ERROR(ERRDOS, ERRbadfid));
data = smb_base(inbuf) + smb_doff;
@@ -176,33 +186,37 @@ int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
}
else
{
- if (write_mode == 0x000c)
+ if (msg)
{
- nwritten = write_pipe(p, data+2, numtowrite-2);
- if (nwritten != 0)
- {
- nwritten += 2;
- }
+ /*
+ * skip the length-of-pdu, the client could be
+ * a nasty bitch and lie to us, e.g
+ * an nt-smb-writepipe-DoS attack.
+ */
+
+ data += 2;
+ numtowrite -= 2;
}
- else
+
+ nwritten = write_pipe(p, data, numtowrite);
+
+ if (msg && nwritten != 0)
{
- nwritten = write_pipe(p, data, numtowrite);
+ nwritten += 2;
}
}
if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0))
{
- return (UNIXERROR(ERRDOS,ERRnoaccess));
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
}
-
- set_message(outbuf,6,0,True);
- SSVAL(outbuf,smb_vwv2,nwritten);
-
- DEBUG(3,("writeX-IPC pnum=%04x nwritten=%d\n",
- p->pnum, nwritten));
+ set_message(outbuf, 6, 0, True);
+ SSVAL(outbuf, smb_vwv2, nwritten);
+
+ DEBUG(3, ("writeX-IPC pnum=%04x nwritten=%d\n", p->pnum, nwritten));
- return chain_reply(inbuf,outbuf,length,bufsize);
+ return chain_reply(inbuf, outbuf, length, bufsize);
}
/****************************************************************************
@@ -211,48 +225,50 @@ int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
This code is basically stolen from reply_read_and_X with some
wrinkles to handle pipes.
****************************************************************************/
-int reply_pipe_read_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);
- int smb_maxcnt = SVAL(inbuf,smb_vwv5);
- int smb_mincnt = SVAL(inbuf,smb_vwv6);
+ pipes_struct *p = get_rpc_pipe_p(inbuf, smb_vwv2);
+ int smb_maxcnt = SVAL(inbuf, smb_vwv5);
+ int smb_mincnt = SVAL(inbuf, smb_vwv6);
int nread = -1;
char *data;
- if (!p) return(ERROR(ERRDOS,ERRbadfid));
+ if (!p)
+ return (ERROR(ERRDOS, ERRbadfid));
- set_message(outbuf,12,0,True);
+ set_message(outbuf, 12, 0, True);
data = smb_buf(outbuf);
nread = read_pipe(p, data, 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-IPC pnum=%04x min=%d max=%d nread=%d\n",
- p->pnum, smb_mincnt, smb_maxcnt, nread));
-
- return chain_reply(inbuf,outbuf,length,bufsize);
+ 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-IPC pnum=%04x min=%d max=%d nread=%d\n",
+ p->pnum, smb_mincnt, smb_maxcnt, nread));
+
+ return chain_reply(inbuf, outbuf, length, bufsize);
}
/****************************************************************************
reply to a close
****************************************************************************/
-int reply_pipe_close(connection_struct *conn, char *inbuf,char *outbuf)
+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);
+ 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));
+ DEBUG(5, ("reply_pipe_close: pnum:%x\n", p->pnum));
- if (!close_rpc_pipe_hnd(p)) return(ERROR(ERRDOS,ERRbadfid));
+ if (!close_rpc_pipe_hnd(p))
+ return (ERROR(ERRDOS, ERRbadfid));
- return(outsize);
+ return (outsize);
}
-
diff --git a/source/smbd/predict.c b/source/smbd/predict.c
index f51e54a568c..34044b82f22 100644
--- a/source/smbd/predict.c
+++ b/source/smbd/predict.c
@@ -37,7 +37,7 @@ 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
@@ -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)
diff --git a/source/smbd/process.c b/source/smbd/process.c
index bba218a73e8..4a5f3eb03b8 100644
--- a/source/smbd/process.c
+++ b/source/smbd/process.c
@@ -23,9 +23,9 @@
extern int DEBUGLEVEL;
-time_t smb_last_time=(time_t)0;
+struct timeval smb_last_time;
-char *InBuffer = NULL;
+static char *InBuffer = NULL;
char *OutBuffer = NULL;
char *last_inbuf = 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 fstring global_myworkgroup;
extern pstring global_myname;
extern int max_send;
@@ -230,6 +230,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
@@ -282,8 +328,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},
@@ -318,9 +364,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 },
@@ -329,7 +375,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},
@@ -338,14 +384,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 | CAN_IPC },
{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},
@@ -367,14 +413,15 @@ 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;
+ extern int global_smbpid;
- if (pid == -1)
+ if (pid == (pid_t)-1)
pid = getpid();
errno = 0;
@@ -391,6 +438,10 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
if (smb_messages[match].code == type)
break;
+ /* yuck! this is an interim measure before we get rid of our
+ current inbuf/outbuf system */
+ global_smbpid = SVAL(inbuf,smb_pid);
+
if (match == num_smb_messages)
{
DEBUG(0,("Unknown message type %d!\n",type));
@@ -398,21 +449,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;
@@ -434,8 +489,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
* move it unless you know what you're doing... :-).
* JRA.
*/
- if (session_tag != last_session_tag)
- {
+ if (session_tag != last_session_tag) {
user_struct *vuser = NULL;
vuser_key key;
key.pid = pid;
@@ -460,7 +514,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
if (flags & AS_GUEST)
flags &= ~AS_USER;
else
- return(ERROR(ERRSRV,ERRinvnid));
+ return(ERROR(ERRSRV,ERRaccess));
}
/* this code is to work around a bug is MS client 3 without
introducing a security hole - it needs to be able to do
@@ -512,9 +566,8 @@ static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
int type = CVAL(inbuf,smb_com);
int outsize = 0;
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();
@@ -565,7 +618,7 @@ void process_smb(char *inbuf, char *outbuf)
name" */
static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
DEBUG( 1, ( "Connection denied from %s\n",
- client_connection_addr() ) );
+ client_addr(Client) ) );
send_smb(Client,(char *)buf);
exit_server("connection denied");
}
@@ -646,7 +699,7 @@ char *smb_fn_name(int type)
void construct_reply_common(char *inbuf,char *outbuf)
{
- memset(outbuf, 0, smb_size);
+ memset(outbuf,'\0',smb_size);
set_message(outbuf,0,0,True);
CVAL(outbuf,smb_com) = CVAL(inbuf,smb_com);
@@ -656,7 +709,9 @@ void construct_reply_common(char *inbuf,char *outbuf)
CVAL(outbuf,smb_reh) = 0;
SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); /* bit 7 set
means a reply */
- SSVAL(outbuf,smb_flg2,FLAGS2_LONG_PATH_COMPONENTS); /* say we support long filenames */
+ SSVAL(outbuf,smb_flg2,FLAGS2_LONG_PATH_COMPONENTS);
+ /* say we support long filenames */
+
SSVAL(outbuf,smb_err,SMB_SUCCESS);
SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
@@ -677,7 +732,6 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
int outsize2;
char inbuf_saved[smb_wct];
char outbuf_saved[smb_wct];
- extern int chain_size;
int wct = CVAL(outbuf,smb_wct);
int outsize = smb_size + 2*wct + SVAL(outbuf,smb_vwv0+2*wct);
@@ -693,6 +747,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;
@@ -747,71 +809,164 @@ 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 caller 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_connection_name()));
- 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;
+
+ if (keepalive && (t - last_keepalive_sent_time)>keepalive)
+ {
+ if (!send_keepalive(Client)) {
+ DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
+ return False;
+ }
+ DEBUG(0,("TODO: send keepalive to all smbd client-side SMB connections\n"));
+ last_keepalive_sent_time = t;
+ }
+
+ /* check for connection timeouts */
+ allidle = conn_idle_all(t, deadtime);
+
+ if (allidle && conn_num_open()>0) {
+ DEBUG(2,("Closing idle connection 2.\n"));
+ return False;
+ }
+
+ /*
+ * Check to see if we have any blocking locks
+ * outstanding on the queue.
+ */
+ process_blocking_lock_queue(t);
+
+ /*
+ * Check to see if we have any change notifies
+ * outstanding on the queue.
+ */
+ process_pending_change_notify_queue(t);
+
+ /*
+ * Modify the select timeout depending upon
+ * what we have remaining in our queues.
+ */
+
+ *select_timeout = setup_select_timeout();
+
+ return True;
+}
+
+/****************************************************************************
+ process commands from the client
+****************************************************************************/
+
+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;
+
+ InBuffer += SMB_ALIGNMENT;
+ OutBuffer += SMB_ALIGNMENT;
+
+ max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
+
+ /* re-initialise the timezone */
+ TimeInit();
while (True)
{
int deadtime = lp_deadtime()*60;
- int counter;
- int last_keepalive=0;
- int service_load_counter = 0;
BOOL got_smb = False;
+ int select_timeout = setup_select_timeout();
if (deadtime <= 0)
deadtime = DEFAULT_SMBD_TIMEOUT;
@@ -823,106 +978,55 @@ void smbd_process(void)
errno = 0;
- 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 (counter > 365 * 3600) /* big number of seconds. */
- {
- counter = 0;
- service_load_counter = 0;
- }
-
- if (smb_read_error == READ_EOF)
- {
- DEBUG(3,("end of file from client\n"));
- return;
- }
+ /* free up temporary memory */
+ lp_talloc_free();
- if (smb_read_error == READ_ERROR)
- {
- DEBUG(3,("receive_smb error (%s) exiting\n",
- strerror(errno)));
+ while(!receive_message_or_smb(InBuffer,BUFFER_SIZE,select_timeout,&got_smb))
+ {
+ if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
return;
- }
-
- t = time(NULL);
-
- /* become root again if waiting */
- unbecome_user();
-
- /* check for smb.conf reload */
- if (counter >= service_load_counter + SMBD_RELOAD_CHECK)
- {
- service_load_counter = counter;
-
- /* reload services, if files have changed. */
- reload_services(True);
- }
+ num_smbs = 0; /* Reset smb counter. */
+ }
+ if(got_smb) {
/*
- * If reload_after_sighup == True then we got a SIGHUP
- * and are being asked to reload. Fix from <branko.cibej@hermes.si>
- */
+ * 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;
- 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();
- }
-
- /* automatic timeout if all connections are closed */
- if (conn_num_open()==0 && counter >= IDLE_CLOSED_TIMEOUT)
- {
- DEBUG( 2, ( "Closing idle connection\n" ) );
- return;
- }
+ process_smb(InBuffer, OutBuffer);
- if (keepalive && (counter-last_keepalive)>keepalive)
- {
- if (!send_keepalive(Client)) {
- DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
- return;
- }
- last_keepalive = counter;
+ if(smb_echo_count != num_echos) {
+ if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
+ return;
+ num_smbs = 0; /* Reset smb counter. */
}
- /* close down all idle client-side MSRPC connections */
- free_connections();
-
- /* check for connection timeouts */
- allidle = conn_idle_all(t, deadtime);
-
- if (allidle && conn_num_open()>0) {
- DEBUG(2,("Closing idle connection 2.\n"));
- return;
- }
+ num_smbs++;
/*
- * Check to see if we have any blocking locks
- * 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_blocking_lock_queue(t);
- /*
- * Check to see if we have any change notifies
- * outstanding on the queue.
- */
- process_pending_change_notify_queue(t);
+ 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. */
+ }
+ }
}
-
- if(got_smb)
- process_smb(InBuffer, OutBuffer);
else
process_local_message(InBuffer, BUFFER_SIZE);
}
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index 508f76a2a65..f0bffec69a3 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -38,12 +38,12 @@ 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
@@ -78,7 +78,7 @@ int reply_special(char *inbuf, char *outbuf)
*name1 = *name2 = 0;
- memset(outbuf, 0, smb_size);
+ memset(outbuf, '\0', smb_size);
smb_setlen(outbuf, 0);
@@ -132,8 +132,7 @@ int reply_special(char *inbuf, char *outbuf)
if (lp_status(-1))
{
- claim_connection(NULL, "STATUS.", MAXSTATUS,
- True);
+ claim_connection(NULL, "", MAXSTATUS, True);
}
break;
@@ -168,9 +167,7 @@ work out what error to give to a failed connection
static int connection_error(char *inbuf, char *outbuf, int ecode)
{
if (ecode == ERRnoipc)
- {
return (ERROR(ERRDOS, ERRnoipc));
- }
return (ERROR(ERRSRV, ecode));
}
@@ -215,11 +212,12 @@ 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;
@@ -234,10 +232,19 @@ int reply_tcon(connection_struct * conn,
parse_connect(smb_buf(inbuf) + 1, service, user, password, &pwlen,
dev);
+ /*
+ * map from DOS codepage format to Unix
+ */
+
+ dos_to_unix(user, True);
+ if (!doencrypt)
+ {
+ dos_to_unix(password, True);
+ }
+
map_nt_and_unix_username(global_myworkgroup, user, user, NULL);
- conn =
- make_connection(service, user, global_myworkgroup, password,
+ conn = make_connection(service, user, global_myworkgroup, password,
pwlen, dev, vuid, &ecode);
if (!conn)
@@ -318,10 +325,19 @@ int reply_tcon_and_X(connection_struct * conn, char *inbuf, char *outbuf,
StrnCpy(devicename, path + strlen(path) + 1, 6);
DEBUG(4, ("Got device type %s\n", devicename));
+ /*
+ * map from DOS codepage format to Unix
+ */
+
+ dos_to_unix(user, True);
+ if (!doencrypt)
+ {
+ dos_to_unix(password, True);
+ }
+
map_nt_and_unix_username(global_myworkgroup, user, user, NULL);
- conn =
- make_connection(service, user, global_myworkgroup, password,
+ conn = make_connection(service, user, global_myworkgroup, password,
passlen, devicename, vuid, &ecode);
if (!conn)
@@ -349,6 +365,8 @@ int reply_tcon_and_X(connection_struct * conn, char *inbuf, char *outbuf,
/* what does setting this bit do? It is set by NT4 and
may affect the ability to autorun mounted cdroms */
SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS);
+
+ init_dfsroot(conn, inbuf, outbuf);
}
DEBUG(3, ("tconX service=%s user=%s\n", service, user));
@@ -382,14 +400,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;
}
/****************************************************************************
@@ -501,22 +544,23 @@ user %s attempted down-level SMB connection\n",
enum remote_arch_types ra_type = get_remote_arch();
char *p = smb_buf(inbuf);
- DEBUG(10,
- ("passlen1: %d passlen2: %d\n", passlen1, passlen2));
-
- 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_WIN2K
+ || ra_type == RA_WIN95)
{
- if (global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))
- set_remote_arch(RA_WINNT);
- else
+ if (!
+ (global_client_caps &
+ (CAP_NT_SMBS | CAP_STATUS32)))
+ {
set_remote_arch(RA_WIN95);
+ }
}
if (passlen1 != 24 && passlen2 <= 24)
@@ -564,12 +608,26 @@ user %s attempted down-level SMB connection\n",
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);
@@ -595,6 +653,11 @@ user %s attempted down-level SMB connection\n",
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,
@@ -627,6 +690,13 @@ user %s attempted down-level SMB connection\n",
}
strlower(user);
+
+ /*
+ * map from DOS codepage format to Unix
+ */
+
+ dos_to_unix(user, True);
+
/*
* In share level security, only overwrite sesssetup_use if
* it's a non null-session share. Helps keep %U and %G
@@ -796,11 +866,10 @@ int reply_chkpth(connection_struct * conn, char *inbuf, char *outbuf,
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));
- }
+
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+
+ unix_convert(name, conn, 0, &bad_path, &st);
mode = SVAL(inbuf, smb_vwv0);
@@ -809,7 +878,7 @@ int reply_chkpth(connection_struct * conn, char *inbuf, char *outbuf,
if (VALID_STAT(st))
ok = S_ISDIR(st.st_mode);
else
- ok = dos_directory_exist(name, NULL);
+ ok = vfs_directory_exist(conn, name, NULL);
}
if (!ok)
@@ -863,6 +932,10 @@ int reply_getatr(connection_struct * conn, char *inbuf, char *outbuf,
pstrcpy(fname, smb_buf(inbuf) + 1);
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ /* if((SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) && dfs_redirect(fname,conn)) return(dfs_path_error(inbuf,outbuf));
+ */
/* dos smetimes asks for a stat of "" - it returns a "hidden directory"
under WfWg - weird! */
if (!(*fname))
@@ -876,17 +949,10 @@ int reply_getatr(connection_struct * conn, char *inbuf, char *outbuf,
}
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;
@@ -920,7 +986,7 @@ int reply_getatr(connection_struct * conn, char *inbuf, char *outbuf,
put_dos_date3(outbuf, smb_vwv1, mtime & ~1);
else
put_dos_date3(outbuf, smb_vwv1, mtime);
- SIVAL(outbuf, smb_vwv3, (uint32) size);
+ SIVAL(outbuf, smb_vwv3, (uint32)size);
if (Protocol >= PROTOCOL_NT1)
{
@@ -934,7 +1000,7 @@ int reply_getatr(connection_struct * conn, char *inbuf, char *outbuf,
DEBUG(3,
("getatr name=%s mode=%d size=%d\n", fname, mode,
- (uint32) size));
+ (uint32)size));
return (outsize);
}
@@ -955,16 +1021,12 @@ int reply_setatr(connection_struct * conn, char *inbuf, char *outbuf,
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);
- if (VALID_STAT_OF_DIR(st) || dos_directory_exist(fname, NULL))
+ if (VALID_STAT_OF_DIR(st) || vfs_directory_exist(conn, fname, NULL))
mode |= aDIR;
if (check_name(fname, conn))
ok = (file_chmod(conn, fname, mode, NULL) == 0);
@@ -999,7 +1061,7 @@ int reply_dskattr(connection_struct * conn, char *inbuf, char *outbuf,
int outsize = 0;
SMB_BIG_UINT dfree, dsize, bsize;
- conn->vfs_ops.disk_free(".", &bsize, &dfree, &dsize);
+ conn->vfs_ops.disk_free(".", True, &bsize, &dfree, &dsize);
outsize = set_message(outbuf, 5, 0, True);
@@ -1059,7 +1121,7 @@ int reply_search(connection_struct * conn, char *inbuf, char *outbuf,
/* 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)
@@ -1068,12 +1130,7 @@ int reply_search(connection_struct * conn, char *inbuf, char *outbuf,
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_convert(directory, conn, 0, &bad_path, NULL);
unix_format(dir2);
if (!check_name(directory, conn))
@@ -1099,7 +1156,7 @@ int reply_search(connection_struct * conn, char *inbuf, char *outbuf,
if (strlen(directory) == 0)
pstrcpy(directory, "./");
- memset(status, 0, 21);
+ memset((char *)status, '\0', 21);
CVAL(status, 0) = dirtype;
}
else
@@ -1138,7 +1195,7 @@ int reply_search(connection_struct * conn, char *inbuf, char *outbuf,
p = mask;
while (*p)
{
- if ((skip = skip_multibyte_char(*p)) != 0)
+ if ((skip = get_character_len(*p)) != 0)
{
p += skip;
}
@@ -1176,8 +1233,9 @@ int reply_search(connection_struct * conn, char *inbuf, char *outbuf,
if (status_len == 0)
{
dptr_num =
- dptr_create(conn, directory, expect_close,
- SVAL(inbuf, smb_pid));
+ dptr_create(conn, directory, True,
+ expect_close, SVAL(inbuf,
+ smb_pid));
if (dptr_num < 0)
{
if (dptr_num == -2)
@@ -1241,7 +1299,7 @@ int reply_search(connection_struct * conn, char *inbuf, char *outbuf,
p += DIR_STRUCT_SIZE;
}
}
- }
+ } /* if (ok ) */
}
@@ -1251,6 +1309,7 @@ int reply_search(connection_struct * conn, char *inbuf, char *outbuf,
{
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
@@ -1262,12 +1321,12 @@ int reply_search(connection_struct * conn, char *inbuf, char *outbuf,
CVAL(outbuf, smb_rcls) = ERRDOS;
SSVAL(outbuf, smb_err, ERRnofiles);
/* Also close the dptr - we know it's gone */
- dptr_close(dptr_num);
+ 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);
@@ -1305,7 +1364,7 @@ int reply_fclose(connection_struct * conn, char *inbuf, char *outbuf,
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;
@@ -1320,7 +1379,7 @@ int reply_fclose(connection_struct * conn, char *inbuf, char *outbuf,
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);
@@ -1354,11 +1413,10 @@ int reply_open(connection_struct * conn, char *inbuf, char *outbuf,
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));
- }
+
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ unix_convert(fname, conn, 0, &bad_path, NULL);
fsp = file_new();
if (!fsp)
@@ -1375,7 +1433,7 @@ int reply_open(connection_struct * conn, char *inbuf, char *outbuf,
return (UNIXERROR(ERRDOS, ERRnoaccess));
}
- unixmode = unix_mode(conn, aARCH);
+ unixmode = unix_mode(conn, aARCH, fname);
open_file_shared(fsp, conn, fname, share_mode,
(FILE_FAIL_IF_NOT_EXIST | FILE_EXISTS_OPEN),
@@ -1416,7 +1474,7 @@ int reply_open(connection_struct * conn, char *inbuf, char *outbuf,
put_dos_date3(outbuf, smb_vwv2, mtime & ~1);
else
put_dos_date3(outbuf, smb_vwv2, mtime);
- SIVAL(outbuf, smb_vwv4, (uint32) size);
+ SIVAL(outbuf, smb_vwv4, (uint32)size);
SSVAL(outbuf, smb_vwv6, rmode);
if (oplock_request && lp_fake_oplocks(SNUM(conn)))
@@ -1424,7 +1482,7 @@ int reply_open(connection_struct * conn, char *inbuf, char *outbuf,
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,21 +1517,17 @@ int reply_open_and_X(connection_struct * conn, char *inbuf, char *outbuf,
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));
- }
+
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ unix_convert(fname, conn, 0, &bad_path, NULL);
fsp = file_new();
if (!fsp)
@@ -1490,7 +1544,7 @@ int reply_open_and_X(connection_struct * conn, char *inbuf, char *outbuf,
return (UNIXERROR(ERRDOS, ERRnoaccess));
}
- unixmode = unix_mode(conn, smb_attr | aARCH);
+ unixmode = unix_mode(conn, smb_attr | aARCH, fname);
open_file_shared(fsp, conn, fname, smb_mode, smb_ofun, unixmode,
oplock_request, &rmode, &smb_action);
@@ -1531,7 +1585,7 @@ int reply_open_and_X(connection_struct * conn, char *inbuf, char *outbuf,
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;
}
@@ -1546,7 +1600,7 @@ int reply_open_and_X(connection_struct * conn, char *inbuf, char *outbuf,
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;
}
@@ -1558,7 +1612,7 @@ int reply_open_and_X(connection_struct * conn, char *inbuf, char *outbuf,
put_dos_date3(outbuf, smb_vwv4, mtime & ~1);
else
put_dos_date3(outbuf, smb_vwv4, mtime);
- SIVAL(outbuf, smb_vwv6, (uint32) size);
+ SIVAL(outbuf, smb_vwv6, (uint32)size);
SSVAL(outbuf, smb_vwv8, rmode);
SSVAL(outbuf, smb_vwv11, smb_action);
@@ -1622,11 +1676,10 @@ int reply_mknew(connection_struct * conn, char *inbuf, char *outbuf,
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));
- }
+
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ unix_convert(fname, conn, 0, &bad_path, NULL);
if (createmode & aVOLID)
{
@@ -1635,7 +1688,7 @@ int reply_mknew(connection_struct * conn, char *inbuf, char *outbuf,
fname));
}
- unixmode = unix_mode(conn, createmode);
+ unixmode = unix_mode(conn, createmode, fname);
fsp = file_new();
if (!fsp)
@@ -1655,12 +1708,12 @@ int reply_mknew(connection_struct * conn, char *inbuf, char *outbuf,
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. */
@@ -1688,7 +1741,7 @@ int reply_mknew(connection_struct * conn, char *inbuf, char *outbuf,
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));
@@ -1717,13 +1770,12 @@ int reply_ctemp(connection_struct * conn, char *inbuf, char *outbuf,
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));
- }
- unixmode = unix_mode(conn, createmode);
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ unix_convert(fname, conn, 0, &bad_path, NULL);
+
+ unixmode = unix_mode(conn, createmode, fname);
fsp = file_new();
if (fsp)
@@ -1740,7 +1792,7 @@ int reply_ctemp(connection_struct * conn, char *inbuf, char *outbuf,
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. */
@@ -1771,7 +1823,7 @@ int reply_ctemp(connection_struct * conn, char *inbuf, char *outbuf,
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));
@@ -1811,7 +1863,7 @@ 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)
@@ -1827,6 +1879,7 @@ int reply_unlink(connection_struct * conn, char *inbuf, char *outbuf,
BOOL has_wild;
BOOL exists = False;
BOOL bad_path = False;
+ BOOL rc = True;
*directory = *mask = 0;
@@ -1834,13 +1887,11 @@ int reply_unlink(connection_struct * conn, char *inbuf, char *outbuf,
pstrcpy(name, smb_buf(inbuf) + 1);
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+
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)
@@ -1855,7 +1906,16 @@ int reply_unlink(connection_struct * conn, char *inbuf, char *outbuf,
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, '?');
@@ -1864,14 +1924,11 @@ int reply_unlink(connection_struct * conn, char *inbuf, char *outbuf,
{
pstrcat(directory, "/");
pstrcat(directory, mask);
- if (can_delete(directory, conn, dirtype) &&
- !conn->vfs_ops.unlink(dos_to_unix(directory, False)))
+ if (can_delete(directory, conn, dirtype)
+ && !dos_unlink(directory))
count++;
if (!count)
- exists =
- vfs_file_exist(conn,
- dos_to_unix(directory, False),
- NULL);
+ exists = vfs_file_exist(conn, directory, NULL);
}
else
{
@@ -1907,9 +1964,9 @@ int reply_unlink(connection_struct * conn, char *inbuf, char *outbuf,
directory, dname);
if (!can_delete(fname, conn, dirtype))
continue;
- if (!conn->vfs_ops.
- unlink(dos_to_unix(fname, False)))
- count++;
+ if (!conn->
+ vfs_ops.unlink(dos_to_unix(fname, False)))
+ count++;
DEBUG(3,
("reply_unlink : doing unlink on %s\n",
fname));
@@ -1968,14 +2025,52 @@ int reply_readbraw(connection_struct * conn, char *inbuf, char *outbuf,
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,
@@ -1986,7 +2081,6 @@ int reply_readbraw(connection_struct * conn, char *inbuf, char *outbuf,
return (-1);
}
}
-#endif /* LARGE_SMB_OFF_T */
maxcount = (SVAL(inbuf, smb_vwv3) & 0xFFFF);
mincount = (SVAL(inbuf, smb_vwv4) & 0xFFFF);
@@ -1994,17 +2088,7 @@ int reply_readbraw(connection_struct * conn, char *inbuf, char *outbuf,
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))
+ if (!is_locked(fsp, conn, maxcount, startpos, READ_LOCK))
{
SMB_OFF_T size = fsp->size;
SMB_OFF_T sizeneeded = startpos + maxcount;
@@ -2026,7 +2110,8 @@ int reply_readbraw(connection_struct * conn, char *inbuf, char *outbuf,
nread = 0;
DEBUG(3, ("readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n",
- fsp->fnum, (double)startpos, maxcount, mincount, nread));
+ fsp->fnum, (double)startpos,
+ (int)maxcount, (int)mincount, (int)nread));
#if UNSAFE_READRAW
{
@@ -2111,8 +2196,15 @@ int reply_lockread(connection_struct * conn, char *inbuf, char *outbuf,
numtoread = MIN(BUFFER_SIZE - outsize, numtoread);
data = smb_buf(outbuf) + 3;
+ /*
+ * 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_RDLCK, &eclass, &ecode))
+ (fsp, conn, numtoread, startpos, WRITE_LOCK, &eclass, &ecode))
{
if ((ecode == ERRlock) && lp_blocking_locks(SNUM(conn)))
{
@@ -2138,7 +2230,7 @@ int reply_lockread(connection_struct * conn, char *inbuf, char *outbuf,
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);
}
@@ -2147,8 +2239,9 @@ int reply_lockread(connection_struct * conn, char *inbuf, char *outbuf,
/****************************************************************************
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;
@@ -2168,13 +2261,11 @@ int reply_read(connection_struct * conn, char *inbuf, char *outbuf,
numtoread = MIN(BUFFER_SIZE - outsize, numtoread);
data = smb_buf(outbuf) + 3;
- if (is_locked(fsp, conn, numtoread, startpos, F_RDLCK))
+ if (is_locked(fsp, conn, numtoread, startpos, READ_LOCK))
return (ERROR(ERRDOS, ERRlock));
if (numtoread > 0)
- {
nread = read_file(fsp, data, startpos, numtoread);
- }
if (nread < 0)
return (UNIXERROR(ERRDOS, ERRnoaccess));
@@ -2186,7 +2277,7 @@ int reply_read(connection_struct * conn, char *inbuf, char *outbuf,
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);
}
@@ -2216,17 +2307,33 @@ int reply_read_and_X(connection_struct * conn, char *inbuf, char *outbuf,
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))
+ }
+
+ if (is_locked(fsp, conn, smb_maxcnt, startpos, READ_LOCK))
return (ERROR(ERRDOS, ERRlock));
nread = read_file(fsp, data, startpos, smb_maxcnt);
@@ -2238,7 +2345,7 @@ int reply_read_and_X(connection_struct * conn, char *inbuf, char *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);
}
@@ -2247,7 +2354,7 @@ int reply_read_and_X(connection_struct * conn, char *inbuf, char *outbuf,
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 size, int dum_buffsize)
{
ssize_t nwritten = 0;
ssize_t total_written = 0;
@@ -2284,23 +2391,15 @@ int reply_writebraw(connection_struct * conn, char *inbuf, char *outbuf,
CVAL(inbuf, smb_com) = SMBwritec;
CVAL(outbuf, smb_com) = SMBwritec;
- if (is_locked(fsp, conn, tcount, startpos, F_WRLCK))
+ if (is_locked(fsp, conn, tcount, startpos, WRITE_LOCK))
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));
@@ -2329,7 +2428,7 @@ int reply_writebraw(connection_struct * conn, char *inbuf, char *outbuf,
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,
@@ -2350,10 +2449,11 @@ int reply_writebraw(connection_struct * conn, char *inbuf, char *outbuf,
if ((lp_syncalways(SNUM(conn)) || write_through) &&
lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
+ conn->vfs_ops.fsync(fsp->fd_ptr->fd);
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 */
@@ -2367,7 +2467,7 @@ int reply_writebraw(connection_struct * conn, char *inbuf, char *outbuf,
reply to a writeunlock (core+)
****************************************************************************/
int reply_writeunlock(connection_struct * conn, char *inbuf, char *outbuf,
- int dum_size, int dum_buffsize)
+ int size, int dum_buffsize)
{
ssize_t nwritten = -1;
size_t numtowrite;
@@ -2386,22 +2486,19 @@ int reply_writeunlock(connection_struct * conn, char *inbuf, char *outbuf,
startpos = IVAL(inbuf, smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (is_locked(fsp, conn, numtowrite, startpos, F_WRLCK))
+ if (is_locked(fsp, conn, numtowrite, startpos, WRITE_LOCK))
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)))
+ conn->vfs_ops.fsync(fsp->fd_ptr->fd);
if (((nwritten == 0) && (numtowrite != 0)) || (nwritten < 0))
return (UNIXERROR(ERRDOS, ERRnoaccess));
@@ -2414,7 +2511,7 @@ int reply_writeunlock(connection_struct * conn, char *inbuf, char *outbuf,
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);
}
@@ -2422,8 +2519,8 @@ int reply_writeunlock(connection_struct * conn, char *inbuf, char *outbuf,
/****************************************************************************
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;
@@ -2434,8 +2531,7 @@ int reply_write(connection_struct * conn, char *inbuf, char *outbuf,
/* If it's an IPC, pass off the pipe handler. */
if (IS_IPC(conn))
- return reply_pipe_write(inbuf, outbuf, dum_size,
- dum_buffsize);
+ return reply_pipe_write(inbuf, outbuf, size, dum_buffsize);
CHECK_FSP(fsp, conn);
CHECK_WRITE(fsp);
@@ -2445,22 +2541,24 @@ int reply_write(connection_struct * conn, char *inbuf, char *outbuf,
startpos = IVAL(inbuf, smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (is_locked(fsp, conn, numtowrite, startpos, F_WRLCK))
+ if (is_locked(fsp, conn, numtowrite, startpos, WRITE_LOCK))
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);
+ {
+ if (
+ (nwritten =
+ set_filelen(fsp->fd_ptr->fd, (SMB_OFF_T) startpos)) >= 0) /* tpot vfs */
+ set_filelen_write_cache(fsp, startpos);
+ }
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)))
+ conn->vfs_ops.fsync(fsp->fd_ptr->fd);
if (((nwritten == 0) && (numtowrite != 0)) || (nwritten < 0))
return (UNIXERROR(ERRDOS, ERRnoaccess));
@@ -2476,7 +2574,7 @@ int reply_write(connection_struct * conn, char *inbuf, char *outbuf,
}
DEBUG(3, ("write fnum=%d num=%d wrote=%d\n",
- fsp->fnum, numtowrite, nwritten));
+ fsp->fnum, (int)numtowrite, (int)nwritten));
return (outsize);
}
@@ -2506,22 +2604,34 @@ int reply_write_and_X(connection_struct * conn, char *inbuf, char *outbuf,
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))
+ if (is_locked(fsp, conn, numtowrite, startpos, WRITE_LOCK))
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,
@@ -2529,7 +2639,7 @@ int reply_write_and_X(connection_struct * conn, char *inbuf, char *outbuf,
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));
@@ -2545,11 +2655,10 @@ int reply_write_and_X(connection_struct * conn, char *inbuf, char *outbuf,
}
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)
+ conn->vfs_ops.fsync(fsp->fd_ptr->fd);
return chain_reply(inbuf, outbuf, length, bufsize);
}
@@ -2558,8 +2667,9 @@ int reply_write_and_X(connection_struct * conn, char *inbuf, char *outbuf,
/****************************************************************************
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;
@@ -2570,10 +2680,12 @@ int reply_lseek(connection_struct * conn, char *inbuf, char *outbuf,
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;
@@ -2591,15 +2703,61 @@ int reply_lseek(connection_struct * conn, char *inbuf, char *outbuf,
if ((res = conn->vfs_ops.lseek(fsp->fd_ptr->fd, startpos, umode)) ==
-1)
- return (UNIXERROR(ERRDOS, ERRnoaccess));
+ {
+ /*
+ * 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 =
+ conn->vfs_ops.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 (conn->
+ vfs_ops.fstat(fsp->fd_ptr->fd,
+ &sbuf) == -1)
+ return (UNIXERROR
+ (ERRDOS, ERRnoaccess));
+
+ current_pos += sbuf.st_size;
+ }
+
+ if (current_pos < 0)
+ res =
+ conn->vfs_ops.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);
}
@@ -2607,8 +2765,9 @@ int reply_lseek(connection_struct * conn, char *inbuf, char *outbuf,
/****************************************************************************
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);
@@ -2625,7 +2784,7 @@ int reply_flush(connection_struct * conn, char *inbuf, char *outbuf,
}
else
{
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
+ conn->vfs_ops.fsync(fsp->fd_ptr->fd);
}
DEBUG(3, ("flush\n"));
@@ -2649,8 +2808,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;
@@ -2661,9 +2820,7 @@ int reply_close(connection_struct * conn,
/* If it's an IPC, pass off to the pipe handler. */
if (IS_IPC(conn))
- {
return reply_pipe_close(conn, inbuf, outbuf);
- }
fsp = file_fsp(inbuf, smb_vwv0);
@@ -2680,20 +2837,24 @@ int reply_close(connection_struct * conn,
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,
@@ -2712,9 +2873,20 @@ 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, conn->num_files_open));
+ 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 */
@@ -2729,12 +2901,12 @@ 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;
@@ -2749,24 +2921,28 @@ int reply_writeclose(connection_struct * conn,
mtime = make_unix_date3(inbuf + smb_vwv4);
data = smb_buf(inbuf) + 1;
- if (is_locked(fsp, conn, numtowrite, startpos, F_WRLCK))
+ if (is_locked(fsp, conn, numtowrite, startpos, WRITE_LOCK))
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, conn->num_files_open));
+ 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);
@@ -2795,7 +2971,7 @@ int reply_lock(connection_struct * conn,
DEBUG(3, ("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
fsp->fd_ptr->fd, fsp->fnum, (double)offset, (double)count));
- if (!do_lock(fsp, conn, count, offset, F_WRLCK, &eclass, &ecode))
+ if (!do_lock(fsp, conn, count, offset, WRITE_LOCK, &eclass, &ecode))
{
if ((ecode == ERRlock) && lp_blocking_locks(SNUM(conn)))
{
@@ -2818,7 +2994,7 @@ 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 size, int dum_buffsize)
{
int outsize = set_message(outbuf, 0, 0, True);
SMB_OFF_T count, offset;
@@ -2901,6 +3077,8 @@ int reply_echo(connection_struct * conn,
DEBUG(3, ("echo %d times\n", smb_reverb));
+ smb_echo_count++;
+
return -1;
}
@@ -2943,7 +3121,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))
{
@@ -2956,7 +3134,7 @@ int reply_printopen(connection_struct * conn,
SET_DENY_MODE(DENY_ALL) |
SET_OPEN_MODE(DOS_OPEN_WRONLY),
(FILE_CREATE_IF_NOT_EXIST | FILE_EXISTS_FAIL),
- unix_mode(conn, 0), 0, NULL, NULL);
+ unix_mode(conn, 0, fname2), 0, NULL, NULL);
if (!fsp->open)
{
@@ -2986,6 +3164,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);
@@ -2995,7 +3174,13 @@ 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);
}
@@ -3012,7 +3197,9 @@ int reply_printqueue(connection_struct * conn,
int max_count = SVAL(inbuf, smb_vwv0);
int start_index = SVAL(inbuf, smb_vwv1);
uint16 vuid = SVAL(inbuf, smb_uid);
- VUSER_KEY;
+ vuser_key key;
+ key.pid = conn != NULL ? conn->smbd_pid : getpid();
+ key.vuid = vuid;
/* we used to allow the client to get the cnum wrong, but that
is really quite gross and only worked when there was only
@@ -3101,7 +3288,7 @@ int reply_printwrite(connection_struct * conn, char *inbuf, char *outbuf,
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));
@@ -3121,15 +3308,11 @@ int reply_mkdir(connection_struct * conn, char *inbuf, char *outbuf,
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));
+ unix_mode(conn, aDIR, directory));
if (ret < 0)
{
@@ -3156,7 +3339,7 @@ static BOOL recursive_rmdir(connection_struct * conn, 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;
@@ -3194,8 +3377,8 @@ static BOOL recursive_rmdir(connection_struct * conn, char *directory)
ret = True;
break;
}
- if (conn->vfs_ops.
- rmdir(dos_to_unix(fullname, False)) != 0)
+ if (conn->
+ vfs_ops.rmdir(dos_to_unix(fullname, False)) != 0)
{
ret = True;
break;
@@ -3213,129 +3396,136 @@ static BOOL recursive_rmdir(connection_struct * conn, char *directory)
}
/****************************************************************************
- reply to a rmdir
+ The internals of the rmdir code - called elsewhere.
****************************************************************************/
-int reply_rmdir(connection_struct * conn, char *inbuf, char *outbuf,
- int dum_size, int dum_buffsize)
-{
- pstring directory;
- int outsize = 0;
- BOOL ok = False;
- 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));
- }
+BOOL rmdir_internals(connection_struct * conn, char *directory)
+{
+ BOOL ok;
- if (check_name(directory, conn))
+ ok = (conn->vfs_ops.rmdir(dos_to_unix(directory, False)) == 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);
- 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)))
+ if (dirptr != NULL)
{
- /* 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)))
{
- int dirpos = TellDir(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;
- if (!IS_VETO_PATH(conn, dname))
+
+ /* Construct the full name. */
+ if (strlen(directory) +
+ strlen(dname) + 1 >=
+ sizeof(fullname))
{
- all_veto_files = False;
+ errno = ENOMEM;
break;
}
- }
- if (all_veto_files)
- {
- SeekDir(dirptr, dirpos);
- while ((dname = ReadDirName(dirptr)))
+ pstrcpy(fullname, directory);
+ pstrcat(fullname, "/");
+ pstrcat(fullname, dname);
+
+ if (conn->vfs_ops.lstat(dos_to_unix
+ (fullname,
+ False),
+ &st) != 0)
+ break;
+ if (st.st_mode & S_IFDIR)
{
- 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))
+ if (lp_recursive_veto_delete
+ (SNUM(conn)))
{
- errno = ENOMEM;
- break;
+ if (recursive_rmdir
+ (conn,
+ fullname) != 0)
+ break;
}
- pstrcpy(fullname, directory);
- pstrcat(fullname, "/");
- pstrcat(fullname, dname);
-
- if (conn->vfs_ops.
- lstat(dos_to_unix
- (fullname, False),
- &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
+ if (conn->
+ vfs_ops.rmdir(dos_to_unix
(fullname,
False)) !=
- 0)
- break;
- }
- else if (conn->vfs_ops.
- unlink(dos_to_unix
- (fullname,
- False)) != 0)
+ 0)
break;
}
- CloseDir(dirptr);
- /* Retry the rmdir */
- ok =
- (conn->vfs_ops.
- rmdir(dos_to_unix
- (directory, False)) == 0);
+ else if (conn->
+ vfs_ops.unlink(dos_to_unix
+ (fullname,
+ False)) != 0)
+ break;
}
- else
- CloseDir(dirptr);
+ CloseDir(dirptr);
+ /* Retry the rmdir */
+ ok =
+ (conn->
+ vfs_ops.rmdir(dos_to_unix
+ (directory, False)) == 0);
}
else
- errno = ENOTEMPTY;
+ CloseDir(dirptr);
}
+ else
+ errno = ENOTEMPTY;
+ }
- if (!ok)
- DEBUG(3, ("couldn't remove directory %s : %s\n",
- directory, strerror(errno)));
+ 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;
+ int outsize = 0;
+ BOOL ok = False;
+ BOOL bad_path = False;
+
+ pstrcpy(directory, smb_buf(inbuf) + 1);
+
+ RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
+ unix_convert(directory, conn, NULL, &bad_path, NULL);
+
+ if (check_name(directory, conn))
+ {
+ dptr_closepath(directory, SVAL(inbuf, smb_pid));
+ ok = rmdir_internals(conn, directory);
}
if (!ok)
@@ -3474,24 +3664,17 @@ int rename_internals(connection_struct * conn,
int count = 0;
int error = ERRnoaccess;
BOOL exists = False;
+ BOOL rc = True;
+ pstring zdirectory;
*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
@@ -3512,7 +3695,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, '?');
@@ -3580,27 +3772,29 @@ int rename_internals(connection_struct * conn,
}
}
+ pstrcpy(zdirectory, dos_to_unix(directory, False));
if (replace_if_exists)
{
/*
* NT SMB specific flag - rename can overwrite
* file with the same name so don't check for
- * dos_file_exist().
+ * vfs_file_exist().
*/
if (resolve_wildcards(directory, newname) &&
can_rename(directory, conn) &&
- !conn->vfs_ops.
- rename(dos_to_unix(directory, False), newname))
+ !conn->vfs_ops.rename(zdirectory,
+ dos_to_unix(newname,
+ False)))
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))
+ !vfs_file_exist(conn, newname, NULL) &&
+ !conn->vfs_ops.rename(zdirectory,
+ dos_to_unix(newname,
+ False)))
count++;
}
@@ -3610,13 +3804,8 @@ int rename_internals(connection_struct * conn,
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))
+ exists = vfs_file_exist(conn, directory, NULL);
+ if (!count && exists && vfs_file_exist(conn, newname, NULL))
{
exists = True;
error = ERRrename;
@@ -3669,11 +3858,8 @@ int rename_internals(connection_struct * conn,
continue;
}
- if (!replace_if_exists
- && vfs_file_exist(conn,
- dos_to_unix(destname,
- False),
- NULL))
+ if (!replace_if_exists &&
+ vfs_file_exist(conn, destname, NULL))
{
DEBUG(6,
("file_exist %s\n", destname));
@@ -3681,9 +3867,10 @@ int rename_internals(connection_struct * conn,
continue;
}
- if (!conn->vfs_ops.
- rename(dos_to_unix(fname, False),
- destname))
+ if (!conn->
+ vfs_ops.rename(dos_to_unix(fname, False),
+ dos_to_unix(destname,
+ False)))
count++;
DEBUG(3,
("rename_internals: doing rename on %s -> %s\n",
@@ -3725,6 +3912,9 @@ int reply_mv(connection_struct * conn, char *inbuf, char *outbuf,
pstrcpy(name, smb_buf(inbuf) + 1);
pstrcpy(newname, smb_buf(inbuf) + 3 + strlen(name));
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+ RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+
DEBUG(3, ("reply_mv : %s -> %s\n", name, newname));
outsize = rename_internals(conn, inbuf, outbuf, name, newname, False);
@@ -3739,14 +3929,17 @@ int reply_mv(connection_struct * conn, char *inbuf, char *outbuf,
******************************************************************/
static BOOL copy_file(char *src, char *dest1, connection_struct * conn,
- int ofun, int count, BOOL target_is_directory)
+ int ofun, 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)
{
@@ -3759,7 +3952,7 @@ static BOOL copy_file(char *src, char *dest1, connection_struct * conn,
pstrcat(dest, p);
}
- if (!vfs_file_exist(conn, dos_to_unix(src, False), &st))
+ if (!vfs_file_exist(conn, src, &st))
return (False);
fsp1 = file_new();
@@ -3820,9 +4013,15 @@ static BOOL copy_file(char *src, char *dest1, connection_struct * conn,
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);
}
@@ -3840,6 +4039,7 @@ int reply_copy(connection_struct * conn, char *inbuf, char *outbuf,
char *p;
int count = 0;
int error = ERRnoaccess;
+ int err = 0;
BOOL has_wild;
BOOL exists = False;
int tid2 = SVAL(inbuf, smb_vwv0);
@@ -3848,6 +4048,7 @@ int reply_copy(connection_struct * conn, char *inbuf, char *outbuf,
BOOL target_is_directory = False;
BOOL bad_path1 = False;
BOOL bad_path2 = False;
+ BOOL rc = True;
*directory = *mask = 0;
@@ -3863,18 +4064,13 @@ int reply_copy(connection_struct * conn, char *inbuf, char *outbuf,
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));
- }
+ RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+ RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
- target_is_directory = dos_directory_exist(newname, NULL);
+ rc = unix_convert(name, conn, 0, &bad_path1, NULL);
+ unix_convert(newname, conn, 0, &bad_path2, NULL);
+
+ target_is_directory = vfs_directory_exist(conn, False, NULL);
if ((flags & 1) && target_is_directory)
{
@@ -3886,7 +4082,7 @@ int reply_copy(connection_struct * conn, char *inbuf, char *outbuf,
return (ERROR(ERRDOS, ERRbadpath));
}
- if ((flags & (1 << 5)) && dos_directory_exist(name, NULL))
+ if ((flags & (1 << 5)) && vfs_directory_exist(conn, name, NULL))
{
/* wants a tree copy! XXXX */
DEBUG(3, ("Rejecting tree copy\n"));
@@ -3906,7 +4102,16 @@ int reply_copy(connection_struct * conn, char *inbuf, char *outbuf,
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, '?');
@@ -3917,12 +4122,15 @@ int reply_copy(connection_struct * conn, char *inbuf, char *outbuf,
pstrcat(directory, mask);
if (resolve_wildcards(directory, newname) &&
copy_file(directory, newname, conn, ofun,
- count, target_is_directory)) count++;
+ count, target_is_directory, &err))
+ count++;
+ if (!count && err)
+ {
+ errno = err;
+ return (UNIXERROR(ERRHRD, ERRgeneral));
+ }
if (!count)
- exists =
- vfs_file_exist(conn,
- dos_to_unix(directory, False),
- NULL);
+ exists = vfs_file_exist(conn, directory, NULL);
}
else
{
@@ -3946,17 +4154,17 @@ int reply_copy(connection_struct * conn, char *inbuf, char *outbuf,
pstrcpy(fname, dname);
if (!mask_match
- (fname, mask, case_sensitive,
- False)) continue;
+ (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));
@@ -3967,6 +4175,13 @@ int reply_copy(connection_struct * conn, char *inbuf, char *outbuf,
if (count == 0)
{
+ if (err)
+ {
+ /* Error on close... */
+ errno = err;
+ return (UNIXERROR(ERRHRD, ERRgeneral));
+ }
+
if (exists)
return (ERROR(ERRDOS, error));
else
@@ -4010,7 +4225,7 @@ int reply_setdir(connection_struct * conn, char *inbuf, char *outbuf,
}
else
{
- ok = dos_directory_exist(newdir, NULL);
+ ok = vfs_directory_exist(conn, newdir, NULL);
if (ok)
{
string_set(&conn->connectpath, newdir);
@@ -4029,15 +4244,269 @@ int reply_setdir(connection_struct * conn, char *inbuf, char *outbuf,
}
/****************************************************************************
+ 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;
+}
+
+/****************************************************************************
+ Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
+****************************************************************************/
+static uint32 map_lock_offset(uint32 high, uint32 low)
+{
+ unsigned int i;
+ uint32 mask = 0;
+ uint32 highcopy = high;
+
+ /*
+ * Try and find out how many significant bits there are in high.
+ */
+
+ for (i = 0; highcopy; i++)
+ highcopy >>= 1;
+
+ /*
+ * We use 31 bits not 32 here as POSIX
+ * lock offsets may not be negative.
+ */
+
+ mask = (~0) << (31 - i);
+
+ if (low & mask)
+ return 0; /* Fail. */
+
+ high <<= (31 - i);
+
+ return (high | low);
+}
+
+/****************************************************************************
+ 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);
- uchar locktype = CVAL(inbuf, smb_vwv3);
+ unsigned char locktype = CVAL(inbuf, smb_vwv3);
#if 0
- uchar oplocklevel = CVAL(inbuf, smb_vwv3 + 1);
+ unsigned char oplocklevel = CVAL(inbuf, smb_vwv3 + 1);
#endif
uint16 num_ulocks = SVAL(inbuf, smb_vwv6);
uint16 num_locks = SVAL(inbuf, smb_vwv7);
@@ -4048,6 +4517,8 @@ int reply_lockingX(connection_struct * conn, char *inbuf, char *outbuf,
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);
@@ -4058,42 +4529,33 @@ int reply_lockingX(connection_struct * conn, char *inbuf, char *outbuf,
*/
if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
{
- 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);
+no oplock granted on this file (%s).\n",
+ fsp->fnum, fsp->fsp_name));
+
+ /* 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);
}
- /* Remove the oplock flag from the sharemode. */
- lock_share_entry(fsp->conn, dev, inode);
- if (remove_share_oplock(fsp) == False)
+ if (remove_oplock(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));
-
- unlock_share_entry(fsp->conn, dev, inode);
- }
- else
- {
- unlock_share_entry(fsp->conn, dev, inode);
-
- /* Clear the granted flag and return. */
- fsp->granted_oplock = False;
+ ("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 */
@@ -4113,28 +4575,14 @@ dev = %x, inode = %.0f\n",
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",
@@ -4155,28 +4603,14 @@ dev = %x, inode = %.0f\n",
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",
@@ -4184,7 +4618,8 @@ dev = %x, inode = %.0f\n",
if (!do_lock
(fsp, conn, count, offset,
- ((locktype & 1) ? F_RDLCK : F_WRLCK), &eclass, &ecode))
+ ((locktype & 1) ? READ_LOCK : WRITE_LOCK), &eclass,
+ &ecode))
{
if ((ecode == ERRlock) && (lock_timeout != 0)
&& lp_blocking_locks(SNUM(conn)))
@@ -4206,34 +4641,25 @@ dev = %x, inode = %.0f\n",
all of the previous locks (X/Open spec). */
if (i != num_locks && num_locks != 0)
{
- for (; i >= 0; i--)
+ /*
+ * Ensure we don't do a remove on the lock that just failed,
+ * as under POSIX rules, if we have a lock already there, we
+ * will delete it (and we shouldn't) .....
+ */
+ for (i--; 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);
}
@@ -4289,7 +4715,7 @@ int reply_readbmpx(connection_struct * conn, char *inbuf, char *outbuf,
tcount = maxcount;
total_read = 0;
- if (is_locked(fsp, conn, maxcount, startpos, F_RDLCK))
+ if (is_locked(fsp, conn, maxcount, startpos, READ_LOCK))
return (ERROR(ERRDOS, ERRlock));
do
@@ -4324,7 +4750,7 @@ int reply_readbmpx(connection_struct * conn, char *inbuf, char *outbuf,
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 size, int dum_buffsize)
{
size_t numtowrite;
ssize_t nwritten = -1;
@@ -4352,17 +4778,13 @@ int reply_writebmpx(connection_struct * conn, char *inbuf, char *outbuf,
not an SMBwritebmpx - set this up now so we don't forget */
CVAL(outbuf, smb_com) = SMBwritec;
- if (is_locked(fsp, conn, tcount, startpos, F_WRLCK))
+ if (is_locked(fsp, conn, tcount, startpos, WRITE_LOCK))
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);
- 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)
+ conn->vfs_ops.fsync(fsp->fd_ptr->fd);
if (nwritten < (ssize_t) numtowrite)
return (UNIXERROR(ERRHRD, ERRdiskfull));
@@ -4402,7 +4824,7 @@ int reply_writebmpx(connection_struct * conn, char *inbuf, char *outbuf,
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)
{
@@ -4465,24 +4887,10 @@ int reply_writebs(connection_struct * conn, char *inbuf, char *outbuf,
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)
+ conn->vfs_ops.fsync(fsp->fd_ptr->fd);
if (nwritten < (ssize_t) numtowrite)
{
@@ -4524,7 +4932,7 @@ int reply_writebs(connection_struct * conn, char *inbuf, char *outbuf,
reply to a SMBsetattrE
****************************************************************************/
int reply_setattrE(connection_struct * conn, char *inbuf, char *outbuf,
- int dum_size, int dum_buffsize)
+ int size, int dum_buffsize)
{
struct utimbuf unix_times;
int outsize = 0;
@@ -4579,7 +4987,7 @@ int reply_setattrE(connection_struct * conn, char *inbuf, char *outbuf,
reply to a SMBgetattrE
****************************************************************************/
int reply_getattrE(connection_struct * conn, char *inbuf, char *outbuf,
- int dum_size, int dum_buffsize)
+ int size, int dum_buffsize)
{
SMB_STRUCT_STAT sbuf;
int outsize = 0;
@@ -4612,7 +5020,7 @@ int reply_getattrE(connection_struct * conn, char *inbuf, char *outbuf,
}
else
{
- SIVAL(outbuf, smb_vwv6, (uint32) sbuf.st_size);
+ SIVAL(outbuf, smb_vwv6, (uint32)sbuf.st_size);
SIVAL(outbuf, smb_vwv8, SMB_ROUNDUP(sbuf.st_size, 1024));
}
SSVAL(outbuf, smb_vwv10, mode);
diff --git a/source/smbd/server.c b/source/smbd/server.c
index 8d27541e336..f36df3d020c 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -27,7 +27,6 @@ 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;
@@ -37,7 +36,6 @@ int last_message = -1;
/* a useful macro to debug the last message processed */
#define LAST_MESSAGE() smb_fn_name(last_message)
-extern pstring scope;
extern int DEBUGLEVEL;
extern pstring user_socket_options;
@@ -114,7 +112,7 @@ static int open_server_socket(int port, uint32 ipaddr)
/****************************************************************************
open the socket communication
****************************************************************************/
-static BOOL open_sockets(BOOL is_daemon,int port,int port445)
+static BOOL open_sockets(BOOL is_daemon,int port, int port445)
{
extern int Client;
extern int ClientPort;
@@ -183,7 +181,8 @@ max can be %d\n",
num_interfaces = 1;
/* open an incoming socket */
- s = open_server_socket(port, interpret_addr(lp_socket_address()));
+ s = open_server_socket(port,
+ interpret_addr(lp_socket_address()));
if (s == -1)
return(False);
fd_listenset[0] = s;
@@ -207,11 +206,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,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--) {
@@ -332,6 +334,14 @@ BOOL reload_services(BOOL test)
ret = lp_load(servicesf,False,False,True);
+#ifdef MS_DFS
+ /* load the dfs maps of all the services having
+ a dfs_map parameter
+ we don't want to do this in lp_load because we want just the smbd
+ server to load up the dfs maps into msdfs.tdb. not nmbd, swat etc*/
+ load_dfsmaps();
+#endif
+
load_printers();
/* perhaps the config filename is now set */
@@ -351,6 +361,7 @@ BOOL reload_services(BOOL test)
}
reset_mangled_cache();
+ reset_stat_cache();
/* this forces service parameters to be flushed */
become_service(NULL,True);
@@ -361,9 +372,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)
{
@@ -438,6 +450,8 @@ void exit_server(char *reason)
conn_close_all();
+ respond_to_all_remaining_local_messages();
+
#ifdef WITH_DFS
if (dcelogin_atmost_once) {
dfs_unlogin();
@@ -458,15 +472,11 @@ void exit_server(char *reason)
}
locking_end();
+#ifdef MS_DFS
+ msdfs_end();
+#endif
DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
-#ifdef MEM_MAN
- {
- extern FILE *dbf;
- smb_mem_write_verbose(dbf);
- dbgflush();
- }
-#endif
exit(0);
}
@@ -477,11 +487,25 @@ void exit_server(char *reason)
****************************************************************************/
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 */
init_dptrs();
- init_dfs_table();
}
/****************************************************************************
@@ -489,20 +513,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]\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");
}
@@ -515,6 +540,7 @@ static void usage(char *pname)
extern BOOL append_log;
/* shall I run as a daemon */
BOOL is_daemon = False;
+ BOOL specified_logfile = False;
int port = SMB_PORT;
int port445 = SMB_PORT2;
int opt;
@@ -524,58 +550,18 @@ 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 */
- 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);
-
- /* 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:l:s:d:Dp:h?VPaof:")) )
switch (opt) {
case 'O':
pstrcpy(user_socket_options,optarg);
break;
- case 'i':
- pstrcpy(scope,optarg);
- break;
-
case 'P':
{
extern BOOL passive;
@@ -588,6 +574,7 @@ static void usage(char *pname)
break;
case 'l':
+ specified_logfile = True;
pstrcpy(debugf,optarg);
break;
@@ -620,11 +607,73 @@ 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();
+
+ if(!specified_logfile)
+ 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));
@@ -638,6 +687,10 @@ static void usage(char *pname)
exit(1);
}
+ /*
+ * Do this before reload_services.
+ */
+
if (!reload_services(False))
return(-1);
@@ -650,16 +703,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;
@@ -671,10 +714,7 @@ static void usage(char *pname)
codepage_initialise(lp_client_code_page());
- if (!pwdb_initialise(True))
- {
- exit(1);
- }
+ fstrcpy(global_myworkgroup, lp_workgroup());
CatchSignal(SIGHUP,SIGNAL_CAST sig_hup);
@@ -684,7 +724,6 @@ static void usage(char *pname)
/* If we are using the malloc debug code we can't use
SIGUSR1 and SIGUSR2 to do debug level changes. */
-#ifndef MEM_MAN
#if defined(SIGUSR1)
CatchSignal( SIGUSR1, SIGNAL_CAST sig_usr1 );
#endif /* SIGUSR1 */
@@ -692,7 +731,6 @@ static void usage(char *pname)
#if defined(SIGUSR2)
CatchSignal( SIGUSR2, SIGNAL_CAST sig_usr2 );
#endif /* SIGUSR2 */
-#endif /* MEM_MAN */
DEBUG(3,( "loaded services\n"));
@@ -719,9 +757,18 @@ static void usage(char *pname)
if (!open_sockets(is_daemon,port,port445))
exit(1);
+ /*
+ * Note that this call should be done after the fork() call
+ * in open_sockets(), as some versions of the locking shared
+ * memory code register openers in a flat file.
+ */
+
if (!locking_init(0))
exit(1);
+ if(!pwdb_initialise(True))
+ exit(1);
+
/* possibly reload the services file. */
reload_services(True);
diff --git a/source/smbd/service.c b/source/smbd/service.c
index 58543ff3274..3cb36e05941 100644
--- a/source/smbd/service.c
+++ b/source/smbd/service.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
service (connection) opening and closing
- Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Andrew Tridgell 1992-2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -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;
@@ -54,7 +54,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);
@@ -89,7 +89,7 @@ int find_service(char *service)
{
int iService;
- string_sub(service,"\\","/");
+ all_string_sub(service,"\\","/",0);
iService = lp_servicenumber(service);
@@ -99,7 +99,7 @@ int find_service(char *service)
char *phome_dir = get_unixhome_dir(service);
pstring home_dir;
- if(phome_dir == NULL)
+ if(!phome_dir)
{
/*
* Try mapping the servicename, it may
@@ -173,7 +173,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);
}
}
@@ -315,13 +315,13 @@ connection_struct *make_connection(char *service,char *user,
{
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;
@@ -362,6 +362,36 @@ connection_struct *make_connection(char *service,char *user,
string_set(&conn->dirpath,"");
string_set(&conn->user,user);
+ conn->vfs_conn = (struct vfs_connection_struct *)
+ malloc(sizeof(struct vfs_connection_struct));
+
+ if (conn->vfs_conn == NULL) {
+ DEBUG(0, ("No memory to create vfs_connection_struct"));
+ return NULL;
+ }
+
+ ZERO_STRUCTP(conn->vfs_conn);
+
+ /* Copy across relevant data from connection struct */
+
+ conn->vfs_conn->printer = conn->printer;
+ conn->vfs_conn->ipc = conn->ipc;
+ conn->vfs_conn->read_only = conn->read_only;
+ conn->vfs_conn->admin_user = conn->admin_user;
+
+ pstrcpy(conn->vfs_conn->dirpath, conn->dirpath);
+ pstrcpy(conn->vfs_conn->connectpath, conn->connectpath);
+ pstrcpy(conn->vfs_conn->origpath, conn->origpath);
+
+ pstrcpy(conn->vfs_conn->service, service);
+ pstrcpy(conn->vfs_conn->user, conn->user);
+
+ conn->vfs_conn->uid = conn->uid;
+ conn->vfs_conn->gid = conn->gid;
+ conn->vfs_conn->ngroups = conn->ngroups;
+ conn->vfs_conn->groups = (gid_t *)memdup(conn->groups,
+ conn->ngroups * sizeof(gid_t));
+
/* Initialise VFS function pointers */
if (*lp_vfsobj(SNUM(conn))) {
@@ -386,40 +416,83 @@ connection_struct *make_connection(char *service,char *user,
vfs_init_default(conn);
}
+ /*
+ * 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))
+ {
+ const struct passwd *pass2;
+ pstring fuser;
+ pstrcpy(fuser,lp_force_user(snum));
+
+ /* Allow %S to be used by force user. */
+ pstring_sub(fuser,"%S",service);
+
+ pass2 = 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) {
+ /*
+ * 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\n",gname));
- } else {
- DEBUG(1,("Couldn't find group %s\n",gname));
+ DEBUG(3,("Forced group %s for member %s\n",gname,user));
+ break;
}
}
-#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));
+ conn->gid = gptr->gr_gid;
+ DEBUG(3,("Forced group %s\n",gname));
+ }
+ } else {
+ DEBUG(1,("Couldn't find group %s\n",gname));
}
}
+#endif /* HAVE_GETGRNAM */
{
pstring s;
@@ -453,20 +526,27 @@ connection_struct *make_connection(char *service,char *user,
}
if (lp_status(SNUM(conn)))
- claim_connection(conn,"STATUS.",
+ claim_connection(conn,"",
MAXSTATUS,False);
} /* IS_IPC */
/* execute any "root preexec = " line */
if (*lp_rootpreexec(SNUM(conn)))
{
+ BOOL ret;
pstring cmd;
user_struct *vuser = get_valid_user_struct(&key);
pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
standard_sub(conn,vuser, cmd);
vuid_free_user_struct(vuser);
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)) {
@@ -476,7 +556,7 @@ connection_struct *make_connection(char *service,char *user,
lp_servicename(SNUM(conn)),
lp_max_connections(SNUM(conn)));
if (lp_status(SNUM(conn))) {
- yield_connection(conn,"STATUS.",MAXSTATUS);
+ yield_connection(conn,"",MAXSTATUS);
}
}
conn_free(conn);
@@ -493,7 +573,7 @@ connection_struct *make_connection(char *service,char *user,
lp_servicename(SNUM(conn)),
lp_max_connections(SNUM(conn)));
if (lp_status(SNUM(conn)))
- yield_connection(conn,"STATUS.",MAXSTATUS);
+ yield_connection(conn,"",MAXSTATUS);
}
conn_free(conn);
*ecode = ERRinvnetname;
@@ -536,12 +616,32 @@ connection_struct *make_connection(char *service,char *user,
/* execute any "preexec = " line */
if (*lp_preexec(SNUM(conn)))
{
+ BOOL ret;
pstring cmd;
user_struct *vuser = get_valid_user_struct(&key);
pstrcpy(cmd,lp_preexec(SNUM(conn)));
standard_sub(conn,vuser, cmd);
vuid_free_user_struct(vuser);
- 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 */
@@ -554,53 +654,10 @@ connection_struct *make_connection(char *service,char *user,
set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
}
- if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
-
- dbgtext( "%s (%s) ", remote_machine, client_connection_addr() );
- 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)key.pid );
- }
-
- /* Invoke make connection hook */
+ /* Invoke VFS 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 *)memdup(conn->groups,
- conn->ngroups * sizeof(gid_t));
-
- /* Call connect hook */
-
- if (conn->vfs_ops.connect(vconn, service, user) < 0) {
+ if (conn->vfs_ops.connect(conn->vfs_conn, service, user) < 0) {
return NULL;
}
}
@@ -626,10 +683,18 @@ void close_cnum(connection_struct *conn, uint16 vuid)
if (conn->vfs_ops.disconnect != NULL) {
- /* Call disconnect hook */
+ /* Call VFS disconnect hook */
conn->vfs_ops.disconnect();
+ }
+
+ /* Close dlopen() handle */
+
+ if (conn->vfs_conn->dl_handle != NULL) {
+ dlclose(conn->vfs_conn->dl_handle); /* should we check return val? */
+ }
+
/* Free vfs_connection_struct */
if (conn->vfs_conn != NULL) {
@@ -638,14 +703,13 @@ void close_cnum(connection_struct *conn, uint16 vuid)
}
free(conn->vfs_conn);
}
- }
yield_connection(conn,
lp_servicename(SNUM(conn)),
lp_max_connections(SNUM(conn)));
if (lp_status(SNUM(conn)))
- yield_connection(conn,"STATUS.",MAXSTATUS);
+ yield_connection(conn,"",MAXSTATUS);
file_close_conn(conn);
dptr_closecnum(conn);
diff --git a/source/smbd/ssl.c b/source/smbd/ssl.c
index 1f098b2533d..be9aae7c5c3 100644
--- a/source/smbd/ssl.c
+++ b/source/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/source/smbd/trans2.c b/source/smbd/trans2.c
index 21ec4c25178..e6ee65d101d 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -22,7 +22,6 @@
*/
#include "includes.h"
-#include "nterr.h"
#include "trans2.h"
extern int DEBUGLEVEL;
@@ -32,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.
@@ -96,7 +95,14 @@ static int send_trans2_replies(char *outbuf, int bufsize, char *params,
total_sent_thistime = params_to_send + data_to_send +
alignment_offset + data_alignment_offset;
/* We can never send more than useable_space */
- total_sent_thistime = MIN(total_sent_thistime, useable_space);
+ /*
+ * Note that 'useable_space' does not include the alignment offsets,
+ * but we must include the alignment offsets in the calculation of
+ * the length of the data we send over the wire, as the alignment offsets
+ * are sent here. Fix from Marc_Jacobsen@hp.com.
+ */
+ total_sent_thistime = MIN(total_sent_thistime, useable_space+
+ alignment_offset + data_alignment_offset);
set_message(outbuf, 10, total_sent_thistime, True);
@@ -112,22 +118,19 @@ static int send_trans2_replies(char *outbuf, int bufsize, char *params,
data_sent_thistime = MIN(data_sent_thistime,data_to_send);
SSVAL(outbuf,smb_prcnt, params_sent_thistime);
+
+ /* smb_proff is the offset from the start of the SMB header to the
+ parameter bytes, however the first 4 bytes of outbuf are
+ the Netbios over TCP header. Thus use smb_base() to subtract
+ them from the calculation */
+
+ SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
+
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_prdisp,0);
- }
else
- {
- /* smb_proff is the offset from the start of the SMB header to the
- parameter bytes, however the first 4 bytes of outbuf are
- the Netbios over TCP header. Thus use smb_base() to subtract
- them from the calculation */
- SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
/* Absolute displacement of param bytes sent in this packet */
SSVAL(outbuf,smb_prdisp,pp - params);
- }
SSVAL(outbuf,smb_drcnt, data_sent_thistime);
if(data_sent_thistime == 0)
@@ -217,11 +220,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)
@@ -238,7 +237,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf,
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
- unixmode = unix_mode(conn,open_attr | aARCH);
+ unixmode = unix_mode(conn,open_attr | aARCH, fname);
open_file_shared(fsp,conn,fname,open_mode,open_ofun,unixmode,
oplock_request, &rmode,&smb_action);
@@ -273,7 +272,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf,
if(params == NULL)
return(ERROR(ERRDOS,ERRnomem));
- memset(params, 0, 28);
+ memset((char *)params,'\0',28);
SSVAL(params,0,fsp->fnum);
SSVAL(params,2,fmode);
put_dos_date2(params,4, mtime);
@@ -299,12 +298,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;
@@ -330,6 +329,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);
@@ -347,6 +347,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);
@@ -368,7 +370,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)
@@ -407,7 +428,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;
@@ -503,7 +524,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;
@@ -580,6 +601,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);
}
@@ -611,8 +633,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)
@@ -668,13 +691,11 @@ static int call_trans2findfirst(connection_struct *conn,
pstrcpy(directory, params + 12); /* Complete directory path with
wildcard mask appended */
+ RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf);
+
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)
{
@@ -709,40 +730,25 @@ static int call_trans2findfirst(connection_struct *conn,
pdata = *ppdata = Realloc(*ppdata, max_data_bytes + 1024);
if(!*ppdata)
return(ERROR(ERRDOS,ERRnomem));
- memset(pdata, 0, 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));
}
@@ -764,39 +770,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 -
@@ -804,7 +820,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. */
@@ -824,6 +843,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);
}
@@ -844,7 +874,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);
@@ -892,7 +922,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));
- memset(pdata, 0, max_data_bytes);
+ memset((char *)pdata,'\0',max_data_bytes + 1024);
/* Realloc the params space */
params = *pparams = Realloc(*pparams, 6*SIZEOFWORD);
@@ -969,7 +999,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))
{
@@ -997,7 +1027,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))
{
@@ -1010,38 +1040,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 */
@@ -1071,6 +1112,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);
@@ -1079,7 +1121,6 @@ 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));
@@ -1088,7 +1129,8 @@ static int call_trans2qfsinfo(connection_struct *conn,
return (ERROR(ERRSRV,ERRinvdevice));
}
- pdata = *ppdata = Realloc(*ppdata, 1024); memset(pdata, 0, 1024);
+ pdata = *ppdata = Realloc(*ppdata, max_data_bytes + 1024);
+ memset((char *)pdata,'\0',max_data_bytes + 1024);
switch (info_level)
{
@@ -1096,7 +1138,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);
+ conn->vfs_ops.disk_free(".",False,&bsize,&dfree,&dsize);
SIVAL(pdata,l1_idFileSystem,st.st_dev);
SIVAL(pdata,l1_cSectorUnit,bsize/512);
SIVAL(pdata,l1_cUnit,dsize);
@@ -1125,16 +1167,22 @@ 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|
+ FILE_DEVICE_IS_MOUNTED|
+ (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), False);
+ 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));
@@ -1152,26 +1200,27 @@ static int call_trans2qfsinfo(connection_struct *conn,
/* NT4 always serves this up as unicode but expects it to be
* delivered as ascii! (tridge && JRA)
*/
- if (global_client_caps & CAP_NT_SMBS) {
+ if ((get_remote_arch() != RA_WIN2K) && (global_client_caps & CAP_NT_SMBS)) {
data_len = 18 + strlen(vname);
SIVAL(pdata,12,strlen(vname));
pstrcpy(pdata+18,vname);
} 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), False);
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS);
}
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);
+ conn->vfs_ops.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;
@@ -1237,6 +1286,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);
@@ -1257,20 +1307,18 @@ 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) && conn->vfs_ops.stat(dos_to_unix(fname,False),&sbuf))) {
DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
if((errno == ENOENT) && bad_path)
{
@@ -1279,6 +1327,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.
@@ -1299,16 +1350,17 @@ 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));
- }
+
+ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
if (!check_name(fname,conn) ||
- (!VALID_STAT(sbuf) && conn->vfs_ops.stat(dos_to_unix(fname,False),
- &sbuf))) {
+ (!VALID_STAT(sbuf) && conn->vfs_ops.stat(dos_to_unix(fname,False),&sbuf))) {
DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
if((errno == ENOENT) && bad_path)
{
@@ -1336,8 +1388,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); memset(params, 0, 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) {
@@ -1346,7 +1399,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
}
- memset(pdata, 0, data_size);
+ memset((char *)pdata,'\0',data_size);
switch (info_level)
{
@@ -1417,26 +1470,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), False);
+ 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), False);
+ } else {
+ pstrcpy(pdata+4,fname);
+ }
data_size = 4 + l;
SIVAL(pdata,0,l);
- pstrcpy(pdata+4,fname);
break;
case SMB_QUERY_FILE_ALLOCATION_INFO:
@@ -1528,20 +1592,16 @@ 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) && conn->vfs_ops.stat(dos_to_unix(fname,False),&st))) {
DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
if((errno == ENOENT) && bad_path)
{
@@ -1570,11 +1630,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)
@@ -1600,10 +1656,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;
@@ -1651,14 +1709,25 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
case SMB_SET_FILE_BASIC_INFO:
{
+ /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
+ time_t write_time;
+ time_t changed_time;
+
/* Ignore create time at offset pdata. */
/* access time */
tvs.actime = interpret_long_date(pdata+8);
- /* write time + changed time, combined. */
- tvs.modtime=MAX(interpret_long_date(pdata+16),
- interpret_long_date(pdata+24));
+ write_time = interpret_long_date(pdata+16);
+ changed_time = interpret_long_date(pdata+24);
+
+ tvs.modtime = MIN(write_time, changed_time);
+
+ /* Prefer a defined time to an undefined one. */
+ if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1)
+ tvs.modtime = (write_time == (time_t)0 || write_time == (time_t)-1
+ ? changed_time
+ : write_time);
#if 0 /* Needs more testing... */
/* Test from Luke to prevent Win95 from
@@ -1673,6 +1742,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);
@@ -1682,12 +1771,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))
@@ -1695,121 +1782,133 @@ 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 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) == 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, 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 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) == 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, 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);
+ unlock_share_entry(fsp->conn, dev, inode);
- /*
- * 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(iterate_fsp, new_share_mode,
- iterate_fsp->granted_oplock ? LEVEL_II_OPLOCK : NO_OPLOCK)==False)
- DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close for fnum %d, \
+ if(modify_share_mode(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);
+ /*
+ * 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);
- } /* 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;
@@ -1821,23 +1920,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
@@ -1845,38 +1954,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"));
- fd = dos_open(fname,O_RDWR,0);
+ if(size != st.st_size) {
+
+ DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new size to %.0f\n",
+ fname, (double)size ));
+
+ if (fd == -1) {
+ fd = conn->vfs_ops.open(dos_to_unix(fname,False),O_RDWR,0);
if (fd == -1)
- {
return(UNIXERROR(ERRDOS,ERRbadpath));
- }
- set_filelen(fd, size);
- close(fd);
- }
- else
- {
- set_filelen(fd, size);
+ set_filelen(fd, size); /* tpot vfs */
+ conn->vfs_ops.close(fd);
+ } else {
+ set_filelen(fd, size); /* tpot vfs */
}
+
+ if(fsp)
+ set_filelen_write_cache(fsp, size);
}
SSVAL(params,0,0);
@@ -1905,14 +2027,10 @@ 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));
+ unix_mode(conn,aDIR,directory));
if(ret < 0)
{
@@ -2007,17 +2125,58 @@ static int call_trans2findnotifynext(connection_struct *conn,
}
/****************************************************************************
+ reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>
+****************************************************************************/
+static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf,
+ char* outbuf, int length, int bufsize,
+ char** pparams, char** ppdata)
+{
+ char *params = *pparams;
+ enum remote_arch_types ra_type = get_remote_arch();
+ BOOL NT_arch = ((ra_type == RA_WINNT) || (ra_type == RA_WIN2K));
+ pstring pathname;
+ int reply_size = 0;
+ int max_referral_level = SVAL(params,0);
+
+
+ DEBUG(10,("call_trans2getdfsreferral\n"));
+
+ if(!lp_host_msdfs())
+ return(ERROR(ERRDOS,ERRbadfunc));
+
+ /* if pathname is in UNICODE, convert to DOS */
+ /* NT always sends in UNICODE, may not set UNICODE flag */
+ if(NT_arch || (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS))
+ {
+ unistr_to_dos(pathname, &params[2]);
+ DEBUG(10,("UNICODE referral for %s\n",pathname));
+ }
+ else
+ pstrcpy(pathname,&params[2]);
+
+ if((reply_size = setup_dfs_referral(pathname,max_referral_level,ppdata)) < 0)
+ return(ERROR(ERRDOS,ERRbadfile));
+
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_UNICODE_STRINGS |
+ FLAGS2_DFS_PATHNAMES);
+ send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size);
+
+ return(-1);
+}
+
+
+/****************************************************************************
reply to a SMBfindclose (stop trans2 directory search)
****************************************************************************/
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);
@@ -2050,237 +2209,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);
- memset(*ppdata, 0, 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!
@@ -2411,104 +2339,78 @@ 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;
+
+ case TRANSACT2_GET_DFS_REFERRAL:
+ outsize = call_trans2getdfsreferral(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
@@ -2526,4 +2428,3 @@ int reply_trans2(connection_struct *conn,
call_trans2xxx calls have already sent
it. If outsize != -1 then it is returning */
}
-
diff --git a/source/smbd/vfs-wrap.c b/source/smbd/vfs-wrap.c
index 3493c231789..24e45a6d24a 100644
--- a/source/smbd/vfs-wrap.c
+++ b/source/smbd/vfs-wrap.c
@@ -1,7 +1,7 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
- Wrap disk only vfs functions to sidestep dodgy compilers.
+s Wrap disk only vfs functions to sidestep dodgy compilers.
Copyright (C) Tim Potter 1998
This program is free software; you can redistribute it and/or modify
@@ -41,7 +41,7 @@ void vfswrap_dummy_disconnect(void)
/* Disk operations */
-SMB_BIG_UINT vfswrap_disk_free(char *path, SMB_BIG_UINT *bsize,
+SMB_BIG_UINT vfswrap_disk_free(char *path, BOOL small_query, SMB_BIG_UINT *bsize,
SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
SMB_BIG_UINT result;
@@ -54,7 +54,7 @@ SMB_BIG_UINT vfswrap_disk_free(char *path, SMB_BIG_UINT *bsize,
}
#endif
- result = sys_disk_free(path, bsize, dfree, dsize);
+ result = sys_disk_free(path, small_query, bsize, dfree, dsize);
return result;
}
@@ -204,9 +204,9 @@ int vfswrap_rename(char *old, char *new)
return result;
}
-void vfswrap_sync_file(int fd)
+void vfswrap_fsync(int fd)
{
- sys_sync_file(fd);
+ fsync(fd);
}
int vfswrap_stat(char *fname, SMB_STRUCT_STAT *sbuf)
@@ -252,15 +252,6 @@ int vfswrap_lstat(char *path,
return result;
}
-BOOL vfswrap_fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count,
- int type)
-{
- BOOL result;
-
- result = fcntl_lock(fd, op, offset, count, type);
- return result;
-}
-
int vfswrap_unlink(char *path)
{
int result;
diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c
index 18aaf0d3604..44f44bd169a 100644
--- a/source/smbd/vfs.c
+++ b/source/smbd/vfs.c
@@ -20,9 +20,6 @@
*/
#include "includes.h"
-#ifdef HAVE_LIBDL
-#include <dlfcn.h>
-#endif
extern int DEBUGLEVEL;
@@ -61,11 +58,10 @@ struct vfs_ops default_vfs_ops = {
vfswrap_write,
vfswrap_lseek,
vfswrap_rename,
- vfswrap_sync_file,
+ vfswrap_fsync,
vfswrap_stat,
vfswrap_fstat,
vfswrap_lstat,
- vfswrap_fcntl_lock,
vfswrap_unlink,
vfswrap_chmod,
vfswrap_utime
@@ -96,7 +92,9 @@ BOOL vfs_init_custom(connection_struct *conn)
/* Open object file */
- handle = dlopen(lp_vfsobj(SNUM(conn)), RTLD_NOW);
+ handle = dlopen(lp_vfsobj(SNUM(conn)), RTLD_NOW | RTLD_GLOBAL);
+ conn->vfs_conn->dl_handle = handle;
+
if (!handle) {
DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)),
dlerror()));
@@ -106,17 +104,17 @@ BOOL vfs_init_custom(connection_struct *conn)
/* Get handle on vfs_init() symbol */
fptr = dlsym(handle, "vfs_init");
+
if (fptr == NULL) {
DEBUG(0, ("No vfs_init() symbol found in %s\n",
lp_vfsobj(SNUM(conn))));
return False;
}
- dlclose(handle);
-
/* Initialise vfs_ops structure */
- if ((ops = fptr(lp_vfsoptions(SNUM(conn)))) == NULL) {
+ if ((ops = fptr(NULL)) == NULL) {
+ DEBUG(0, ("vfs_init function from %s failed\n", lp_vfsobj(SNUM(conn))));
return False;
}
@@ -182,8 +180,8 @@ BOOL vfs_init_custom(connection_struct *conn)
conn->vfs_ops.rename = default_vfs_ops.rename;
}
- if (conn->vfs_ops.sync == NULL) {
- conn->vfs_ops.sync = default_vfs_ops.sync;
+ if (conn->vfs_ops.fsync == NULL) {
+ conn->vfs_ops.fsync = default_vfs_ops.fsync;
}
if (conn->vfs_ops.stat == NULL) {
@@ -198,10 +196,6 @@ BOOL vfs_init_custom(connection_struct *conn)
conn->vfs_ops.lstat = default_vfs_ops.lstat;
}
- if (conn->vfs_ops.lock == NULL) {
- conn->vfs_ops.lock = default_vfs_ops.lock;
- }
-
if (conn->vfs_ops.unlink == NULL) {
conn->vfs_ops.unlink = default_vfs_ops.unlink;
}
@@ -218,6 +212,24 @@ BOOL vfs_init_custom(connection_struct *conn)
}
#endif
+BOOL vfs_directory_exist(connection_struct *conn, char *dname,
+ SMB_STRUCT_STAT *st)
+{
+ SMB_STRUCT_STAT st2;
+ BOOL ret;
+
+ if (!st) st = &st2;
+
+ if (conn->vfs_ops.stat(dos_to_unix(dname,False),st) != 0)
+ return(False);
+
+ ret = S_ISDIR(st->st_mode);
+ if(!ret)
+ errno = ENOTDIR;
+
+ return ret;
+}
+
/*******************************************************************
check if a vfs file exists
********************************************************************/
@@ -377,3 +389,69 @@ char *vfs_readdirname(connection_struct *conn, void *p)
unix_to_dos(dname, True);
return(dname);
}
+
+/* VFS options not quite working yet */
+
+#if 0
+
+/***************************************************************************
+ handle the interpretation of the vfs option parameter
+ *************************************************************************/
+static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
+{
+ struct vfs_options *new_option, **options = (struct vfs_options **)ptr;
+ int i;
+
+ /* Create new vfs option */
+
+ new_option = (struct vfs_options *)malloc(sizeof(*new_option));
+ if (new_option == NULL) {
+ return False;
+ }
+
+ ZERO_STRUCTP(new_option);
+
+ /* Get name and value */
+
+ new_option->name = strtok(pszParmValue, "=");
+
+ if (new_option->name == NULL) {
+ return False;
+ }
+
+ while(isspace(*new_option->name)) {
+ new_option->name++;
+ }
+
+ for (i = strlen(new_option->name); i > 0; i--) {
+ if (!isspace(new_option->name[i - 1])) break;
+ }
+
+ new_option->name[i] = '\0';
+ new_option->name = strdup(new_option->name);
+
+ new_option->value = strtok(NULL, "=");
+
+ if (new_option->value != NULL) {
+
+ while(isspace(*new_option->value)) {
+ new_option->value++;
+ }
+
+ for (i = strlen(new_option->value); i > 0; i--) {
+ if (!isspace(new_option->value[i - 1])) break;
+ }
+
+ new_option->value[i] = '\0';
+ new_option->value = strdup(new_option->value);
+ }
+
+ /* Add to list */
+
+ DLIST_ADD(*options, new_option);
+
+ return True;
+}
+
+#endif
+