X-Git-Url: http://git.samba.org/?p=samba.git;a=blobdiff_plain;f=source3%2Fsmbd%2Fserver.c;h=29a0d462f3d4df82eb143fd48b2d2cd8f4480f0e;hp=93042e119b000762578d06e53239976b863facab;hb=10f844c988cf426d2309d5bd73bedec182dd03d3;hpb=71d648cdb431ecf984196a7e480208a94fcdf390 diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 93042e119b0..29a0d462f3d 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -452,8 +452,20 @@ static BOOL scan_directory(char *path, char *name,int cnum,BOOL docache) return(True); } +#if 0 + /* + * This code I believe is incorrect - and commenting it out + * is the correct fix for the bug mentioned below in the + * comment 'name2 here was changed to dname - since 1.9.16p2 - not sure of reason (jra)'. + * 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); +#endif /* open the directory */ if (!(cur_dir = OpenDir(cnum, path, True))) @@ -1139,6 +1151,7 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct 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; @@ -1148,12 +1161,32 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct 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 */ @@ -1191,8 +1224,6 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct */ 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--; @@ -1326,6 +1357,7 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct 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; @@ -1473,6 +1505,11 @@ void close_file(int fnum, BOOL normal_close) 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)); @@ -1680,9 +1717,9 @@ int check_share_mode( share_mode_entry *share, int deny_mode, char *fname, (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; } @@ -1928,9 +1965,11 @@ dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode)); 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; @@ -2509,7 +2548,7 @@ max can be %d\n", num_interfaces, FD_SETSIZE)); return True; } close(Client); /* The parent doesn't need this socket */ -#endif /NO_FORK_DEBUG */ +#endif /* NO_FORK_DEBUG */ } /* end for num */ } /* end while 1 */ } /* end if is_daemon */ @@ -2575,6 +2614,8 @@ static void process_smb(char *inbuf, char *outbuf) if (msg_type == 0) show_msg(inbuf); + else if(msg_type == 0x85) + return; /* Keepalive packet. */ nread = construct_reply(inbuf,outbuf,nread,max_send); @@ -2765,24 +2806,8 @@ BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval) 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 @@ -2791,19 +2816,20 @@ global_oplocks_open = %d\n", dev, inode, global_oplocks_open)); { 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; } @@ -2818,15 +2844,42 @@ allowing break to succeed.\n", dev, inode, fnum)); 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); @@ -2844,6 +2897,10 @@ Allowing break to succeed regardless.\n", fsp->name, fnum, dev, inode)); 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. */ @@ -2862,49 +2919,54 @@ Allowing break to succeed regardless.\n", fsp->name, fnum, dev, inode)); */ 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; - /* * 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"); @@ -2916,10 +2978,10 @@ inode = %x).\n", fsp->name, fnum, dev, inode)); 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) { @@ -2928,8 +2990,8 @@ inode = %x).\n", fsp->name, fnum, dev, inode)); 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; } @@ -2978,15 +3040,15 @@ should be %d\n", pid, share_entry->op_port, oplock_port)); 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; } @@ -2994,7 +3056,7 @@ to pid %d on port %d for dev = %x, inode = %x. Error was %s\n", /* * 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. */ @@ -3006,15 +3068,25 @@ to pid %d on port %d for dev = %x, inode = %x. Error was %s\n", char *reply_msg_start; if(receive_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply), - OPLOCK_BREAK_TIMEOUT * 1000) == False) + (OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) * 1000) == 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; } @@ -3044,7 +3116,8 @@ pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", share_entry->pid 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; } @@ -3054,9 +3127,9 @@ pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", share_entry->pid &op_break_msg[OPLOCK_BREAK_PID_OFFSET], OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) != 0)) { - DEBUG(3,("request_oplock_break: received other message whilst awaiting \ + DEBUG(3,("%s 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)); + timestring(), share_entry->pid, share_entry->op_port, dev, inode)); if(push_local_message(op_break_reply, sizeof(op_break_reply)) == False) return False; continue; @@ -3065,11 +3138,44 @@ oplock break response from pid %d on port %d for dev = %x, inode = %x.\n", break; } - 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 ****************************************************************************/ @@ -3125,7 +3231,7 @@ BOOL reload_services(BOOL test) } } - create_mangled_stack(lp_mangledstack()); + reset_mangled_stack( lp_mangledstack() ); /* this forces service parameters to be flushed */ become_service(-1,True); @@ -3378,6 +3484,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de 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); @@ -3528,6 +3635,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de { 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))); } { @@ -3550,14 +3658,35 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de ****************************************************************************/ 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;ireal_open_flags = -1; } + /* for RPC pipes */ + init_rpc_pipe_hnd(); + +#ifdef NTDOMAIN + /* for LSA handles */ + init_lsa_policy_hnd(); +#endif + init_dptrs(); } @@ -4959,7 +5102,9 @@ static void usage(char *pname) int port = SMB_PORT; int opt; extern char *optarg; - char pidFile[100] = { 0 }; + char pidFile[100]; + + *pidFile = '\0'; #ifdef NEED_AUTH_PARAMETERS set_auth_parameters(argc,argv); @@ -5099,7 +5244,18 @@ static void usage(char *pname) #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 defined(SIGUSR1) + signal( SIGUSR1, SIGNAL_CAST sig_usr1 ); +#endif /* SIGUSR1 */ + +#if defined(SIGUSR2) + signal( SIGUSR2, SIGNAL_CAST sig_usr2 ); +#endif /* SIGUSR2 */ + DEBUG(3,("%s loaded services\n",timestring())); if (!is_daemon && !is_a_socket(0)) @@ -5114,6 +5270,10 @@ static void usage(char *pname) become_daemon(); } + if (!directory_exist(lp_lockdir(), NULL)) { + mkdir(lp_lockdir(), 0755); + } + if (*pidFile) { int fd;