Unix SMB/Netbios implementation.
Version 1.9.
Main SMB server routines
- Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Andrew Tridgell 1992-1998
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
extern BOOL use_mangled_map;
extern BOOL short_case_preserve;
extern BOOL case_mangle;
-extern time_t smb_last_time;
+time_t smb_last_time=(time_t)0;
extern int smb_read_error;
extern pstring user_socket_options;
+#ifdef DFS_AUTH
+extern int dcelogin_atmost_once;
+#endif /* DFS_AUTH */
+
connection_struct Connections[MAX_CONNECTIONS];
files_struct Files[MAX_OPEN_FILES];
extern fstring remote_machine;
-pstring OriginalDir;
+extern pstring OriginalDir;
/* these can be set by some functions to override the error codes */
-int unix_ERR_class=SUCCESS;
+int unix_ERR_class=SMB_SUCCESS;
int unix_ERR_code=0;
return(result);
}
-
/*******************************************************************
chmod a file - but preserve some bits
********************************************************************/
return(sys_chmod(fname,unixmode));
}
+/*******************************************************************
+Wrapper around sys_utime that possibly allows DOS semantics rather
+than POSIX.
+*******************************************************************/
+
+int file_utime(int cnum, char *fname, struct utimbuf *times)
+{
+ extern struct current_user current_user;
+ struct stat sb;
+ int ret = -1;
+
+ errno = 0;
+
+ if(sys_utime(fname, times) == 0)
+ return 0;
+
+ if((errno != EPERM) && (errno != EACCES))
+ return -1;
+
+ if(!lp_dos_filetimes(SNUM(cnum)))
+ return -1;
+
+ /* We have permission (given by the Samba admin) to
+ break POSIX semantics and allow a user to change
+ the time on a file they don't own but can write to
+ (as DOS does).
+ */
+
+ if(sys_stat(fname,&sb) != 0)
+ return -1;
+
+ /* Check if we have write access. */
+ if (CAN_WRITE(cnum)) {
+ if (((sb.st_mode & S_IWOTH) ||
+ Connections[cnum].admin_user ||
+ ((sb.st_mode & S_IWUSR) && current_user.uid==sb.st_uid) ||
+ ((sb.st_mode & S_IWGRP) &&
+ in_group(sb.st_gid,current_user.gid,
+ current_user.ngroups,current_user.igroups)))) {
+ /* We are allowed to become root and change the filetime. */
+ become_root(False);
+ ret = sys_utime(fname, times);
+ unbecome_root(False);
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+Change a filetime - possibly allowing DOS semantics.
+*******************************************************************/
+
+BOOL set_filetime(int cnum, char *fname, time_t mtime)
+{
+ struct utimbuf times;
+
+ if (null_mtime(mtime)) return(True);
+
+ times.modtime = times.actime = mtime;
+
+ if (file_utime(cnum, fname, ×)) {
+ DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
+ }
+
+ return(True);
+}
/****************************************************************************
check if two filenames are equal
return(True);
}
+ /*
+ * The incoming name can be mangled, and if we de-mangle it
+ * here it will not compare correctly against the filename (name2)
+ * read from the directory and then mangled by the name_map_mangle()
+ * call. We need to mangle both names or neither.
+ * (JRA).
+ */
if (mangled)
- check_mangled_stack(name);
+ mangled = !check_mangled_cache( name );
/* open the directory */
if (!(cur_dir = OpenDir(cnum, path, True)))
if (!name_map_mangle(name2,False,SNUM(cnum))) continue;
if ((mangled && mangled_equal(name,name2))
- || fname_equal(name, name2)) /* name2 here was changed to dname - since 1.9.16p2 - not sure of reason (jra) */
+ || fname_equal(name, name2))
{
/* we've found the file, change it's name and return */
if (docache) DirCacheAdd(path,name,dname,SNUM(cnum));
/* check on the mangled stack to see if we can recover the
base of the filename */
if (is_mangled(start))
- check_mangled_stack(start);
+ check_mangled_cache( start );
DEBUG(5,("New file %s\n",start));
return(True);
fd support routines - attempt to find a empty slot in the FileFd array.
Increments the ref_count of the returned entry.
****************************************************************************/
-static file_fd_struct *fd_get_new()
+static file_fd_struct *fd_get_new(void)
{
int i;
file_fd_struct *fd_ptr;
struct stat statbuf;
file_fd_struct *fd_ptr;
files_struct *fsp = &Files[fnum];
+ int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
fsp->open = False;
fsp->fd_ptr = 0;
pstrcpy(fname,fname1);
/* check permissions */
- if ((flags != O_RDONLY) && !CAN_WRITE(cnum) && !Connections[cnum].printer)
- {
+
+ /*
+ * This code was changed after seeing a client open request
+ * containing the open mode of (DENY_WRITE/read-only) with
+ * the 'create if not exist' bit set. The previous code
+ * would fail to open the file read only on a read-only share
+ * as it was checking the flags parameter directly against O_RDONLY,
+ * this was failing as the flags parameter was set to O_RDONLY|O_CREAT.
+ * JRA.
+ */
+
+ if (!CAN_WRITE(cnum) && !Connections[cnum].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));
check_for_pipe(fname);
return;
}
+ else if(flags & O_CREAT) {
+ /* We don't want to write - but we must make sure that O_CREAT
+ doesn't create the file if we have write access into the
+ directory.
+ */
+ flags &= ~O_CREAT;
+ }
+ }
/* this handles a bug in Win95 - it doesn't say to create the file when it
should */
DEBUG(3,("Bug in client? Set O_WRONLY without O_CREAT\n"));
*/
-#if UTIME_WORKAROUND
- /* XXXX - is this OK?? */
- /* this works around a utime bug but can cause other problems */
- if ((flags & (O_WRONLY|O_RDWR)) && (flags & O_CREAT) && !(flags & O_APPEND))
- sys_unlink(fname);
-#endif
-
/*
* Ensure we have a valid struct stat so we can search the
* open fd table.
*/
if((fd_ptr = fd_get_already_open(sbuf))!= 0) {
- int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
-
/* File was already open. */
if((flags & O_CREAT) && (flags & O_EXCL)) {
fd_ptr->ref_count--;
Connections[cnum].num_files_open++;
fsp->mode = sbuf->st_mode;
GetTimeOfDay(&fsp->open_time);
- fsp->uid = current_user.id;
+ fsp->vuid = current_user.vuid;
fsp->size = 0;
fsp->pos = -1;
fsp->open = True;
fsp->print_file = Connections[cnum].printer;
fsp->modified = False;
fsp->granted_oplock = False;
+ fsp->sent_oplock_break = False;
fsp->cnum = cnum;
string_set(&fsp->name,dos_to_unix(fname,False));
fsp->wbmpx_ptr = NULL;
/****************************************************************************
close a file - possibly invalidating the read prediction
+
+If normal_close is 1 then this came from a normal SMBclose (or equivalent)
+operation otherwise it came as the result of some other operation such as
+the closing of the connection. In the latter case printing and
+magic scripts are not run
****************************************************************************/
-void close_file(int fnum)
+void close_file(int fnum, BOOL normal_close)
{
files_struct *fs_p = &Files[fnum];
int cnum = fs_p->cnum;
uint32 dev = fs_p->fd_ptr->dev;
uint32 inode = fs_p->fd_ptr->inode;
- share_lock_token token;
+ int token;
+
+ Files[fnum].reserved = False;
+#if USE_READ_PREDICTION
invalidate_read_prediction(fs_p->fd_ptr->fd);
+#endif
+
fs_p->open = False;
Connections[cnum].num_files_open--;
if(fs_p->wbmpx_ptr)
unlock_share_entry( cnum, dev, inode, token);
/* NT uses smbclose to start a print - weird */
- if (fs_p->print_file)
+ if (normal_close && fs_p->print_file)
print_file(fnum);
/* check for magic scripts */
- check_magic(fnum,cnum);
+ if (normal_close)
+ check_magic(fnum,cnum);
+
+ if(fs_p->granted_oplock == True)
+ global_oplocks_open--;
+
+ fs_p->sent_oplock_break = False;
DEBUG(2,("%s %s closed file %s (numopen=%d)\n",
timestring(),Connections[cnum].user,fs_p->name,
Connections[cnum].num_files_open));
+
+ if (fs_p->name) {
+ string_free(&fs_p->name);
+ }
+
+ /* we will catch bugs faster by zeroing this structure */
+ memset(fs_p, 0, sizeof(*fs_p));
}
enum {AFAIL,AREAD,AWRITE,AALL};
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(int cnum,char *fname)
+BOOL check_file_sharing(int cnum,char *fname, BOOL rename_op)
{
int i;
int ret = False;
- min_share_mode_entry *old_shares = 0;
+ share_mode_entry *old_shares = 0;
int num_share_modes;
struct stat sbuf;
- share_lock_token token;
+ int token;
int pid = getpid();
uint32 dev, inode;
broke_oplock = False;
for(i = 0; i < num_share_modes; i++)
{
- min_share_mode_entry *share_entry = &old_shares[i];
+ share_mode_entry *share_entry = &old_shares[i];
/*
* Break oplocks before checking share modes. See comment in
if(share_entry->op_type & BATCH_OPLOCK)
{
- DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \
+ /*
+ * 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
+ * batch oplock, and then fails to respond to the oplock break
+ * request. This only seems to occur when the client is doing an
+ * SMBmv to the smbd it is using - thus we try and detect this
+ * condition by checking if the file being moved is open and oplocked by
+ * this smbd process, and then not sending the oplock break in this
+ * special case. If the file was open with a deny mode that
+ * prevents the move the SMBmv will fail anyway with a share
+ * violation error. JRA.
+ */
+ if(rename_op && (share_entry->pid == pid))
+ {
+ DEBUG(0,("check_file_sharing: NT redirector workaround - rename attempted on \
+batch oplocked file %s, dev = %x, inode = %x\n", fname, dev, inode));
+ /*
+ * This next line is a test that allows the deny-mode
+ * processing to be skipped. This seems to be needed as
+ * NT insists on the rename succeeding (in Office 9x no less !).
+ * This should be removed as soon as (a) MS fix the redirector
+ * bug or (b) NT SMB support in Samba makes NT not issue the
+ * call (as is my fervent hope). JRA.
+ */
+ continue;
+ }
+ else
+ {
+ DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \
dev = %x, inode = %x\n", share_entry->op_type, fname, dev, inode));
- /* Oplock break.... */
- unlock_share_entry(cnum, dev, inode, token);
- if(request_oplock_break(share_entry, dev, inode) == False)
- {
- free((char *)old_shares);
- DEBUG(0,("check_file_sharing: FAILED when breaking oplock (%x) on file %s, \
+ /* Oplock break.... */
+ unlock_share_entry(cnum, dev, inode, token);
+ if(request_oplock_break(share_entry, dev, inode) == False)
+ {
+ free((char *)old_shares);
+ DEBUG(0,("check_file_sharing: FAILED when breaking oplock (%x) on file %s, \
dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
- return False;
+ return False;
+ }
+ lock_share_entry(cnum, dev, inode, &token);
+ broke_oplock = True;
+ break;
}
- lock_share_entry(cnum, dev, inode, &token);
- broke_oplock = True;
- break;
}
/* someone else has a share lock on it, check to see
Helper for open_file_shared.
Truncate a file after checking locking; close file if locked.
**************************************************************************/
-static void truncate_unless_locked(int fnum, int cnum, share_lock_token token,
- BOOL *share_locked)
+static void truncate_unless_locked(int fnum, int cnum, int token,
+ BOOL *share_locked)
{
if (Files[fnum].can_write){
if (is_locked(fnum,cnum,0x3FFFFFFF,0)){
if (*share_locked && lp_share_modes(SNUM(cnum)))
unlock_share_entry( cnum, Files[fnum].fd_ptr->dev,
Files[fnum].fd_ptr->inode, token);
- close_file(fnum);
+ close_file(fnum,False);
/* Share mode no longer locked. */
*share_locked = False;
errno = EACCES;
/****************************************************************************
check if we can open a file with a share mode
****************************************************************************/
-int check_share_mode( min_share_mode_entry *share, int deny_mode, char *fname,
+int check_share_mode( share_mode_entry *share, int deny_mode, char *fname,
BOOL fcbopen, int *flags)
{
int old_open_mode = share->share_mode &0xF;
(access_allowed == AREAD && *flags == O_WRONLY) ||
(access_allowed == AWRITE && *flags == O_RDONLY))
{
- DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n",
+ 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, access_allowed));
+ share->pid,fname, fcbopen, *flags, access_allowed));
return False;
}
BOOL file_existed = file_exist(fname,&sbuf);
BOOL share_locked = False;
BOOL fcbopen = False;
- share_lock_token token;
+ int token;
uint32 dev = 0;
uint32 inode = 0;
int num_share_modes = 0;
{
unix_ERR_class = ERRDOS;
/* OS/2 Workplace shell fix may be main code stream in a later release. */
-#ifdef OS2_WPS_FIX
+#if 1 /* OS2_WPS_FIX - Recent versions of OS/2 need this. */
unix_ERR_code = ERRcannotopen;
#else /* OS2_WPS_FIX */
unix_ERR_code = ERROR_EAS_NOT_SUPPORTED;
flags = O_RDONLY;
break;
}
+
+ if (share_mode&(1<<14)) {
+ flags2 |= O_SYNC;
+ }
if (flags != O_RDONLY && file_existed &&
(!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf))))
if (lp_share_modes(SNUM(cnum)))
{
int i;
- min_share_mode_entry *old_shares = 0;
+ share_mode_entry *old_shares = 0;
if (file_existed)
{
broke_oplock = False;
for(i = 0; i < num_share_modes; i++)
{
- min_share_mode_entry *share_entry = &old_shares[i];
+ share_mode_entry *share_entry = &old_shares[i];
/*
* By observation of NetBench, oplocks are broken *before* share
be extended to level II oplocks (multiple reader
oplocks). */
- if(oplock_request && (num_share_modes == 0) && lp_oplocks(SNUM(cnum)))
+ if(oplock_request && (num_share_modes == 0) && lp_oplocks(SNUM(cnum)) &&
+ !IS_VETO_OPLOCK_PATH(cnum,fname))
{
fs_p->granted_oplock = True;
+ fs_p->sent_oplock_break = False;
global_oplocks_open++;
port = oplock_port;
{
int ret=0,readret;
+#if USE_READ_PREDICTION
if (!Files[fnum].can_write)
{
ret = read_predict(Files[fnum].fd_ptr->fd,pos,data,NULL,n);
n -= ret;
pos += ret;
}
+#endif
#if USE_MMAP
if (Files[fnum].mmap_ptr)
{
- int num = MIN(n,(int)(Files[fnum].mmap_size-pos));
+ int num = (Files[fnum].mmap_size > pos) ? (Files[fnum].mmap_size - pos) : -1;
+ num = MIN(n,num);
if (num > 0)
{
memcpy(data,Files[fnum].mmap_ptr+pos,num);
/* just possibly it's a default service? */
if (iService < 0)
{
- char *defservice = lp_defaultservice();
- if (defservice && *defservice && !strequal(defservice,service)) {
+ char *pdefservice = lp_defaultservice();
+ if (pdefservice && *pdefservice && !strequal(pdefservice,service)) {
+ /*
+ * We need to do a local copy here as lp_defaultservice()
+ * returns one of the rotating lp_string buffers that
+ * could get overwritten by the recursive find_service() call
+ * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
+ */
+ pstring defservice;
+ pstrcpy(defservice, pdefservice);
iService = find_service(defservice);
if (iService >= 0) {
string_sub(service,"_","/");
int ecode=def_code;
int i=0;
- if (unix_ERR_class != SUCCESS)
+ if (unix_ERR_class != SMB_SUCCESS)
{
eclass = unix_ERR_class;
ecode = unix_ERR_code;
- unix_ERR_class = SUCCESS;
+ unix_ERR_class = SMB_SUCCESS;
unix_ERR_code = 0;
}
else
int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line)
{
int outsize = set_message(outbuf,0,0,True);
- int cmd;
- cmd = CVAL(inbuf,smb_com);
-
- CVAL(outbuf,smb_rcls) = error_class;
- SSVAL(outbuf,smb_err,error_code);
-
- DEBUG(3,("%s error packet at line %d cmd=%d (%s) eclass=%d ecode=%d\n",
+ int cmd = CVAL(inbuf,smb_com);
+ int flgs2 = SVAL(outbuf,smb_flg2);
+
+ if ((flgs2 & FLAGS2_32_BIT_ERROR_CODES) == FLAGS2_32_BIT_ERROR_CODES)
+ {
+ SIVAL(outbuf,smb_rcls,error_code);
+
+ DEBUG(3,("%s 32 bit error packet at line %d cmd=%d (%s) eclass=%08x [%s]\n",
+ timestring(), line, cmd, smb_fn_name(cmd), error_code, smb_errstr(outbuf)));
+ }
+ else
+ {
+ CVAL(outbuf,smb_rcls) = error_class;
+ SSVAL(outbuf,smb_err,error_code);
+ DEBUG(3,("%s error packet at line %d cmd=%d (%s) eclass=%d ecode=%d\n",
timestring(),
line,
(int)CVAL(inbuf,smb_com),
error_class,
error_code));
+ }
+
if (errno != 0)
DEBUG(3,("error string = %s\n",strerror(errno)));
/****************************************************************************
this prevents zombie child processes
****************************************************************************/
-static int sig_cld()
+static int sig_cld(void)
{
static int depth = 0;
if (depth != 0)
/****************************************************************************
this is called when the client exits abruptly
**************************************************************************/
-static int sig_pipe()
+static int sig_pipe(void)
{
- extern int password_client;
- BlockSignals(True,SIGPIPE);
+ struct cli_state *cli;
+ BlockSignals(True,SIGPIPE);
- if (password_client != -1) {
- DEBUG(3,("lost connection to password server\n"));
- close(password_client);
- password_client = -1;
+ if ((cli = server_client()) && cli->initialised) {
+ DEBUG(3,("lost connection to password server\n"));
+ cli_shutdown(cli);
#ifndef DONT_REINSTALL_SIG
- signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+ signal(SIGPIPE, SIGNAL_CAST sig_pipe);
#endif
- BlockSignals(False,SIGPIPE);
- return 0;
- }
+ BlockSignals(False,SIGPIPE);
+ return 0;
+ }
- exit_server("Got sigpipe\n");
- return(0);
+ exit_server("Got sigpipe\n");
+ return(0);
}
/****************************************************************************
extern int Client;
if (is_daemon)
- {
- int s;
- struct sockaddr addr;
- int in_addrlen = sizeof(addr);
-
- /* Stop zombies */
+ {
+ int num_interfaces = iface_count();
+ int fd_listenset[FD_SETSIZE];
+ fd_set listen_set;
+ int s;
+ int i;
+
+ /* Stop zombies */
#ifdef SIGCLD_IGNORE
- signal(SIGCLD, SIG_IGN);
+ signal(SIGCLD, SIG_IGN);
#else
- signal(SIGCLD, SIGNAL_CAST sig_cld);
+ signal(SIGCLD, SIGNAL_CAST sig_cld);
#endif
+ if(atexit_set == 0)
+ atexit(killkids);
+
+ FD_ZERO(&listen_set);
+
+ if(lp_interfaces() && lp_bind_interfaces_only())
+ {
+ /* We have been given an interfaces line, and been
+ told to only bind to those interfaces. Create a
+ socket per interface and bind to only these.
+ */
+
+ if(num_interfaces > FD_SETSIZE)
+ {
+ DEBUG(0,("open_sockets: Too many interfaces specified to bind to. Number was %d \
+max can be %d\n", num_interfaces, FD_SETSIZE));
+ return False;
+ }
+
+ /* Now open a listen socket for each of the interfaces. */
+ for(i = 0; i < num_interfaces; i++)
+ {
+ struct in_addr *ifip = iface_n_ip(i);
+
+ if(ifip == NULL)
+ {
+ DEBUG(0,("open_sockets: interface %d has NULL IP address !\n", i));
+ continue;
+ }
+ s = fd_listenset[i] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr);
+ if(s == -1)
+ return False;
+ /* ready to listen */
+ if (listen(s, 5) == -1)
+ {
+ DEBUG(0,("listen: %s\n",strerror(errno)));
+ close(s);
+ return False;
+ }
+ FD_SET(s,&listen_set);
+ }
+ }
+ else
+ {
+ /* Just bind to 0.0.0.0 - accept connections from anywhere. */
+ num_interfaces = 1;
+
/* open an incoming socket */
s = open_socket_in(SOCK_STREAM, port, 0,interpret_addr(lp_socket_address()));
if (s == -1)
- return(False);
+ return(False);
/* ready to listen */
if (listen(s, 5) == -1)
- {
- DEBUG(0,("listen: %s\n",strerror(errno)));
- close(s);
- return False;
- }
-
- if(atexit_set == 0)
- atexit(killkids);
+ {
+ DEBUG(0,("open_sockets: listen: %s\n",strerror(errno)));
+ close(s);
+ return False;
+ }
- /* now accept incoming connections - forking a new process
- for each incoming connection */
- DEBUG(2,("waiting for a connection\n"));
- while (1)
- {
- Client = accept(s,&addr,&in_addrlen);
+ fd_listenset[0] = s;
+ FD_SET(s,&listen_set);
+ }
- if (Client == -1 && errno == EINTR)
- continue;
+ /* now accept incoming connections - forking a new process
+ for each incoming connection */
+ DEBUG(2,("waiting for a connection\n"));
+ while (1)
+ {
+ fd_set lfds;
+ int num;
- if (Client == -1)
- {
- DEBUG(0,("accept: %s\n",strerror(errno)));
- continue;
- }
+ memcpy((char *)&lfds, (char *)&listen_set, sizeof(listen_set));
+
+ num = sys_select(&lfds,NULL);
+
+ if (num == -1 && errno == EINTR)
+ continue;
+
+ /* Find the sockets that are read-ready - accept on these. */
+ for( ; num > 0; num--)
+ {
+ struct sockaddr addr;
+ int in_addrlen = sizeof(addr);
+
+ s = -1;
+ for(i = 0; i < num_interfaces; i++)
+ {
+ if(FD_ISSET(fd_listenset[i],&lfds))
+ {
+ s = fd_listenset[i];
+ /* Clear this so we don't look at it again. */
+ FD_CLR(fd_listenset[i],&lfds);
+ break;
+ }
+ }
+
+ Client = accept(s,&addr,&in_addrlen);
+
+ if (Client == -1 && errno == EINTR)
+ continue;
+
+ if (Client == -1)
+ {
+ DEBUG(0,("open_sockets: accept: %s\n",strerror(errno)));
+ continue;
+ }
#ifdef NO_FORK_DEBUG
+#ifndef NO_SIGNAL_TEST
+ signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+ signal(SIGCLD, SIGNAL_CAST SIG_DFL);
+#endif /* NO_SIGNAL_TEST */
+ return True;
+#else /* NO_FORK_DEBUG */
+ if (Client != -1 && fork()==0)
+ {
+ /* Child code ... */
+
#ifndef NO_SIGNAL_TEST
signal(SIGPIPE, SIGNAL_CAST sig_pipe);
signal(SIGCLD, SIGNAL_CAST SIG_DFL);
-#endif
- return True;
-#else
- if (Client != -1 && fork()==0)
- {
- /* Child code ... */
-#ifndef NO_SIGNAL_TEST
- signal(SIGPIPE, SIGNAL_CAST sig_pipe);
- signal(SIGCLD, SIGNAL_CAST SIG_DFL);
-#endif
- /* close the listening socket */
- close(s);
-
- /* close our standard file descriptors */
- close_low_fds();
- am_parent = 0;
+#endif /* NO_SIGNAL_TEST */
+ /* close the listening socket(s) */
+ for(i = 0; i < num_interfaces; i++)
+ close(fd_listenset[i]);
+
+ /* close our standard file descriptors */
+ close_low_fds();
+ am_parent = 0;
- set_socket_options(Client,"SO_KEEPALIVE");
- set_socket_options(Client,user_socket_options);
-
- /* Reset global variables in util.c so that
- client substitutions will be done correctly
- in the process.
- */
- reset_globals_after_fork();
- return True;
- }
- close(Client); /* The parent doesn't need this socket */
-#endif
- }
- }
+ set_socket_options(Client,"SO_KEEPALIVE");
+ set_socket_options(Client,user_socket_options);
+
+ /* Reset global variables in util.c so that
+ client substitutions will be done correctly
+ in the process.
+ */
+ reset_globals_after_fork();
+ return True;
+ }
+ close(Client); /* The parent doesn't need this socket */
+#endif /* NO_FORK_DEBUG */
+ } /* end for num */
+ } /* end while 1 */
+ } /* end if is_daemon */
else
- {
- /* We will abort gracefully when the client or remote system
- goes away */
+ {
+ /* Started from inetd. fd 0 is the socket. */
+ /* We will abort gracefully when the client or remote system
+ goes away */
#ifndef NO_SIGNAL_TEST
- signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+ signal(SIGPIPE, SIGNAL_CAST sig_pipe);
#endif
- Client = dup(0);
+ Client = dup(0);
- /* close our standard file descriptors */
- close_low_fds();
+ /* close our standard file descriptors */
+ close_low_fds();
- set_socket_options(Client,"SO_KEEPALIVE");
- set_socket_options(Client,user_socket_options);
- }
+ set_socket_options(Client,"SO_KEEPALIVE");
+ set_socket_options(Client,user_socket_options);
+ }
return True;
}
name" */
static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
DEBUG(1,("%s Connection denied from %s\n",
- timestring(),client_addr()));
+ timestring(),client_addr(Client)));
send_smb(Client,(char *)buf);
exit_server("connection denied");
}
if (msg_type == 0)
show_msg(inbuf);
+ else if(msg_type == 0x85)
+ return; /* Keepalive packet. */
nread = construct_reply(inbuf,outbuf,nread,max_send);
/****************************************************************************
open the oplock IPC socket communication
****************************************************************************/
-static BOOL open_oplock_ipc()
+static BOOL open_oplock_ipc(void)
{
struct sockaddr_in sock_name;
int len = sizeof(sock_name);
static BOOL process_local_message(int sock, char *buffer, int buf_size)
{
int32 msg_len;
- int16 from_port;
+ uint16 from_port;
char *msg_start;
msg_len = IVAL(buffer,UDP_CMD_LEN_OFFSET);
BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval)
{
extern int Client;
- static char *inbuf = NULL;
- static char *outbuf = NULL;
+ char *inbuf = NULL;
+ char *outbuf = NULL;
files_struct *fsp = NULL;
int fnum;
time_t start_time;
BOOL shutdown_server = False;
- DEBUG(5,("oplock_break: called for dev = %x, inode = %x. Current \
-global_oplocks_open = %d\n", dev, inode, global_oplocks_open));
-
- if(inbuf == NULL)
- {
- inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- if(inbuf == NULL) {
- DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
- return False;
- }
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- if(outbuf == NULL) {
- DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
- free(inbuf);
- inbuf = NULL;
- return False;
- }
- }
+ DEBUG(3,("%s oplock_break: called for dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", timestring(), dev, inode, global_oplocks_open));
/* We need to search the file open table for the
entry containing this dev and inode, and ensure
{
if(OPEN_FNUM(fnum))
{
- fsp = &Files[fnum];
- if((fsp->fd_ptr->dev == dev) && (fsp->fd_ptr->inode == inode) &&
- (fsp->open_time.tv_sec == tval->tv_sec) &&
- (fsp->open_time.tv_usec == tval->tv_usec))
- break;
+ if((Files[fnum].fd_ptr->dev == dev) && (Files[fnum].fd_ptr->inode == inode) &&
+ (Files[fnum].open_time.tv_sec == tval->tv_sec) &&
+ (Files[fnum].open_time.tv_usec == tval->tv_usec)) {
+ fsp = &Files[fnum];
+ break;
+ }
}
}
if(fsp == NULL)
{
/* The file could have been closed in the meantime - return success. */
- DEBUG(3,("oplock_break: cannot find open file with dev = %x, inode = %x (fnum = %d) \
-allowing break to succeed.\n", dev, inode, fnum));
+ DEBUG(0,("%s oplock_break: cannot find open file with dev = %x, inode = %x (fnum = %d) \
+allowing break to succeed.\n", timestring(), dev, inode, fnum));
return True;
}
if(!fsp->granted_oplock)
{
- DEBUG(3,("oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock. \
-Allowing break to succeed regardless.\n", fsp->name, fnum, dev, inode));
+ DEBUG(0,("%s oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock. Allowing break to succeed regardless.\n", timestring(), fsp->name, fnum, dev, inode));
return True;
}
+ /* mark the oplock break as sent - we don't want to send twice! */
+ if (fsp->sent_oplock_break)
+ {
+ DEBUG(0,("%s oplock_break: ERROR: oplock_break already sent for file %s (fnum = %d, dev = %x, inode = %x)\n", timestring(), fsp->name, fnum, dev, inode));
+
+ /* We have to fail the open here as we cannot send another oplock break on this
+ file whilst we are awaiting a response from the client - neither can we
+ allow another open to succeed while we are waiting for the client. */
+ return False;
+ }
+
/* 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.
+ We cannot use these staticaly as we may recurse into here due to
+ messages crossing on the wire.
*/
+ if((inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN))==NULL)
+ {
+ DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
+ return False;
+ }
+
+ if((outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN))==NULL)
+ {
+ DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
+ free(inbuf);
+ inbuf = NULL;
+ return False;
+ }
+
/* Prepare the SMBlockingX message. */
bzero(outbuf,smb_size);
set_message(outbuf,8,0,True);
send_smb(Client, outbuf);
+ /* Remember we just sent an oplock break on this file. */
+ fsp->sent_oplock_break = True;
+
+ /* We need this in case a readraw crosses on the wire. */
global_oplock_break = True;
/* Process incoming messages. */
*/
if (smb_read_error == READ_EOF)
- DEBUG(0,("oplock_break: end of file from client\n"));
+ DEBUG(0,("%s oplock_break: end of file from client\n", timestring()));
if (smb_read_error == READ_ERROR)
- DEBUG(0,("oplock_break: receive_smb error (%s)\n",
- strerror(errno)));
+ DEBUG(0,("%s oplock_break: receive_smb error (%s)\n",
+ timestring(), strerror(errno)));
if (smb_read_error == READ_TIMEOUT)
- DEBUG(0,("oplock_break: receive_smb timed out after %d seconds.\n",
- OPLOCK_BREAK_TIMEOUT));
+ DEBUG(0,("%s oplock_break: receive_smb timed out after %d seconds.\n",
+ timestring(), OPLOCK_BREAK_TIMEOUT));
- DEBUG(0,("oplock_break failed for file %s (fnum = %d, dev = %x, \
-inode = %x).\n", fsp->name, fnum, dev, inode));
+ DEBUG(0,("%s oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
shutdown_server = True;
break;
}
- process_smb(inbuf, outbuf);
- /* We only need this in case a readraw crossed on the wire. */
- if(global_oplock_break)
- global_oplock_break = False;
+ /*
+ * There are certain SMB requests that we shouldn't allow
+ * to recurse. opens, renames and deletes are the obvious
+ * ones. This is handled in the switch_message() function.
+ * If global_oplock_break is set they will push the packet onto
+ * the pending smb queue and return -1 (no reply).
+ * JRA.
+ */
+
+ process_smb(inbuf, outbuf);
/*
* Die if we go over the time limit.
if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT)
{
- DEBUG(0,("oplock_break: no break received from client within \
-%d seconds.\n", OPLOCK_BREAK_TIMEOUT));
- DEBUG(0,("oplock_break failed for file %s (fnum = %d, dev = %x, \
-inode = %x).\n", fsp->name, fnum, dev, inode));
+ DEBUG(0,("%s oplock_break: no break received from client within \
+%d seconds.\n", timestring(), OPLOCK_BREAK_TIMEOUT));
+ DEBUG(0,("%s oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
shutdown_server = True;
break;
}
}
+ /* Free the buffers we've been using to recurse. */
+ free(inbuf);
+ free(outbuf);
+
+ /* We need this in case a readraw crossed on the wire. */
+ if(global_oplock_break)
+ global_oplock_break = False;
+
/*
* If the client did not respond we must die.
*/
if(shutdown_server)
{
- DEBUG(0,("oplock_break: client failure in break - shutting down this smbd.\n"));
+ DEBUG(0,("%s oplock_break: client failure in break - shutting down this smbd.\n",
+ timestring()));
close_sockets();
close(oplock_sock);
exit_server("oplock break failure");
from the sharemode. */
/* Paranoia.... */
fsp->granted_oplock = False;
+ fsp->sent_oplock_break = False;
+ global_oplocks_open--;
}
- global_oplocks_open--;
-
/* Santity check - remove this later. JRA */
if(global_oplocks_open < 0)
{
exit_server("oplock_break: global_oplocks_open < 0");
}
- DEBUG(5,("oplock_break: returning success for fnum = %d, dev = %x, inode = %x. Current \
-global_oplocks_open = %d\n", fnum, dev, inode, global_oplocks_open));
+ DEBUG(3,("%s oplock_break: returning success for fnum = %d, dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", timestring(), fnum, dev, inode, global_oplocks_open));
return True;
}
by the local smbd then call the oplock break function directly.
****************************************************************************/
-BOOL request_oplock_break(min_share_mode_entry *share_entry,
+BOOL request_oplock_break(share_mode_entry *share_entry,
uint32 dev, uint32 inode)
{
char op_break_msg[OPLOCK_BREAK_MSG_LEN];
struct sockaddr_in addr_out;
int pid = getpid();
+ time_t start_time;
+ int time_left;
if(pid == share_entry->pid)
{
addr_out.sin_port = htons( share_entry->op_port );
addr_out.sin_family = AF_INET;
- DEBUG(3,("request_oplock_break: sending a oplock break message to pid %d on port %d \
-for dev = %x, inode = %x\n", share_entry->pid, share_entry->op_port, dev, inode));
+ DEBUG(3,("%s request_oplock_break: sending a oplock break message to pid %d on port %d \
+for dev = %x, inode = %x\n", timestring(), share_entry->pid, share_entry->op_port, dev, inode));
if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0,
(struct sockaddr *)&addr_out,sizeof(addr_out)) < 0)
{
- DEBUG(0,("request_oplock_break: failed when sending a oplock break message \
+ DEBUG(0,("%s request_oplock_break: failed when sending a oplock break message \
to pid %d on port %d for dev = %x, inode = %x. Error was %s\n",
- share_entry->pid, share_entry->op_port, dev, inode,
+ timestring(), share_entry->pid, share_entry->op_port, dev, inode,
strerror(errno)));
return False;
}
/*
* 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 seconds.
+ * return in (OPLOCK_BREAK_TIMEOUT + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) seconds.
* While we get messages that aren't ours, loop.
*/
- while(1)
+ start_time = time(NULL);
+ time_left = OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR;
+
+ while(time_left >= 0)
{
char op_break_reply[UDP_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN];
int32 reply_msg_len;
- int16 reply_from_port;
+ uint16 reply_from_port;
char *reply_msg_start;
if(receive_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply),
- OPLOCK_BREAK_TIMEOUT * 1000) == False)
+ time_left ? time_left * 1000 : 1) == False)
{
if(smb_read_error == READ_TIMEOUT)
- DEBUG(0,("request_oplock_break: no response received to oplock break request to \
-pid %d on port %d for dev = %x, inode = %x\n", share_entry->pid,
+ {
+ DEBUG(0,("%s request_oplock_break: no response received to oplock break request to \
+pid %d on port %d for dev = %x, inode = %x\n", timestring(), share_entry->pid,
share_entry->op_port, dev, inode));
+ /*
+ * This is a hack to make handling of failing clients more robust.
+ * If a oplock break response message is not received in the timeout
+ * period we may assume that the smbd servicing that client holding
+ * the oplock has died and the client changes were lost anyway, so
+ * we should continue to try and open the file.
+ */
+ break;
+ }
else
- DEBUG(0,("request_oplock_break: error in response received to oplock break request to \
-pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", share_entry->pid,
+ DEBUG(0,("%s request_oplock_break: error in response received to oplock break request to \
+pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", timestring, share_entry->pid,
share_entry->op_port, dev, inode, strerror(errno)));
return False;
}
- /*
- * If the response we got was not an answer to our message, but
- * was a completely different request, push it onto the pending
- * udp message stack so that we can deal with it in the main loop.
- * It may be another oplock break request to us.
- */
-
- /*
- * Local note from JRA. There exists the possibility of a denial
- * of service attack here by allowing non-root processes running
- * on a local machine sending many of these pending messages to
- * a smbd port. Currently I'm not sure how to restrict the messages
- * I will queue (although I could add a limit to the queue) to
- * those received by root processes only. There should be a
- * way to make this bulletproof....
- */
-
reply_msg_len = IVAL(op_break_reply,UDP_CMD_LEN_OFFSET);
reply_from_port = SVAL(op_break_reply,UDP_CMD_PORT_OFFSET);
if(reply_msg_len != OPLOCK_BREAK_MSG_LEN)
{
/* Ignore it. */
- DEBUG(0,("request_oplock_break: invalid message length received. Ignoring\n"));
+ DEBUG(0,("%s request_oplock_break: invalid message length received. Ignoring\n",
+ timestring()));
continue;
}
- if(((SVAL(reply_msg_start,UDP_MESSAGE_CMD_OFFSET) & CMD_REPLY) == 0) ||
- (reply_from_port != share_entry->op_port) ||
+ /*
+ * Test to see if this is the reply we are awaiting.
+ */
+
+ if((SVAL(reply_msg_start,UDP_MESSAGE_CMD_OFFSET) & CMD_REPLY) &&
+ (reply_from_port == share_entry->op_port) &&
(memcmp(&reply_msg_start[OPLOCK_BREAK_PID_OFFSET],
&op_break_msg[OPLOCK_BREAK_PID_OFFSET],
- OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) != 0))
+ OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) == 0))
{
- DEBUG(3,("request_oplock_break: received other message whilst awaiting \
-oplock break response from pid %d on port %d for dev = %x, inode = %x.\n",
- share_entry->pid, share_entry->op_port, dev, inode));
- if(push_local_message(op_break_reply, sizeof(op_break_reply)) == False)
- return False;
- continue;
+ /*
+ * This is the reply we've been waiting for.
+ */
+ break;
}
+ else
+ {
+ /*
+ * This is another message - probably a break request.
+ * Process it to prevent potential deadlock.
+ * Note that the code in switch_message() prevents
+ * us from recursing into here as any SMB requests
+ * we might process that would cause another oplock
+ * break request to be made will be queued.
+ * JRA.
+ */
- break;
+ process_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply));
+ }
+
+ time_left -= (time(NULL) - start_time);
}
- DEBUG(3,("request_oplock_break: broke oplock.\n"));
+ DEBUG(3,("%s request_oplock_break: broke oplock.\n", timestring()));
return True;
}
+/****************************************************************************
+Get the next SMB packet, doing the local message processing automatically.
+****************************************************************************/
+
+BOOL receive_next_smb(int smbfd, int oplockfd, char *inbuf, int bufsize, int timeout)
+{
+ BOOL got_smb = False;
+ BOOL ret;
+
+ do
+ {
+ ret = receive_message_or_smb(smbfd,oplockfd,inbuf,bufsize,
+ timeout,&got_smb);
+
+ if(ret && !got_smb)
+ {
+ /* Deal with oplock break requests from other smbd's. */
+ process_local_message(oplock_sock, inbuf, bufsize);
+ continue;
+ }
+
+ if(ret && (CVAL(inbuf,0) == 0x85))
+ {
+ /* Keepalive packet. */
+ got_smb = False;
+ }
+
+ }
+ while(ret && !got_smb);
+
+ return ret;
+}
+
/****************************************************************************
check if a snum is in use
****************************************************************************/
lp_killunused(snum_used);
- ret = lp_load(servicesf,False);
+ ret = lp_load(servicesf,False,False,True);
/* perhaps the config filename is now set */
if (!test)
}
}
- create_mangled_stack(lp_mangledstack());
+ reset_mangled_cache();
/* this forces service parameters to be flushed */
become_service(-1,True);
/****************************************************************************
this prevents zombie child processes
****************************************************************************/
-static int sig_hup()
+static int sig_hup(void)
{
BlockSignals(True,SIGHUP);
DEBUG(0,("Got SIGHUP\n"));
return(0);
}
-/****************************************************************************
-Setup the groups a user belongs to.
-****************************************************************************/
-int setup_groups(char *user, int uid, int gid, int *p_ngroups,
- int **p_igroups, gid_t **p_groups,
- int **p_attrs)
-{
- if (-1 == initgroups(user,gid))
- {
- if (getuid() == 0)
- {
- DEBUG(0,("Unable to initgroups!\n"));
- if (gid < 0 || gid > 16000 || uid < 0 || uid > 16000)
- DEBUG(0,("This is probably a problem with the account %s\n",user));
- }
- }
- else
- {
- int i,ngroups;
- int *igroups;
- int *attrs;
- gid_t grp = 0;
- ngroups = getgroups(0,&grp);
- if (ngroups <= 0)
- ngroups = 32;
- igroups = (int *)malloc(sizeof(int)*ngroups);
- attrs = (int *)malloc(sizeof(int)*ngroups);
- for (i=0;i<ngroups;i++)
- {
- attrs [i] = 0x7; /* XXXX don't know what NT user attributes are yet! */
- igroups[i] = 0x42424242;
- }
- ngroups = getgroups(ngroups,(gid_t *)igroups);
-
- if (igroups[0] == 0x42424242)
- ngroups = 0;
-
- *p_ngroups = ngroups;
- *p_attrs = attrs;
-
- /* The following bit of code is very strange. It is due to the
- fact that some OSes use int* and some use gid_t* for
- getgroups, and some (like SunOS) use both, one in prototypes,
- and one in man pages and the actual code. Thus we detect it
- dynamically using some very ugly code */
- if (ngroups > 0)
- {
- /* does getgroups return ints or gid_t ?? */
- static BOOL groups_use_ints = True;
-
- if (groups_use_ints &&
- ngroups == 1 &&
- SVAL(igroups,2) == 0x4242)
- groups_use_ints = False;
-
- for (i=0;groups_use_ints && i<ngroups;i++)
- if (igroups[i] == 0x42424242)
- groups_use_ints = False;
-
- if (groups_use_ints)
- {
- *p_igroups = igroups;
- *p_groups = (gid_t *)igroups;
- }
- else
- {
- gid_t *groups = (gid_t *)igroups;
- igroups = (int *)malloc(sizeof(int)*ngroups);
- for (i=0;i<ngroups;i++)
- {
- igroups[i] = groups[i];
- }
- *p_igroups = igroups;
- *p_groups = (gid_t *)groups;
- }
- }
- DEBUG(3,("%s is in %d groups\n",user,ngroups));
- for (i=0;i<ngroups;i++)
- DEBUG(3,("%d ",igroups[i]));
- DEBUG(3,("\n"));
- }
- return 0;
-}
/****************************************************************************
make a connection to a service
connection_struct *pcon;
BOOL guest = False;
BOOL force = False;
- static BOOL first_connection = True;
strlower(service);
snum = find_service(service);
if (snum < 0)
{
+ extern int Client;
if (strequal(service,"IPC$"))
{
DEBUG(3,("%s refusing IPC connection\n",timestring()));
return(-3);
}
- DEBUG(0,("%s couldn't find service %s\n",timestring(),service));
+ DEBUG(0,("%s %s (%s) couldn't find service %s\n",timestring(),remote_machine,client_addr(Client),service));
return(-2);
}
if (*user && Get_Pwnam(user,True))
return(make_connection(user,user,password,pwlen,dev,vuid));
- if (validated_username(vuid))
- {
- strcpy(user,validated_username(vuid));
- return(make_connection(user,user,password,pwlen,dev,vuid));
- }
+ if(lp_security() != SEC_SHARE)
+ {
+ if (validated_username(vuid))
+ {
+ strcpy(user,validated_username(vuid));
+ return(make_connection(user,user,password,pwlen,dev,vuid));
+ }
+ }
+ else
+ {
+ /*
+ * Security = share. Try with sesssetup_user as the username.
+ */
+ if(*sesssetup_user)
+ {
+ strcpy(user,sesssetup_user);
+ return(make_connection(user,user,password,pwlen,dev,vuid));
+ }
+ }
}
if (!lp_snum_ok(snum) || !check_access(snum)) {
pcon->dirptr = NULL;
pcon->veto_list = NULL;
pcon->hide_list = NULL;
+ pcon->veto_oplock_list = NULL;
string_set(&pcon->dirpath,"");
string_set(&pcon->user,user);
}
if (lp_status(SNUM(cnum)))
- claim_connection(cnum,"STATUS.",MAXSTATUS,first_connection);
-
- first_connection = False;
+ claim_connection(cnum,"STATUS.",MAXSTATUS,False);
} /* IS_IPC */
pcon->open = True;
smbrun(cmd,NULL,False);
}
- if (!become_user(cnum,pcon->vuid))
+ if (!become_user(&Connections[cnum], cnum,pcon->vuid))
{
DEBUG(0,("Can't become connected user!\n"));
pcon->open = False;
{
set_namearray( &pcon->veto_list, lp_veto_files(SNUM(cnum)));
set_namearray( &pcon->hide_list, lp_hide_files(SNUM(cnum)));
+ set_namearray( &pcon->veto_oplock_list, lp_veto_oplocks(SNUM(cnum)));
}
{
+ extern int Client;
DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) connect to service %s as user %s (uid=%d,gid=%d) (pid %d)\n",
timestring(),
remote_machine,
- client_addr(),
+ client_addr(Client),
lp_servicename(SNUM(cnum)),user,
pcon->uid,
pcon->gid,
return(cnum);
}
+/****************************************************************************
+ Attempt to break an oplock on a file (if oplocked).
+ Returns True if the file was closed as a result of
+ the oplock break, False otherwise.
+ Used as a last ditch attempt to free a space in the
+ file table when we have run out.
+****************************************************************************/
+
+static BOOL attempt_close_oplocked_file(files_struct *fp)
+{
+
+ DEBUG(5,("attempt_close_oplocked_file: checking file %s.\n", fp->name));
+
+ if (fp->open && fp->granted_oplock && !fp->sent_oplock_break) {
+
+ /* Try and break the oplock. */
+ file_fd_struct *fsp = fp->fd_ptr;
+ if(oplock_break( fsp->dev, fsp->inode, &fp->open_time)) {
+ if(!fp->open) /* Did the oplock break close the file ? */
+ return True;
+ }
+ }
+
+ return False;
+}
/****************************************************************************
find first available file slot
****************************************************************************/
int find_free_file(void )
{
- int i;
- /* we start at 1 here for an obscure reason I can't now remember,
- but I think is important :-) */
- for (i=1;i<MAX_OPEN_FILES;i++)
- if (!Files[i].open)
- return(i);
- DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n"));
- return(-1);
+ int i;
+ static int first_file;
+
+ /* we want to give out file handles differently on each new
+ connection because of a common bug in MS clients where they try to
+ reuse a file descriptor from an earlier smb connection. This code
+ increases the chance that the errant client will get an error rather
+ than causing corruption */
+ if (first_file == 0) {
+ first_file = (getpid() ^ (int)time(NULL)) % MAX_OPEN_FILES;
+ if (first_file == 0) first_file = 1;
+ }
+
+ if (first_file >= MAX_OPEN_FILES)
+ first_file = 1;
+
+ for (i=first_file;i<MAX_OPEN_FILES;i++)
+ if (!Files[i].open && !Files[i].reserved) {
+ memset(&Files[i], 0, sizeof(Files[i]));
+ first_file = i+1;
+ Files[i].reserved = True;
+ return(i);
+ }
+
+ /* returning a file handle of 0 is a bad idea - so we start at 1 */
+ for (i=1;i<first_file;i++)
+ if (!Files[i].open && !Files[i].reserved) {
+ memset(&Files[i], 0, sizeof(Files[i]));
+ first_file = i+1;
+ Files[i].reserved = True;
+ return(i);
+ }
+
+ /*
+ * Before we give up, go through the open files
+ * and see if there are any files opened with a
+ * batch oplock. If so break the oplock and then
+ * re-use that entry (if it becomes closed).
+ * This may help as NT/95 clients tend to keep
+ * files batch oplocked for quite a long time
+ * after they have finished with them.
+ */
+ for (i=first_file;i<MAX_OPEN_FILES;i++) {
+ if(attempt_close_oplocked_file( &Files[i])) {
+ memset(&Files[i], 0, sizeof(Files[i]));
+ first_file = i+1;
+ Files[i].reserved = True;
+ return(i);
+ }
+ }
+
+ for (i=1;i<MAX_OPEN_FILES;i++) {
+ if(attempt_close_oplocked_file( &Files[i])) {
+ memset(&Files[i], 0, sizeof(Files[i]));
+ first_file = i+1;
+ Files[i].reserved = True;
+ return(i);
+ }
+ }
+
+ DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n"));
+ return(-1);
}
/****************************************************************************
int secword=0;
BOOL doencrypt = SMBENCRYPT();
time_t t = time(NULL);
- /* We need to save and restore this as it can be destroyed
- if we call another server if security=server
- Thanks to Paul Nelson @ Thursby for pointing this out.
- */
- uint16 mid = SVAL(outbuf, smb_mid);
if (lp_security()>=SEC_USER) secword |= 1;
if (doencrypt) secword |= 2;
Protocol = PROTOCOL_LANMAN1;
- if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
- DEBUG(3,("using password server validation\n"));
- if (doencrypt) set_challenge(smb_buf(outbuf));
- }
-
CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
- SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */
SSVAL(outbuf,smb_vwv2,max_recv);
SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
SSVAL(outbuf,smb_vwv4,1);
int secword=0;
BOOL doencrypt = SMBENCRYPT();
time_t t = time(NULL);
- /* We need to save and restore this as it can be destroyed
- if we call another server if security=server
- Thanks to Paul Nelson @ Thursby for pointing this out.
- */
- uint16 mid = SVAL(outbuf, smb_mid);
+ struct cli_state *cli = NULL;
+ char cryptkey[8];
+ char crypt_len = 0;
+
+ if (lp_security() == SEC_SERVER) {
+ cli = server_cryptkey();
+ }
+
+ if (cli) {
+ DEBUG(3,("using password server validation\n"));
+ doencrypt = ((cli->sec_mode & 2) != 0);
+ }
if (lp_security()>=SEC_USER) secword |= 1;
if (doencrypt) secword |= 2;
- set_message(outbuf,13,doencrypt?8:0,True);
- SSVAL(outbuf,smb_vwv1,secword);
- /* Create a token value and add it to the outgoing packet. */
- if (doencrypt)
- generate_next_challenge(smb_buf(outbuf));
+ if (doencrypt) {
+ crypt_len = 8;
+ if (!cli) {
+ generate_next_challenge(cryptkey);
+ } else {
+ memcpy(cryptkey, cli->cryptkey, 8);
+ set_challenge(cli->cryptkey);
+ }
+ }
+ set_message(outbuf,13,crypt_len,True);
+ SSVAL(outbuf,smb_vwv1,secword);
SIVAL(outbuf,smb_vwv6,getpid());
+ if (doencrypt)
+ memcpy(smb_buf(outbuf), cryptkey, 8);
Protocol = PROTOCOL_LANMAN2;
- if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
- DEBUG(3,("using password server validation\n"));
- if (doencrypt) set_challenge(smb_buf(outbuf));
- }
-
CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
- SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */
SSVAL(outbuf,smb_vwv2,max_recv);
SSVAL(outbuf,smb_vwv3,lp_maxmux());
SSVAL(outbuf,smb_vwv4,1);
int reply_nt1(char *outbuf)
{
/* dual names + lock_and_read + nt SMBs + remote API calls */
- int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ;
+ int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|CAP_RPC_REMOTE_APIS;
/*
other valid capabilities which we may support at some time...
CAP_LARGE_FILES|CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
- CAP_LARGE_FILES|CAP_LARGE_READX|
- CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
+ CAP_LARGE_READX|CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
*/
int secword=0;
BOOL doencrypt = SMBENCRYPT();
time_t t = time(NULL);
int data_len;
- int encrypt_len;
- char challenge_len = 8;
- /* We need to save and restore this as it can be destroyed
- if we call another server if security=server
- Thanks to Paul Nelson @ Thursby for pointing this out.
- */
- uint16 mid = SVAL(outbuf, smb_mid);
+ struct cli_state *cli = NULL;
+ char cryptkey[8];
+ char crypt_len = 0;
- if (lp_readraw() && lp_writeraw())
- {
- capabilities |= CAP_RAW_MODE;
+ if (lp_security() == SEC_SERVER) {
+ cli = server_cryptkey();
}
- if (lp_security()>=SEC_USER) secword |= 1;
+ if (cli) {
+ DEBUG(3,("using password server validation\n"));
+ doencrypt = ((cli->sec_mode & 2) != 0);
+ }
+
+ if (doencrypt) {
+ crypt_len = 8;
+ if (!cli) {
+ generate_next_challenge(cryptkey);
+ } else {
+ memcpy(cryptkey, cli->cryptkey, 8);
+ set_challenge(cli->cryptkey);
+ }
+ }
+
+ if (lp_readraw() && lp_writeraw()) {
+ capabilities |= CAP_RAW_MODE;
+ }
+
+ if (lp_security() >= SEC_USER) secword |= 1;
if (doencrypt) secword |= 2;
/* decide where (if) to put the encryption challenge, and
follow it with the OEM'd domain name
*/
- encrypt_len = doencrypt?challenge_len:0;
-#if UNICODE
- data_len = encrypt_len + 2*(strlen(myworkgroup)+1);
-#else
- data_len = encrypt_len + strlen(myworkgroup) + 1;
-#endif
+ data_len = crypt_len + strlen(myworkgroup) + 1;
set_message(outbuf,17,data_len,True);
-
-#if UNICODE
- /* put the OEM'd domain name */
- PutUniCode(smb_buf(outbuf)+encrypt_len,myworkgroup);
-#else
- strcpy(smb_buf(outbuf)+encrypt_len, myworkgroup);
-#endif
+ strcpy(smb_buf(outbuf)+crypt_len, myworkgroup);
CVAL(outbuf,smb_vwv1) = secword;
- /* Create a token value and add it to the outgoing packet. */
- if (doencrypt)
- {
- generate_next_challenge(smb_buf(outbuf));
-
- /* Tell the nt machine how long the challenge is. */
- SSVALS(outbuf,smb_vwv16+1,challenge_len);
- }
+ SSVALS(outbuf,smb_vwv16+1,crypt_len);
+ if (doencrypt)
+ memcpy(smb_buf(outbuf), cryptkey, 8);
Protocol = PROTOCOL_NT1;
- if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
- DEBUG(3,("using password server validation\n"));
- if (doencrypt) set_challenge(smb_buf(outbuf));
- }
-
- SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */
SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
- SIVAL(outbuf,smb_vwv5+1,0xffff); /* raw size. LOTS! */
+ SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */
SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
put_long_date(outbuf+smb_vwv11+1,t);
/****************************************************************************
reply to a negprot
****************************************************************************/
-static int reply_negprot(char *inbuf,char *outbuf)
+static int reply_negprot(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int outsize = set_message(outbuf,1,0,True);
int Index=0;
int i;
for (i=0;i<MAX_OPEN_FILES;i++)
if( Files[i].cnum == cnum && Files[i].open) {
- close_file(i);
+ close_file(i,False);
}
}
****************************************************************************/
void close_cnum(int cnum, uint16 vuid)
{
+ extern int Client;
DirCacheFlush(SNUM(cnum));
unbecome_user();
DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) closed connection to service %s\n",
timestring(),
- remote_machine,client_addr(),
+ remote_machine,client_addr(Client),
lp_servicename(SNUM(cnum))));
yield_connection(cnum,
dptr_closecnum(cnum);
/* execute any "postexec = " line */
- if (*lp_postexec(SNUM(cnum)) && become_user(cnum,vuid))
+ if (*lp_postexec(SNUM(cnum)) && become_user(&Connections[cnum], cnum,vuid))
{
pstring cmd;
strcpy(cmd,lp_postexec(SNUM(cnum)));
free_namearray(Connections[cnum].veto_list);
free_namearray(Connections[cnum].hide_list);
+ free_namearray(Connections[cnum].veto_oplock_list);
string_set(&Connections[cnum].user,"");
string_set(&Connections[cnum].dirpath,"");
}
-/****************************************************************************
-simple routines to do connection counting
-****************************************************************************/
-BOOL yield_connection(int cnum,char *name,int max_connections)
-{
- struct connect_record crec;
- pstring fname;
- FILE *f;
- int mypid = getpid();
- int i;
-
- DEBUG(3,("Yielding connection to %d %s\n",cnum,name));
-
- if (max_connections <= 0)
- return(True);
-
- bzero(&crec,sizeof(crec));
-
- pstrcpy(fname,lp_lockdir());
- standard_sub(cnum,fname);
- trim_string(fname,"","/");
-
- strcat(fname,"/");
- strcat(fname,name);
- strcat(fname,".LCK");
-
- f = fopen(fname,"r+");
- if (!f)
- {
- DEBUG(2,("Couldn't open lock file %s (%s)\n",fname,strerror(errno)));
- return(False);
- }
-
- fseek(f,0,SEEK_SET);
-
- /* find a free spot */
- for (i=0;i<max_connections;i++)
- {
- if (fread(&crec,sizeof(crec),1,f) != 1)
- {
- DEBUG(2,("Entry not found in lock file %s\n",fname));
- fclose(f);
- return(False);
- }
- if (crec.pid == mypid && crec.cnum == cnum)
- break;
- }
-
- if (crec.pid != mypid || crec.cnum != cnum)
- {
- fclose(f);
- DEBUG(2,("Entry not found in lock file %s\n",fname));
- return(False);
- }
-
- bzero((void *)&crec,sizeof(crec));
-
- /* remove our mark */
- if (fseek(f,i*sizeof(crec),SEEK_SET) != 0 ||
- fwrite(&crec,sizeof(crec),1,f) != 1)
- {
- DEBUG(2,("Couldn't update lock file %s (%s)\n",fname,strerror(errno)));
- fclose(f);
- return(False);
- }
-
- DEBUG(3,("Yield successful\n"));
-
- fclose(f);
- return(True);
-}
-
-
-/****************************************************************************
-simple routines to do connection counting
-****************************************************************************/
-BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear)
-{
- struct connect_record crec;
- pstring fname;
- FILE *f;
- int snum = SNUM(cnum);
- int i,foundi= -1;
- int total_recs;
-
- if (max_connections <= 0)
- return(True);
-
- DEBUG(5,("trying claim %s %s %d\n",lp_lockdir(),name,max_connections));
-
- pstrcpy(fname,lp_lockdir());
- standard_sub(cnum,fname);
- trim_string(fname,"","/");
-
- if (!directory_exist(fname,NULL))
- mkdir(fname,0755);
-
- strcat(fname,"/");
- strcat(fname,name);
- strcat(fname,".LCK");
-
- if (!file_exist(fname,NULL))
- {
- int oldmask = umask(022);
- f = fopen(fname,"w");
- if (f) fclose(f);
- umask(oldmask);
- }
-
- total_recs = file_size(fname) / sizeof(crec);
-
- f = fopen(fname,"r+");
-
- if (!f)
- {
- DEBUG(1,("couldn't open lock file %s\n",fname));
- return(False);
- }
-
- /* find a free spot */
- for (i=0;i<max_connections;i++)
- {
-
- if (i>=total_recs ||
- fseek(f,i*sizeof(crec),SEEK_SET) != 0 ||
- fread(&crec,sizeof(crec),1,f) != 1)
- {
- if (foundi < 0) foundi = i;
- break;
- }
-
- if (Clear && crec.pid && !process_exists(crec.pid))
- {
- fseek(f,i*sizeof(crec),SEEK_SET);
- bzero((void *)&crec,sizeof(crec));
- fwrite(&crec,sizeof(crec),1,f);
- if (foundi < 0) foundi = i;
- continue;
- }
- if (foundi < 0 && (!crec.pid || !process_exists(crec.pid)))
- {
- foundi=i;
- if (!Clear) break;
- }
- }
-
- if (foundi < 0)
- {
- DEBUG(3,("no free locks in %s\n",fname));
- fclose(f);
- return(False);
- }
-
- /* fill in the crec */
- bzero((void *)&crec,sizeof(crec));
- crec.magic = 0x280267;
- crec.pid = getpid();
- crec.cnum = cnum;
- crec.uid = Connections[cnum].uid;
- crec.gid = Connections[cnum].gid;
- StrnCpy(crec.name,lp_servicename(snum),sizeof(crec.name)-1);
- crec.start = time(NULL);
-
- StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1);
- StrnCpy(crec.addr,client_addr(),sizeof(crec.addr)-1);
-
- /* make our mark */
- if (fseek(f,foundi*sizeof(crec),SEEK_SET) != 0 ||
- fwrite(&crec,sizeof(crec),1,f) != 1)
- {
- fclose(f);
- return(False);
- }
-
- fclose(f);
- return(True);
-}
#if DUMP_CORE
/*******************************************************************
#endif
}
-#ifdef FAST_SHARE_MODES
- stop_share_mode_mgmt();
-#endif /* FAST_SHARE_MODES */
+ locking_end();
DEBUG(3,("%s Server exit (%s)\n",timestring(),reason?reason:""));
exit(0);
case 'S' : string_sub(p,"%S",lp_servicename(Connections[cnum].service)); break;
case 'g' : string_sub(p,"%g",gidtoname(Connections[cnum].gid)); break;
case 'u' : string_sub(p,"%u",Connections[cnum].user); break;
+ /*
+ * Patch from jkf@soton.ac.uk
+ * Left the %N (NIS server name) in standard_sub_basic as it
+ * is a feature for logon servers, hence uses the username.
+ * The %p (NIS server path) code is here as it is used
+ * instead of the default "path =" string in [homes] and so
+ * needs the service name, not the username.
+ */
+ case 'p' : string_sub(p,"%p",automount_path(lp_servicename(Connections[cnum].service))); break;
case '\0' : p++; break; /* don't run off the end of the string */
default : p+=2; break;
}
#define TIME_INIT (1<<2)
#define CAN_IPC (1<<3)
#define AS_GUEST (1<<5)
-
+#define QUEUE_IN_OPLOCK (1<<6)
/*
define a list of possible SMB messages and their corresponding
{
int code;
char *name;
- int (*fn)();
+ int (*fn)(char *, char *, int, int);
int flags;
#if PROFILING
unsigned long time;
{SMBsetatr,"SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
{SMBchkpth,"SMBchkpth",reply_chkpth,AS_USER},
{SMBsearch,"SMBsearch",reply_search,AS_USER},
- {SMBopen,"SMBopen",reply_open,AS_USER},
+ {SMBopen,"SMBopen",reply_open,AS_USER | QUEUE_IN_OPLOCK },
/* note that SMBmknew and SMBcreate are deliberately overloaded */
{SMBcreate,"SMBcreate",reply_mknew,AS_USER},
{SMBmknew,"SMBmknew",reply_mknew,AS_USER},
- {SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE},
+ {SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
{SMBread,"SMBread",reply_read,AS_USER},
{SMBwrite,"SMBwrite",reply_write,AS_USER},
{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},
- {SMBmv,"SMBmv",reply_mv,AS_USER | NEED_WRITE},
+ {SMBmv,"SMBmv",reply_mv,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
/* this is a Pathworks specific call, allowing the
changing of the root path */
{SMBlseek,"SMBlseek",reply_lseek,AS_USER},
{SMBflush,"SMBflush",reply_flush,AS_USER},
- {SMBctemp,"SMBctemp",reply_ctemp,AS_USER},
- {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER},
+ {SMBctemp,"SMBctemp",reply_ctemp,AS_USER | QUEUE_IN_OPLOCK },
+ {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER | QUEUE_IN_OPLOCK },
{SMBsplclose,"SMBsplclose",reply_printclose,AS_USER},
{SMBsplretq,"SMBsplretq",reply_printqueue,AS_USER|AS_GUEST},
{SMBsplwr,"SMBsplwr",reply_printwrite,AS_USER},
{SMBtrans,"SMBtrans",reply_trans,AS_USER | CAN_IPC},
{SMBtranss,"SMBtranss",NULL,AS_USER | CAN_IPC},
{SMBioctls,"SMBioctls",NULL,AS_USER},
- {SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE},
- {SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE},
+ {SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
+ {SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
- {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER | CAN_IPC},
- {SMBreadX,"SMBreadX",reply_read_and_X,AS_USER},
+ {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},
{SMBlockingX,"SMBlockingX",reply_lockingX,AS_USER},
/* LANMAN2.0 PROTOCOL FOLLOWS */
{SMBfindnclose, "SMBfindnclose", reply_findnclose, AS_USER},
{SMBfindclose, "SMBfindclose", reply_findclose,AS_USER},
- {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER},
+ {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER },
{SMBtranss2, "SMBtranss2", reply_transs2, AS_USER},
/* messaging routines */
else
{
DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,pid));
+
+ if(global_oplock_break && (smb_messages[match].flags & QUEUE_IN_OPLOCK))
+ {
+ /*
+ * Queue this message as we are the process of an oplock break.
+ */
+
+ DEBUG(2,("%s: switch_message: queueing message due to being in oplock break state.\n",
+ timestring() ));
+
+ push_smb_message( inbuf, size);
+ return -1;
+ }
+
if (smb_messages[match].fn)
{
int cnum = SVAL(inbuf,smb_tid);
int flags = smb_messages[match].flags;
- uint16 session_tag = SVAL(inbuf,smb_uid);
+ /* In share mode security we must ignore the vuid. */
+ uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid);
+ /* Ensure this value is replaced in the incoming packet. */
+ SSVAL(inbuf,smb_uid,session_tag);
/* does this protocol need to be run as root? */
if (!(flags & AS_USER))
unbecome_user();
/* does this protocol need to be run as the connected user? */
- if ((flags & AS_USER) && !become_user(cnum,session_tag)) {
+ if ((flags & AS_USER) && !become_user(&Connections[cnum], cnum,session_tag)) {
if (flags & AS_GUEST)
flags &= ~AS_USER;
else
CVAL(outbuf2,smb_com) = CVAL(inbuf2,smb_com);
memcpy(outbuf2+4,inbuf2+4,4);
- CVAL(outbuf2,smb_rcls) = SUCCESS;
+ CVAL(outbuf2,smb_rcls) = SMB_SUCCESS;
CVAL(outbuf2,smb_reh) = 0;
CVAL(outbuf2,smb_flg) = 0x80 | (CVAL(inbuf2,smb_flg) & 0x8); /* bit 7 set
means a reply */
SSVAL(outbuf2,smb_flg2,1); /* say we support long filenames */
- SSVAL(outbuf2,smb_err,SUCCESS);
+ SSVAL(outbuf2,smb_err,SMB_SUCCESS);
SSVAL(outbuf2,smb_tid,SVAL(inbuf2,smb_tid));
SSVAL(outbuf2,smb_pid,SVAL(inbuf2,smb_pid));
SSVAL(outbuf2,smb_uid,SVAL(inbuf2,smb_uid));
chain_size = 0;
chain_fnum = -1;
+ reset_chain_pnum();
bzero(outbuf,smb_size);
set_message(outbuf,0,0,True);
memcpy(outbuf+4,inbuf+4,4);
- CVAL(outbuf,smb_rcls) = SUCCESS;
+ CVAL(outbuf,smb_rcls) = SMB_SUCCESS;
CVAL(outbuf,smb_reh) = 0;
CVAL(outbuf,smb_flg) = 0x80 | (CVAL(inbuf,smb_flg) & 0x8); /* bit 7 set
means a reply */
SSVAL(outbuf,smb_flg2,1); /* say we support long filenames */
- SSVAL(outbuf,smb_err,SUCCESS);
+ SSVAL(outbuf,smb_err,SMB_SUCCESS);
SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));
}
#endif
+ /* re-initialise the timezone */
+ TimeInit();
+
while (True)
{
int deadtime = lp_deadtime()*60;
if (deadtime <= 0)
deadtime = DEFAULT_SMBD_TIMEOUT;
+#if USE_READ_PREDICTION
if (lp_readprediction())
do_read_prediction();
+#endif
errno = 0;
if (keepalive && (counter-last_keepalive)>keepalive)
{
- extern int password_client;
- if (!send_keepalive(Client))
- {
- DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
- return;
- }
- /* also send a keepalive to the password server if its still
- connected */
- if (password_client != -1)
- send_keepalive(password_client);
- last_keepalive = counter;
+ struct cli_state *cli = server_client();
+ if (!send_keepalive(Client)) {
+ DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
+ return;
+ }
+ /* also send a keepalive to the password server if its still
+ connected */
+ if (cli && cli->initialised)
+ send_keepalive(cli->fd);
+ last_keepalive = counter;
}
/* check for connection timeouts */
{
Files[i].open = False;
string_init(&Files[i].name,"");
-
}
for (i=0;i<MAX_OPEN_FILES;i++)
fd_ptr->real_open_flags = -1;
}
+ /* for RPC pipes */
+ init_rpc_pipe_hnd();
+
+ /* for LSA handles */
+ init_lsa_policy_hnd();
+
init_dptrs();
}
int port = SMB_PORT;
int opt;
extern char *optarg;
- char pidFile[100] = { 0 };
#ifdef NEED_AUTH_PARAMETERS
set_auth_parameters(argc,argv);
strcpy(debugf,SMBLOGFILE);
+ strcpy(remote_machine, "smb");
+
setup_logging(argv[0],False);
charset_initialise();
- /* make absolutely sure we run as root - to handle cases whre people
+ /* make absolutely sure we run as root - to handle cases where people
are crazy enough to have it setuid */
#ifdef USE_SETRES
setresuid(0,0,0);
seteuid(0);
#endif
- fault_setup(exit_server);
+ fault_setup((void (*)(void *))exit_server);
signal(SIGTERM , SIGNAL_CAST dflt_sig);
/* we want total control over the permissions on created files,
while ((opt = getopt(argc, argv, "O:i:l:s:d:Dp:hPaf:")) != EOF)
switch (opt)
{
- case 'f':
- strncpy(pidFile, optarg, sizeof(pidFile));
- break;
case 'O':
strcpy(user_socket_options,optarg);
break;
{
struct rlimit rlp;
getrlimit(RLIMIT_NOFILE, &rlp);
- rlp.rlim_cur = (MAX_OPEN_FILES>rlp.rlim_max)? rlp.rlim_max:MAX_OPEN_FILES;
+ /*
+ * Set the fd limit to be MAX_OPEN_FILES + 10 to account for the
+ * extra fd we need to read directories, as well as the log files
+ * and standard handles etc.
+ */
+ rlp.rlim_cur = (MAX_OPEN_FILES+10>rlp.rlim_max)? rlp.rlim_max:MAX_OPEN_FILES+10;
setrlimit(RLIMIT_NOFILE, &rlp);
getrlimit(RLIMIT_NOFILE, &rlp);
DEBUG(3,("Maximum number of open files per session is %d\n",rlp.rlim_cur));
#ifndef NO_SIGNAL_TEST
signal(SIGHUP,SIGNAL_CAST sig_hup);
#endif
-
+
+ /* Setup the signals that allow the debug log level
+ to by dynamically changed. */
+
+ /* 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)
+ signal( SIGUSR1, SIGNAL_CAST sig_usr1 );
+#endif /* SIGUSR1 */
+
+#if defined(SIGUSR2)
+ signal( SIGUSR2, SIGNAL_CAST sig_usr2 );
+#endif /* SIGUSR2 */
+#endif /* MEM_MAN */
+
DEBUG(3,("%s loaded services\n",timestring()));
if (!is_daemon && !is_a_socket(0))
become_daemon();
}
- if (*pidFile)
- {
- int fd;
- char buf[20];
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
- if ((fd = open(pidFile,
-#ifdef O_NONBLOCK
- O_NONBLOCK |
-#endif
- O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
- {
- DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
- exit(1);
- }
- if(fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False)
- {
- DEBUG(0,("ERROR: smbd is already running\n"));
- exit(1);
- }
- sprintf(buf, "%u\n", (unsigned int) getpid());
- if (write(fd, buf, strlen(buf)) < 0)
- {
- DEBUG(0,("ERROR: can't write to %s: %s\n", pidFile, strerror(errno)));
- exit(1);
- }
- /* Leave pid file open & locked for the duration... */
- }
+ if (is_daemon) {
+ pidfile_create("smbd");
+ }
if (!open_sockets(is_daemon,port))
exit(1);
-#ifdef FAST_SHARE_MODES
- if (!start_share_mode_mgmt())
+ if (!locking_init(0))
exit(1);
-#endif /* FAST_SHARE_MODES */
/* possibly reload the services file. */
reload_services(True);