X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source3%2Fsmbd%2Fserver.c;h=51710b7b77959517bff320749b797f5ae2ba305c;hb=3ab97ebe6db1a5a4a0573c7c8482c94876bbce9a;hp=b8e3cba61c2eb03efb5707a447f28e951733dae1;hpb=81e398963dbaed9c6661c336fe98329098576b94;p=kai%2Fsamba.git diff --git a/source3/smbd/server.c b/source3/smbd/server.c index b8e3cba61c2..51710b7b779 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. Main SMB server routines - Copyright (C) Andrew Tridgell 1992-1995 + Copyright (C) Andrew Tridgell 1992-1997 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 @@ -20,20 +20,19 @@ */ #include "includes.h" -#include "loadparm.h" -#include "pcap.h" #include "trans2.h" -#include "reply.h" pstring servicesf = CONFIGFILE; extern pstring debugf; extern pstring sesssetup_user; +extern fstring myworkgroup; char *InBuffer = NULL; char *OutBuffer = NULL; char *last_inbuf = NULL; -BOOL share_mode_pending = False; +int am_parent = 1; +int atexit_set = 0; /* the last message the was processed */ int last_message = -1; @@ -51,16 +50,33 @@ extern BOOL short_case_preserve; extern BOOL case_mangle; extern time_t smb_last_time; +extern int smb_read_error; + extern pstring user_socket_options; connection_struct Connections[MAX_CONNECTIONS]; files_struct Files[MAX_OPEN_FILES]; -extern int Protocol; +/* + * Indirection for file fd's. Needed as POSIX locking + * is based on file/process, not fd/process. + */ +file_fd_struct FileFd[MAX_OPEN_FILES]; +int max_file_fd_used = 0; -int maxxmit = BUFFER_SIZE; +extern int Protocol; -int chain_size = 0; +/* + * Size of data we can send to client. Set + * by the client for all protocols above CORE. + * Set by us for CORE protocol. + */ +int max_send = BUFFER_SIZE; +/* + * Size of the data we can receive. Set by us. + * Can be modified by the max xmit parameter. + */ +int max_recv = BUFFER_SIZE; /* a fnum to use when chaining */ int chain_fnum = -1; @@ -70,6 +86,7 @@ static int num_connections_open = 0; extern fstring remote_machine; +pstring OriginalDir; /* these can be set by some functions to override the error codes */ int unix_ERR_class=SUCCESS; @@ -79,16 +96,9 @@ int unix_ERR_code=0; extern int extra_time_offset; extern pstring myhostname; -extern struct in_addr myip; - static int find_free_connection(int hash); -#ifdef SMB_PASSWD -extern void generate_next_challenge(char *challenge); -extern void set_challenge(char *challenge); -#endif - /* for readability... */ #define IS_DOS_READONLY(test_mode) (((test_mode) & aRONLY) != 0) #define IS_DOS_DIR(test_mode) (((test_mode) & aDIR) != 0) @@ -96,7 +106,21 @@ extern void set_challenge(char *challenge); #define IS_DOS_SYSTEM(test_mode) (((test_mode) & aSYSTEM) != 0) #define IS_DOS_HIDDEN(test_mode) (((test_mode) & aHIDDEN) != 0) - +/**************************************************************************** + when exiting, take the whole family +****************************************************************************/ +void *dflt_sig(void) +{ + exit_server("caught signal"); + return 0; /* Keep -Wall happy :-) */ +} +/**************************************************************************** + Send a SIGTERM to our process group. +*****************************************************************************/ +void killkids(void) +{ + if(am_parent) kill(0,SIGTERM); +} /**************************************************************************** change a dos mode to a unix mode @@ -116,19 +140,21 @@ mode_t unix_mode(int cnum,int dosmode) if ( !IS_DOS_READONLY(dosmode) ) result |= (S_IWUSR | S_IWGRP | S_IWOTH); - if (IS_DOS_DIR(dosmode)) + if (IS_DOS_DIR(dosmode)) { result |= (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR); - - if (MAP_ARCHIVE(cnum) && IS_DOS_ARCHIVE(dosmode)) - result |= S_IXUSR; + result &= (lp_dir_mode(SNUM(cnum)) | 0700); + } else { + if (MAP_ARCHIVE(cnum) && IS_DOS_ARCHIVE(dosmode)) + result |= S_IXUSR; - if (MAP_SYSTEM(cnum) && IS_DOS_SYSTEM(dosmode)) - result |= S_IXGRP; + if (MAP_SYSTEM(cnum) && IS_DOS_SYSTEM(dosmode)) + result |= S_IXGRP; - if (MAP_HIDDEN(cnum) && IS_DOS_HIDDEN(dosmode)) - result |= S_IXOTH; + if (MAP_HIDDEN(cnum) && IS_DOS_HIDDEN(dosmode)) + result |= S_IXOTH; - result &= CREATE_MODE(cnum); + result &= CREATE_MODE(cnum); + } return(result); } @@ -139,31 +165,20 @@ mode_t unix_mode(int cnum,int dosmode) int dos_mode(int cnum,char *path,struct stat *sbuf) { int result = 0; + extern struct current_user current_user; -#if OLD_DOS_MODE - if (!CAN_WRITE(cnum) || !((sbuf->st_mode & S_IWOTH) || - Connections[cnum].admin_user || - ((sbuf->st_mode & S_IWUSR) && - Connections[cnum].uid==sbuf->st_uid) || - ((sbuf->st_mode & S_IWGRP) && - in_group(sbuf->st_gid,Connections[cnum].gid, - Connections[cnum].ngroups, - Connections[cnum].igroups)))) - result |= aRONLY; -#else if (CAN_WRITE(cnum) && !lp_alternate_permissions(SNUM(cnum))) { if (!((sbuf->st_mode & S_IWOTH) || Connections[cnum].admin_user || - ((sbuf->st_mode & S_IWUSR) && Connections[cnum].uid==sbuf->st_uid) || + ((sbuf->st_mode & S_IWUSR) && current_user.uid==sbuf->st_uid) || ((sbuf->st_mode & S_IWGRP) && - in_group(sbuf->st_gid,Connections[cnum].gid, - Connections[cnum].ngroups,Connections[cnum].igroups)))) + in_group(sbuf->st_gid,current_user.gid, + current_user.ngroups,current_user.igroups)))) result |= aRONLY; } else { if ((sbuf->st_mode & S_IWUSR) == 0) result |= aRONLY; } -#endif if ((sbuf->st_mode & S_IXUSR) != 0) result |= aARCH; @@ -249,7 +264,7 @@ int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st) unixmode |= tmp; } - return(chmod(fname,unixmode)); + return(sys_chmod(fname,unixmode)); } @@ -297,7 +312,7 @@ static BOOL mangled_equal(char *name1, char *name2) { pstring tmpname; - if (is_8_3(name2)) + if (is_8_3(name2, True)) return(False); strcpy(tmpname,name2); @@ -375,31 +390,49 @@ for this service. The function will return False if some part of the name except for the last part cannot be resolved + +If the saved_last_component != 0, then the unmodified last component +of the pathname is returned there. This is used in an exceptional +case in reply_mv (so far). If saved_last_component == 0 then nothing +is returned there. ****************************************************************************/ -BOOL unix_convert(char *name,int cnum) +BOOL unix_convert(char *name,int cnum,pstring saved_last_component) { struct stat st; char *start, *end; pstring dirpath; *dirpath = 0; + if(saved_last_component) + *saved_last_component = 0; /* convert to basic unix format - removing \ chars and cleaning it up */ unix_format(name); unix_clean_name(name); - if (!case_sensitive && - (!case_preserve || (is_8_3(name) && !short_case_preserve))) - strnorm(name); - /* names must be relative to the root of the service - trim any leading /. also trim trailing /'s */ trim_string(name,"/","/"); + /* + * Ensure saved_last_component is valid even if file exists. + */ + if(saved_last_component) { + end = strrchr(name, '/'); + if(end) + strcpy(saved_last_component, end + 1); + else + strcpy(saved_last_component, name); + } + + if (!case_sensitive && + (!case_preserve || (is_8_3(name, False) && !short_case_preserve))) + strnorm(name); + /* check if it's a printer file */ if (Connections[cnum].printer) { - if ((! *name) || strchr(name,'/') || !is_8_3(name)) + if ((! *name) || strchr(name,'/') || !is_8_3(name, True)) { char *s; fstring name2; @@ -439,7 +472,10 @@ BOOL unix_convert(char *name,int cnum) end = strchr(start, '/'); /* chop the name at this point */ - if (end) *end = 0; + if (end) *end = 0; + + if(saved_last_component != 0) + strcpy(saved_last_component, end ? end + 1 : start); /* check if the name exists up to this point */ if (sys_stat(name, &st) == 0) @@ -464,7 +500,6 @@ BOOL unix_convert(char *name,int cnum) later */ if (end) strcpy(rest,end+1); - /* try to find this part of the path in the directory */ if (strchr(start,'?') || strchr(start,'*') || !scan_directory(dirpath, start, SNUM(cnum), end?True:False)) @@ -584,11 +619,11 @@ int disk_free(char *path,int *bsize,int *dfree,int *dsize) pstring syscmd; pstring outfile; - sprintf(outfile,"/tmp/dfree.smb.%d",(int)getpid()); + sprintf(outfile,"%s/dfree.smb.%d",tmpdir(),(int)getpid()); sprintf(syscmd,"%s %s",df_command,path); standard_sub_basic(syscmd); - ret = smbrun(syscmd,outfile); + ret = smbrun(syscmd,outfile,False); DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret)); { @@ -705,6 +740,12 @@ BOOL check_name(char *name,int cnum) errno = 0; + if( is_vetoed_path(name)) + { + DEBUG(5,("file path name %s vetoed\n",name)); + return(0); + } + ret = reduce_name(name,Connections[cnum].connectpath,lp_widelinks(SNUM(cnum))); if (!ret) DEBUG(5,("check_name on %s failed\n",name)); @@ -729,16 +770,182 @@ static void check_for_pipe(char *fname) } } +/**************************************************************************** +fd support routines - attempt to do a sys_open +****************************************************************************/ + +int fd_attempt_open(char *fname, int flags, int mode) +{ + int fd = sys_open(fname,flags,mode); + + /* Fix for files ending in '.' */ + if((fd == -1) && (errno == ENOENT) && + (strchr(fname,'.')==NULL)) + { + strcat(fname,"."); + fd = sys_open(fname,flags,mode); + } + +#if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF)) + if ((fd == -1) && (errno == ENAMETOOLONG)) + { + int max_len; + char *p = strrchr(fname, '/'); + + if (p == fname) /* name is "/xxx" */ + { + max_len = pathconf("/", _PC_NAME_MAX); + p++; + } + else if ((p == NULL) || (p == fname)) + { + p = fname; + max_len = pathconf(".", _PC_NAME_MAX); + } + else + { + *p = '\0'; + max_len = pathconf(fname, _PC_NAME_MAX); + *p = '/'; + p++; + } + if (strlen(p) > max_len) + { + char tmp = p[max_len]; + + p[max_len] = '\0'; + if ((fd = sys_open(fname,flags,mode)) == -1) + p[max_len] = tmp; + } + } +#endif + return fd; +} + +/**************************************************************************** +fd support routines - attempt to find an already open file by dev +and inode - increments the ref_count of the returned file_fd_struct *. +****************************************************************************/ +file_fd_struct *fd_get_already_open(struct stat *sbuf) +{ + int i; + file_fd_struct *fd_ptr; + + if(sbuf == 0) + return 0; + + for(i = 0; i <= max_file_fd_used; i++) { + fd_ptr = &FileFd[i]; + if((fd_ptr->ref_count > 0) && + (((uint32)sbuf->st_dev) == fd_ptr->dev) && + (((uint32)sbuf->st_ino) == fd_ptr->inode)) { + fd_ptr->ref_count++; + DEBUG(3, + ("Re-used file_fd_struct %d, dev = %x, inode = %x, ref_count = %d\n", + i, fd_ptr->dev, fd_ptr->inode, fd_ptr->ref_count)); + return fd_ptr; + } + } + return 0; +} + +/**************************************************************************** +fd support routines - attempt to find a empty slot in the FileFd array. +Increments the ref_count of the returned entry. +****************************************************************************/ +file_fd_struct *fd_get_new() +{ + int i; + file_fd_struct *fd_ptr; + + for(i = 0; i < MAX_OPEN_FILES; i++) { + fd_ptr = &FileFd[i]; + if(fd_ptr->ref_count == 0) { + fd_ptr->dev = (uint32)-1; + fd_ptr->inode = (uint32)-1; + fd_ptr->fd = -1; + fd_ptr->fd_readonly = -1; + fd_ptr->fd_writeonly = -1; + fd_ptr->real_open_flags = -1; + fd_ptr->ref_count++; + /* Increment max used counter if neccessary, cuts down + on search time when re-using */ + if(i > max_file_fd_used) + max_file_fd_used = i; + DEBUG(3,("Allocated new file_fd_struct %d, dev = %x, inode = %x\n", + i, fd_ptr->dev, fd_ptr->inode)); + return fd_ptr; + } + } + DEBUG(1,("ERROR! Out of file_fd structures - perhaps increase MAX_OPEN_FILES?\ +n")); + return 0; +} + +/**************************************************************************** +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. +****************************************************************************/ + +void fd_attempt_reopen(char *fname, int mode, file_fd_struct *fd_ptr) +{ + int fd = sys_open( fname, O_RDWR, mode); + + if(fd == -1) + return; + + if(fd_ptr->real_open_flags == O_RDONLY) + fd_ptr->fd_readonly = fd_ptr->fd; + if(fd_ptr->real_open_flags == O_WRONLY) + fd_ptr->fd_writeonly = fd_ptr->fd; + + fd_ptr->fd = fd; + fd_ptr->real_open_flags = O_RDWR; +} + +/**************************************************************************** +fd support routines - attempt to close the file referenced by this fd. +Decrements the ref_count and returns it. +****************************************************************************/ +int fd_attempt_close(file_fd_struct *fd_ptr) +{ + DEBUG(3,("fd_attempt_close on file_fd_struct %d, fd = %d, dev = %x, inode = %x, open_flags = %d, ref_count = %d.\n", + fd_ptr - &FileFd[0], + fd_ptr->fd, fd_ptr->dev, fd_ptr->inode, + fd_ptr->real_open_flags, + fd_ptr->ref_count)); + if(fd_ptr->ref_count > 0) { + fd_ptr->ref_count--; + if(fd_ptr->ref_count == 0) { + if(fd_ptr->fd != -1) + close(fd_ptr->fd); + if(fd_ptr->fd_readonly != -1) + close(fd_ptr->fd_readonly); + if(fd_ptr->fd_writeonly != -1) + close(fd_ptr->fd_writeonly); + fd_ptr->fd = -1; + fd_ptr->fd_readonly = -1; + fd_ptr->fd_writeonly = -1; + fd_ptr->real_open_flags = -1; + fd_ptr->dev = (uint32)-1; + fd_ptr->inode = (uint32)-1; + } + } + return fd_ptr->ref_count; +} /**************************************************************************** open a file ****************************************************************************/ -void open_file(int fnum,int cnum,char *fname1,int flags,int mode) +static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct stat *sbuf) { + extern struct current_user current_user; pstring fname; + struct stat statbuf; + file_fd_struct *fd_ptr; Files[fnum].open = False; - Files[fnum].fd = -1; + Files[fnum].fd_ptr = 0; errno = EPERM; strcpy(fname,fname1); @@ -768,10 +975,104 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode) sys_unlink(fname); #endif + /* + * Ensure we have a valid struct stat so we can search the + * open fd table. + */ + if(sbuf == 0) { + if(stat(fname, &statbuf) < 0) { + if(errno != ENOENT) { + DEBUG(3,("Error doing stat on file %s (%s)\n", + fname,strerror(errno))); + + check_for_pipe(fname); + return; + } + sbuf = 0; + } else { + sbuf = &statbuf; + } + } + + /* + * Check to see if we have this file already + * open. If we do, just use the already open fd and increment the + * reference count (fd_get_already_open increments the ref_count). + */ + 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--; + errno = EEXIST; + return; + } - Files[fnum].fd = sys_open(fname,flags,mode); + /* + * If not opened O_RDWR try + * and do that here - a chmod may have been done + * between the last open and now. + */ + if(fd_ptr->real_open_flags != O_RDWR) + fd_attempt_reopen(fname, mode, fd_ptr); + + /* + * Ensure that if we wanted write access + * it has been opened for write, and if we wanted read it + * was open for read. + */ + if(((accmode == O_WRONLY) && (fd_ptr->real_open_flags == O_RDONLY)) || + ((accmode == O_RDONLY) && (fd_ptr->real_open_flags == O_WRONLY)) || + ((accmode == O_RDWR) && (fd_ptr->real_open_flags != O_RDWR))) { + DEBUG(3,("Error opening (already open for flags=%d) file %s (%s) (flags=%d)\n", + fd_ptr->real_open_flags, fname,strerror(EACCES),flags)); + check_for_pipe(fname); + fd_ptr->ref_count--; + return; + } + + } else { + int open_flags; + /* We need to allocate a new file_fd_struct (this increments the + ref_count). */ + if((fd_ptr = fd_get_new()) == 0) + return; + /* + * Whatever the requested flags, attempt read/write access, + * as we don't know what flags future file opens may require. + * If this fails, try again with the required flags. + * Even if we open read/write when only read access was + * requested the setting of the can_write flag in + * the file_struct will protect us from errant + * write requests. We never need to worry about O_APPEND + * as this is not set anywhere in Samba. + */ + fd_ptr->real_open_flags = O_RDWR; + /* Set the flags as needed without the read/write modes. */ + open_flags = flags & ~(O_RDWR|O_WRONLY|O_RDONLY); + fd_ptr->fd = fd_attempt_open(fname, open_flags|O_RDWR, mode); + /* + * On some systems opening a file for R/W access on a read only + * filesystems sets errno to EROFS. + */ +#ifdef EROFS + if((fd_ptr->fd == -1) && ((errno == EACCES) || (errno == EROFS))) { +#else /* No EROFS */ + if((fd_ptr->fd == -1) && (errno == EACCES)) { +#endif /* EROFS */ + if(flags & O_WRONLY) { + fd_ptr->fd = fd_attempt_open(fname, open_flags|O_WRONLY, mode); + fd_ptr->real_open_flags = O_WRONLY; + } else { + fd_ptr->fd = fd_attempt_open(fname, open_flags|O_RDONLY, mode); + fd_ptr->real_open_flags = O_RDONLY; + } + } + } - if ((Files[fnum].fd>=0) && + if ((fd_ptr->fd >=0) && Connections[cnum].printer && lp_minprintspace(SNUM(cnum))) { pstring dname; int dum1,dum2,dum3; @@ -781,72 +1082,48 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode) if (p) *p = 0; if (sys_disk_free(dname,&dum1,&dum2,&dum3) < lp_minprintspace(SNUM(cnum))) { - close(Files[fnum].fd); - Files[fnum].fd = -1; - sys_unlink(fname); + fd_attempt_close(fd_ptr); + Files[fnum].fd_ptr = 0; + if(fd_ptr->ref_count == 0) + sys_unlink(fname); errno = ENOSPC; return; } } - - /* Fix for files ending in '.' */ - if((Files[fnum].fd == -1) && (errno == ENOENT) && - (strchr(fname,'.')==NULL)) - { - strcat(fname,"."); - Files[fnum].fd = sys_open(fname,flags,mode); - } - -#if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF)) - if ((Files[fnum].fd == -1) && (errno == ENAMETOOLONG)) - { - int max_len; - char *p = strrchr(fname, '/'); - - if (p == fname) /* name is "/xxx" */ - { - max_len = pathconf("/", _PC_NAME_MAX); - p++; - } - else if ((p == NULL) || (p == fname)) - { - p = fname; - max_len = pathconf(".", _PC_NAME_MAX); - } - else - { - *p = '\0'; - max_len = pathconf(fname, _PC_NAME_MAX); - *p = '/'; - p++; - } - if (strlen(p) > max_len) - { - char tmp = p[max_len]; - - p[max_len] = '\0'; - if ((Files[fnum].fd = sys_open(fname,flags,mode)) == -1) - p[max_len] = tmp; - } - } -#endif - - if (Files[fnum].fd < 0) + if (fd_ptr->fd < 0) { DEBUG(3,("Error opening file %s (%s) (flags=%d)\n", fname,strerror(errno),flags)); + /* Ensure the ref_count is decremented. */ + fd_attempt_close(fd_ptr); check_for_pipe(fname); return; } - if (Files[fnum].fd >= 0) + if (fd_ptr->fd >= 0) { - struct stat st; + if(sbuf == 0) { + /* Do the fstat */ + if(fstat(fd_ptr->fd, &statbuf) == -1) { + /* 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(fd_ptr); + return; + } + sbuf = &statbuf; + } + /* Set the correct entries in fd_ptr. */ + fd_ptr->dev = (uint32)sbuf->st_dev; + fd_ptr->inode = (uint32)sbuf->st_ino; + + Files[fnum].fd_ptr = fd_ptr; Connections[cnum].num_files_open++; - fstat(Files[fnum].fd,&st); - Files[fnum].mode = st.st_mode; - Files[fnum].open_time = time(NULL); + Files[fnum].mode = sbuf->st_mode; + GetTimeOfDay(&Files[fnum].open_time); + Files[fnum].uid = current_user.id; Files[fnum].size = 0; Files[fnum].pos = -1; Files[fnum].open = True; @@ -856,11 +1133,10 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode) Files[fnum].can_read = ((flags & O_WRONLY)==0); Files[fnum].can_write = ((flags & (O_WRONLY|O_RDWR))!=0); Files[fnum].share_mode = 0; - Files[fnum].share_pending = False; Files[fnum].print_file = Connections[cnum].printer; Files[fnum].modified = False; Files[fnum].cnum = cnum; - string_set(&Files[fnum].name,fname); + string_set(&Files[fnum].name,dos_to_unix(fname,False)); Files[fnum].wbmpx_ptr = NULL; /* @@ -890,7 +1166,7 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode) { Files[fnum].mmap_size = file_size(fname); Files[fnum].mmap_ptr = (char *)mmap(NULL,Files[fnum].mmap_size, - PROT_READ,MAP_SHARED,Files[fnum].fd,0); + PROT_READ,MAP_SHARED,Files[fnum].fd_ptr->fd,0); if (Files[fnum].mmap_ptr == (char *)-1 || !Files[fnum].mmap_ptr) { @@ -907,7 +1183,7 @@ sync a file void sync_file(int fnum) { #ifndef NO_FSYNC - fsync(Files[fnum].fd); + fsync(Files[fnum].fd_ptr->fd); #endif } @@ -944,7 +1220,7 @@ static void check_magic(int fnum,int cnum) sprintf(magic_output,"%s.out",fname); chmod(fname,0755); - ret = smbrun(fname,magic_output); + ret = smbrun(fname,magic_output,False); DEBUG(3,("Invoking magic command %s gave %d\n",fname,ret)); unlink(fname); } @@ -956,38 +1232,49 @@ close a file - possibly invalidating the read prediction ****************************************************************************/ void close_file(int fnum) { - int cnum = Files[fnum].cnum; - invalidate_read_prediction(Files[fnum].fd); - Files[fnum].open = False; + 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; + + invalidate_read_prediction(fs_p->fd_ptr->fd); + fs_p->open = False; Connections[cnum].num_files_open--; - if(Files[fnum].wbmpx_ptr) + if(fs_p->wbmpx_ptr) { - free((char *)Files[fnum].wbmpx_ptr); - Files[fnum].wbmpx_ptr = NULL; + free((char *)fs_p->wbmpx_ptr); + fs_p->wbmpx_ptr = NULL; } #if USE_MMAP - if(Files[fnum].mmap_ptr) + if(fs_p->mmap_ptr) { - munmap(Files[fnum].mmap_ptr,Files[fnum].mmap_size); - Files[fnum].mmap_ptr = NULL; + munmap(fs_p->mmap_ptr,fs_p->mmap_size); + fs_p->mmap_ptr = NULL; } #endif if (lp_share_modes(SNUM(cnum))) - del_share_mode(fnum); + { + lock_share_entry( cnum, dev, inode, &token); + del_share_mode(token, fnum); + } - close(Files[fnum].fd); + fd_attempt_close(fs_p->fd_ptr); + + if (lp_share_modes(SNUM(cnum))) + unlock_share_entry( cnum, dev, inode, token); /* NT uses smbclose to start a print - weird */ - if (Files[fnum].print_file) + if (fs_p->print_file) print_file(fnum); /* check for magic scripts */ check_magic(fnum,cnum); DEBUG(2,("%s %s closed file %s (numopen=%d)\n", - timestring(),Connections[cnum].user,Files[fnum].name, + timestring(),Connections[cnum].user,fs_p->name, Connections[cnum].num_files_open)); } @@ -1049,17 +1336,44 @@ return True if sharing doesn't prevent the operation ********************************************************************/ BOOL check_file_sharing(int cnum,char *fname) { - int pid=0; - int share_mode = get_share_mode_byname(cnum,fname,&pid); + int i; + int ret = False; + min_share_mode_entry *old_shares = 0; + int num_share_modes; + struct stat sbuf; + share_lock_token token; + int pid = getpid(); - if (!pid || !share_mode) return(True); - - if (share_mode == DENY_DOS) - return(pid == getpid()); + if(!lp_share_modes(SNUM(cnum))) + return True; + + if (stat(fname,&sbuf) == -1) return(True); + + lock_share_entry(cnum, (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, &token); + num_share_modes = get_share_modes(cnum, token, + (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, &old_shares); + + for( i = 0; i < num_share_modes; i++) + { + if (old_shares[i].share_mode != DENY_DOS) + goto free_and_exit; + + if(old_shares[i].pid != pid) + goto free_and_exit; + } /* XXXX exactly what share mode combinations should be allowed for deleting/renaming? */ - return(False); + /* If we got here then either there were no share modes or + all share modes were DENY_DOS and the pid == getpid() */ + ret = True; + +free_and_exit: + + unlock_share_entry(cnum, (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, token); + if(old_shares != NULL) + free((char *)old_shares); + return(ret); } /**************************************************************************** @@ -1067,17 +1381,25 @@ BOOL check_file_sharing(int cnum,char *fname) Helper for open_file_shared. Truncate a file after checking locking; close file if locked. **************************************************************************/ -static void truncate_unless_locked(int fnum, int cnum) +static void truncate_unless_locked(int fnum, int cnum, share_lock_token token, + BOOL *share_locked) { if (Files[fnum].can_write){ if (is_locked(fnum,cnum,0x3FFFFFFF,0)){ + /* 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(cnum))) + unlock_share_entry( cnum, Files[fnum].fd_ptr->dev, + Files[fnum].fd_ptr->inode, token); close_file(fnum); + /* Share mode no longer locked. */ + *share_locked = False; errno = EACCES; unix_ERR_class = ERRDOS; unix_ERR_code = ERRlock; } else - ftruncate(Files[fnum].fd,0); + ftruncate(Files[fnum].fd_ptr->fd,0); } } @@ -1088,25 +1410,31 @@ open a file with a share mode void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, int mode,int *Access,int *action) { + files_struct *fs_p = &Files[fnum]; int flags=0; int flags2=0; int deny_mode = (share_mode>>4)&7; struct stat sbuf; BOOL file_existed = file_exist(fname,&sbuf); + BOOL share_locked = False; BOOL fcbopen = False; - int share_pid=0; + share_lock_token token; + uint32 dev = 0; + uint32 inode = 0; - Files[fnum].open = False; - Files[fnum].fd = -1; + fs_p->open = False; + fs_p->fd_ptr = 0; /* this is for OS/2 EAs - try and say we don't support them */ - if (strstr(fname,".+,;=[].")) { + if (strstr(fname,".+,;=[].")) + { unix_ERR_class = ERRDOS; unix_ERR_code = ERROR_EAS_NOT_SUPPORTED; return; } - if ((ofun & 0x3) == 0 && file_existed) { + if ((ofun & 0x3) == 0 && file_existed) + { errno = EEXIST; return; } @@ -1120,7 +1448,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, append does not mean the same thing under dos and unix */ switch (share_mode&0xF) - { + { case 1: flags = O_WRONLY; break; @@ -1134,18 +1462,21 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, default: flags = O_RDONLY; break; - } + } if (flags != O_RDONLY && file_existed && - (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf)))) { - if (!fcbopen) { + (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf)))) + { + if (!fcbopen) + { errno = EACCES; return; } flags = O_RDONLY; } - if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) { + if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) + { DEBUG(2,("Invalid deny mode %d on file %s\n",deny_mode,fname)); errno = EINVAL; return; @@ -1153,21 +1484,36 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, if (deny_mode == DENY_FCB) deny_mode = DENY_DOS; - if (lp_share_modes(SNUM(cnum))) { - int old_share=0; + if (lp_share_modes(SNUM(cnum))) + { + int num_shares = 0; + int i; + min_share_mode_entry *old_shares = 0; + if (file_existed) - old_share = get_share_mode(cnum,&sbuf,&share_pid); + { + dev = (uint32)sbuf.st_dev; + inode = (uint32)sbuf.st_ino; + lock_share_entry(cnum, dev, inode, &token); + share_locked = True; + num_shares = get_share_modes(cnum, token, dev, inode, &old_shares); + } - if (share_pid) { + for(i = 0; i < num_shares; i++) + { /* someone else has a share lock on it, check to see if we can too */ - int old_open_mode = old_share&0xF; - int old_deny_mode = (old_share>>4)&7; + int old_open_mode = old_shares[i].share_mode &0xF; + int old_deny_mode = (old_shares[i].share_mode >>4)&7; - if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) { + if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) + { DEBUG(2,("Invalid share mode (%d,%d,%d) on file %s\n", deny_mode,old_deny_mode,old_open_mode,fname)); + free((char *)old_shares); + if(share_locked) + unlock_share_entry(cnum, dev, inode, token); errno = EACCES; unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; @@ -1176,20 +1522,25 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, { int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode, - share_pid,fname); + old_shares[i].pid,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 == AWRITE && flags == O_RDONLY)) + { DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n", deny_mode,old_deny_mode,old_open_mode, - share_pid,fname, + old_shares[i].pid,fname, access_allowed)); + free((char *)old_shares); + if(share_locked) + unlock_share_entry(cnum, dev, inode, token); errno = EACCES; unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; return; - } + } if (access_allowed == AREAD) flags = O_RDONLY; @@ -1198,76 +1549,72 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, flags = O_WRONLY; } } + if(old_shares != 0) + free((char *)old_shares); } DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n", flags,flags2,mode)); - open_file(fnum,cnum,fname,flags|(flags2&~(O_TRUNC)),mode); - if (!Files[fnum].open && flags==O_RDWR && errno!=ENOENT && fcbopen) { + open_file(fnum,cnum,fname,flags|(flags2&~(O_TRUNC)),mode,file_existed ? &sbuf : 0); + if (!fs_p->open && flags==O_RDWR && errno!=ENOENT && fcbopen) + { flags = O_RDONLY; - open_file(fnum,cnum,fname,flags,mode); + open_file(fnum,cnum,fname,flags,mode,file_existed ? &sbuf : 0 ); } - if (Files[fnum].open) { + if (fs_p->open) + { int open_mode=0; - switch (flags) { - case O_RDONLY: - open_mode = 0; - break; - case O_RDWR: - open_mode = 2; - break; - case O_WRONLY: - open_mode = 1; - break; + + if((share_locked == False) && lp_share_modes(SNUM(cnum))) + { + /* We created the file - thus we must now lock the share entry before creating it. */ + dev = fs_p->fd_ptr->dev; + inode = fs_p->fd_ptr->inode; + lock_share_entry(cnum, dev, inode, &token); + share_locked = True; } - Files[fnum].share_mode = (deny_mode<<4) | open_mode; - Files[fnum].share_pending = True; + switch (flags) + { + case O_RDONLY: + open_mode = 0; + break; + case O_RDWR: + open_mode = 2; + break; + case O_WRONLY: + open_mode = 1; + break; + } - if (Access) { + fs_p->share_mode = (deny_mode<<4) | open_mode; + + if (Access) (*Access) = open_mode; - } - - if (action) { + + if (action) + { if (file_existed && !(flags2 & O_TRUNC)) *action = 1; if (!file_existed) *action = 2; if (file_existed && (flags2 & O_TRUNC)) *action = 3; } - - if (!share_pid) - share_mode_pending = True; + /* We must create the share mode entry before truncate as + truncate can fail due to locking and have to close the + file (which expects the share_mode_entry to be there). + */ + if (lp_share_modes(SNUM(cnum))) + set_share_mode(token, fnum); if ((flags2&O_TRUNC) && file_existed) - truncate_unless_locked(fnum,cnum); + truncate_unless_locked(fnum,cnum,token,&share_locked); } -} - - -/******************************************************************* -check for files that we should now set our share modes on -********************************************************************/ -static void check_share_modes(void) -{ - int i; - for (i=0;ifd,pos+offset,SEEK_SET) - offset; return(Files[fnum].pos); } /**************************************************************************** read from a file ****************************************************************************/ -int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact) +int read_file(int fnum,char *data,int pos,int n) { - int ret=0; + int ret=0,readret; if (!Files[fnum].can_write) { - ret = read_predict(Files[fnum].fd, - pos, - data, - NULL, - maxcnt); + ret = read_predict(Files[fnum].fd_ptr->fd,pos,data,NULL,n); data += ret; - maxcnt -= ret; - mincnt = MAX(mincnt-ret,0); + n -= ret; pos += ret; } #if USE_MMAP if (Files[fnum].mmap_ptr) { - int num = MIN(maxcnt,Files[fnum].mmap_size-pos); + int num = MIN(n,Files[fnum].mmap_size-pos); if (num > 0) { memcpy(data,Files[fnum].mmap_ptr+pos,num); data += num; pos += num; - maxcnt -= num; - mincnt = MAX(mincnt-num,0); + n -= num; ret += num; } } #endif - if (maxcnt <= 0) + if (n <= 0) return(ret); if (seek_file(fnum,pos) != pos) @@ -1327,13 +1668,10 @@ int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL return(ret); } - if (maxcnt > 0) - ret += read_with_timeout(Files[fnum].fd, - data, - mincnt, - maxcnt, - timeout, - exact); + if (n > 0) { + readret = read(Files[fnum].fd_ptr->fd,data,n); + if (readret > 0) ret += readret; + } return(ret); } @@ -1352,7 +1690,7 @@ int write_file(int fnum,char *data,int n) if (!Files[fnum].modified) { struct stat st; Files[fnum].modified = True; - if (fstat(Files[fnum].fd,&st) == 0) { + if (fstat(Files[fnum].fd_ptr->fd,&st) == 0) { int dosmode = dos_mode(Files[fnum].cnum,Files[fnum].name,&st); if (MAP_ARCHIVE(Files[fnum].cnum) && !IS_DOS_ARCHIVE(dosmode)) { dos_chmod(Files[fnum].cnum,Files[fnum].name,dosmode | aARCH,&st); @@ -1360,7 +1698,7 @@ int write_file(int fnum,char *data,int n) } } - return(write_data(Files[fnum].fd,data,n)); + return(write_data(Files[fnum].fd_ptr->fd,data,n)); } @@ -1612,11 +1950,11 @@ static int sig_cld() } depth++; - BlockSignals(True); + BlockSignals(True,SIGCLD); DEBUG(5,("got SIGCLD\n")); #ifdef USE_WAITPID - while (waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0); + while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0); #endif /* Stop zombies */ @@ -1638,7 +1976,7 @@ static int sig_cld() while (wait3(WAIT3_CAST1 NULL, WNOHANG, WAIT3_CAST2 NULL) > 0); #endif depth--; - BlockSignals(False); + BlockSignals(False,SIGCLD); return 0; } #endif @@ -1648,6 +1986,20 @@ static int sig_cld() **************************************************************************/ static int sig_pipe() { + extern int password_client; + BlockSignals(True,SIGPIPE); + + if (password_client != -1) { + DEBUG(3,("lost connection to password server\n")); + close(password_client); + password_client = -1; +#ifndef DONT_REINSTALL_SIG + signal(SIGPIPE, SIGNAL_CAST sig_pipe); +#endif + BlockSignals(False,SIGPIPE); + return 0; + } + exit_server("Got sigpipe\n"); return(0); } @@ -1673,7 +2025,7 @@ static BOOL open_sockets(BOOL is_daemon,int port) #endif /* open an incoming socket */ - s = open_socket_in(SOCK_STREAM, port, 0); + s = open_socket_in(SOCK_STREAM, port, 0,interpret_addr(lp_socket_address())); if (s == -1) return(False); @@ -1685,6 +2037,9 @@ static BOOL open_sockets(BOOL is_daemon,int port) return False; } + if(atexit_set == 0) + atexit(killkids); + /* now accept incoming connections - forking a new process for each incoming connection */ DEBUG(2,("waiting for a connection\n")); @@ -1698,7 +2053,7 @@ static BOOL open_sockets(BOOL is_daemon,int port) if (Client == -1) { DEBUG(0,("accept: %s",strerror(errno))); - return False; + continue; } #ifdef NO_FORK_DEBUG @@ -1719,6 +2074,7 @@ static BOOL open_sockets(BOOL is_daemon,int port) /* close our standard file descriptors */ close_low_fds(); + am_parent = 0; set_socket_options(Client,"SO_KEEPALIVE"); set_socket_options(Client,user_socket_options); @@ -1794,6 +2150,8 @@ BOOL reload_services(BOOL test) reopen_logs(); + load_interfaces(); + { extern int Client; if (Client != -1) { @@ -1817,13 +2175,13 @@ this prevents zombie child processes ****************************************************************************/ static int sig_hup() { - BlockSignals(True); + BlockSignals(True,SIGHUP); DEBUG(0,("Got SIGHUP\n")); reload_services(False); #ifndef DONT_REINSTALL_SIG signal(SIGHUP,SIGNAL_CAST sig_hup); #endif - BlockSignals(False); + BlockSignals(False,SIGHUP); return(0); } @@ -1905,7 +2263,7 @@ int setup_groups(char *user, int uid, int gid, int *p_ngroups, /**************************************************************************** make a connection to a service ****************************************************************************/ -int make_connection(char *service,char *user,char *password, int pwlen, char *dev,int vuid) +int make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid) { int cnum; int snum; @@ -2025,6 +2383,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de pcon->admin_user = False; pcon->force_user = force; + pcon->vuid = vuid; pcon->uid = pass->pw_uid; pcon->gid = pass->pw_gid; pcon->num_files_open = 0; @@ -2040,14 +2399,21 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de #if HAVE_GETGRNAM if (*lp_force_group(snum)) { - struct group *gptr = (struct group *)getgrnam(lp_force_group(snum)); + struct group *gptr; + pstring gname; + + StrnCpy(gname,lp_force_group(snum),sizeof(pstring)-1); + /* default service may be a group name */ + string_sub(gname,"%S",service); + gptr = (struct group *)getgrnam(gname); + if (gptr) { pcon->gid = gptr->gr_gid; - DEBUG(3,("Forced group %s\n",lp_force_group(snum))); + DEBUG(3,("Forced group %s\n",gname)); } else - DEBUG(1,("Couldn't find group %s\n",lp_force_group(snum))); + DEBUG(1,("Couldn't find group %s\n",gname)); } #endif @@ -2110,10 +2476,10 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de strcpy(cmd,lp_rootpreexec(SNUM(cnum))); standard_sub(cnum,cmd); DEBUG(5,("cmd=%s\n",cmd)); - smbrun(cmd,NULL); + smbrun(cmd,NULL,False); } - if (!become_user(cnum,pcon->uid)) + if (!become_user(cnum,pcon->vuid)) { DEBUG(0,("Can't become connected user!\n")); pcon->open = False; @@ -2163,17 +2529,17 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de pstring cmd; strcpy(cmd,lp_preexec(SNUM(cnum))); standard_sub(cnum,cmd); - smbrun(cmd,NULL); + smbrun(cmd,NULL,False); } /* we've finished with the sensitive stuff */ unbecome_user(); { - extern struct from_host Client_info; DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) connect to service %s as user %s (uid=%d,gid=%d) (pid %d)\n", timestring(), - Client_info.name,Client_info.addr, + remote_machine, + client_addr(), lp_servicename(SNUM(cnum)),user, pcon->uid, pcon->gid, @@ -2275,6 +2641,11 @@ int reply_lanman1(char *outbuf) 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; @@ -2297,7 +2668,8 @@ int reply_lanman1(char *outbuf) } CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */ - SSVAL(outbuf,smb_vwv2,maxxmit); + 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); SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support @@ -2320,6 +2692,11 @@ int reply_lanman2(char *outbuf) 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; @@ -2344,7 +2721,8 @@ int reply_lanman2(char *outbuf) } CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */ - SSVAL(outbuf,smb_vwv2,maxxmit); + 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); SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */ @@ -2354,32 +2732,72 @@ int reply_lanman2(char *outbuf) return (smb_len(outbuf)+4); } + /**************************************************************************** reply for the nt protocol ****************************************************************************/ int reply_nt1(char *outbuf) { - int capabilities=0x300; /* has dual names + lock_and_read */ + /* dual names + lock_and_read + nt SMBs + remote API calls */ + int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ; +/* + 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; + */ + 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); + + if (lp_readraw() && lp_writeraw()) + { + capabilities |= CAP_RAW_MODE; + } if (lp_security()>=SEC_USER) secword |= 1; if (doencrypt) secword |= 2; - set_message(outbuf,17,doencrypt?8:0,True); + /* 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 + + 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 + CVAL(outbuf,smb_vwv1) = secword; #ifdef SMB_PASSWD /* Create a token value and add it to the outgoing packet. */ - if (doencrypt) { + if (doencrypt) + { generate_next_challenge(smb_buf(outbuf)); + /* Tell the nt machine how long the challenge is. */ - SSVALS(outbuf,smb_vwv16+1,8); + SSVALS(outbuf,smb_vwv16+1,challenge_len); } #endif - SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */ - Protocol = PROTOCOL_NT1; if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) { @@ -2389,21 +2807,20 @@ int reply_nt1(char *outbuf) #endif } - if (lp_readraw() && lp_writeraw()) - capabilities |= 1; - + 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 */ - SIVAL(outbuf,smb_vwv5+1,0xFFFF); /* raw size */ + SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */ + SIVAL(outbuf,smb_vwv5+1,0xffff); /* raw size. LOTS! */ + SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */ SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */ put_long_date(outbuf+smb_vwv11+1,t); SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60); + SSVAL(outbuf,smb_vwv17,data_len); /* length of challenge+domain strings */ return (smb_len(outbuf)+4); } - /* these are the protocol lists used for auto architecture detection: WinNT 3.51: @@ -2591,41 +3008,6 @@ static int reply_negprot(char *inbuf,char *outbuf) } -/**************************************************************************** - parse a connect packet -****************************************************************************/ -void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev) -{ - char *p = smb_buf(buf) + 1; - char *p2; - - DEBUG(4,("parsing connect string %s\n",p)); - - p2 = strrchr(p,'\\'); - if (p2 == NULL) - strcpy(service,p); - else - strcpy(service,p2+1); - - p += strlen(p) + 2; - - strcpy(password,p); - *pwlen = strlen(password); - - p += strlen(p) + 2; - - strcpy(dev,p); - - *user = 0; - p = strchr(service,'%'); - if (p != NULL) - { - *p = 0; - strcpy(user,p+1); - } -} - - /**************************************************************************** close all open files for a connection ****************************************************************************/ @@ -2643,10 +3025,8 @@ static void close_open_files(int cnum) /**************************************************************************** close a cnum ****************************************************************************/ -void close_cnum(int cnum, int uid) +void close_cnum(int cnum, uint16 vuid) { - extern struct from_host Client_info; - DirCacheFlush(SNUM(cnum)); unbecome_user(); @@ -2659,7 +3039,7 @@ void close_cnum(int cnum, int uid) DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) closed connection to service %s\n", timestring(), - Client_info.name,Client_info.addr, + remote_machine,client_addr(), lp_servicename(SNUM(cnum)))); yield_connection(cnum, @@ -2673,12 +3053,12 @@ void close_cnum(int cnum, int uid) dptr_closecnum(cnum); /* execute any "postexec = " line */ - if (*lp_postexec(SNUM(cnum)) && become_user(cnum,uid)) + if (*lp_postexec(SNUM(cnum)) && become_user(cnum,vuid)) { pstring cmd; strcpy(cmd,lp_postexec(SNUM(cnum))); standard_sub(cnum,cmd); - smbrun(cmd,NULL); + smbrun(cmd,NULL,False); unbecome_user(); } @@ -2689,7 +3069,7 @@ void close_cnum(int cnum, int uid) pstring cmd; strcpy(cmd,lp_rootpostexec(SNUM(cnum))); standard_sub(cnum,cmd); - smbrun(cmd,NULL); + smbrun(cmd,NULL,False); } Connections[cnum].open = False; @@ -2813,8 +3193,10 @@ BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear) 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); @@ -2871,11 +3253,8 @@ BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear) StrnCpy(crec.name,lp_servicename(snum),sizeof(crec.name)-1); crec.start = time(NULL); - { - extern struct from_host Client_info; - StrnCpy(crec.machine,Client_info.name,sizeof(crec.machine)-1); - StrnCpy(crec.addr,Client_info.addr,sizeof(crec.addr)-1); - } + 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 || @@ -2957,6 +3336,11 @@ void exit_server(char *reason) if (dump_core()) return; #endif } + +#ifdef FAST_SHARE_MODES + stop_share_mode_mgmt(); +#endif /* FAST_SHARE_MODES */ + DEBUG(3,("%s Server exit (%s)\n",timestring(),reason?reason:"")); exit(0); } @@ -3023,7 +3407,7 @@ struct smb_message_struct {SMBecho,"SMBecho",reply_echo,0}, {SMBsesssetupX,"SMBsesssetupX",reply_sesssetup_and_X,0}, {SMBtconX,"SMBtconX",reply_tcon_and_X,0}, - {SMBulogoffX, "SMBulogoffX", reply_ulogoffX, 0}, + {SMBulogoffX, "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */ {SMBgetatr,"SMBgetatr",reply_getatr,AS_USER}, {SMBsetatr,"SMBsetatr",reply_setatr,AS_USER | NEED_WRITE}, {SMBchkpth,"SMBchkpth",reply_chkpth,AS_USER}, @@ -3037,7 +3421,7 @@ struct smb_message_struct {SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE}, {SMBread,"SMBread",reply_read,AS_USER}, {SMBwrite,"SMBwrite",reply_write,AS_USER}, - {SMBclose,"SMBclose",reply_close,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}, @@ -3052,7 +3436,7 @@ struct smb_message_struct {SMBctemp,"SMBctemp",reply_ctemp,AS_USER}, {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER}, {SMBsplclose,"SMBsplclose",reply_printclose,AS_USER}, - {SMBsplretq,"SMBsplretq",reply_printqueue,AS_USER}, + {SMBsplretq,"SMBsplretq",reply_printqueue,AS_USER|AS_GUEST}, {SMBsplwr,"SMBsplwr",reply_printwrite,AS_USER}, {SMBlock,"SMBlock",reply_lock,AS_USER}, {SMBunlock,"SMBunlock",reply_unlock,AS_USER}, @@ -3080,7 +3464,7 @@ struct smb_message_struct {SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE}, {SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE}, - {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER}, + {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER | CAN_IPC}, {SMBreadX,"SMBreadX",reply_read_and_X,AS_USER}, {SMBwriteX,"SMBwriteX",reply_write_and_X,AS_USER}, {SMBlockingX,"SMBlockingX",reply_lockingX,AS_USER}, @@ -3178,15 +3562,24 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize { int cnum = SVAL(inbuf,smb_tid); int flags = smb_messages[match].flags; - int uid = SVAL(inbuf,smb_uid); + uint16 session_tag = SVAL(inbuf,smb_uid); /* 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,uid)) - return(ERROR(ERRSRV,ERRinvnid)); + if ((flags & AS_USER) && !become_user(cnum,session_tag)) { + if (flags & AS_GUEST) + flags &= ~AS_USER; + else + return(ERROR(ERRSRV,ERRinvnid)); + } + /* this code is to work around a bug is MS client 3 without + introducing a security hole - it needs to be able to do + print queue checks as guest if it isn't logged in properly */ + if (flags & AS_USER) + flags &= ~AS_GUEST; /* does it need write permission? */ if ((flags & NEED_WRITE) && !CAN_WRITE(cnum)) @@ -3238,103 +3631,99 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize /**************************************************************************** -construct a chained reply and add it to the already made reply - -inbuf points to the original message start. -inbuf2 points to the smb_wct part of the secondary message -type is the type of the secondary message -outbuf points to the original outbuffer -outbuf2 points to the smb_wct field of the new outbuffer -size is the total length of the incoming message (from inbuf1) -bufsize is the total buffer size - -return how many bytes were added to the response -****************************************************************************/ -int chain_reply(int type,char *inbuf,char *inbuf2,char *outbuf,char *outbuf2,int size,int bufsize) + construct a chained reply and add it to the already made reply + **************************************************************************/ +int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) { - int outsize = 0; - char *ibuf,*obuf; - static BOOL in_chain = False; - static char *last_outbuf=NULL; - BOOL was_inchain = in_chain; - int insize_remaining; - static int insize_deleted; - - - chain_size += PTR_DIFF(outbuf2,outbuf) - smb_wct; - if (was_inchain) - outbuf = last_outbuf; - else - insize_deleted = 0; + static char *orig_inbuf; + static char *orig_outbuf; + int smb_com1, smb_com2 = CVAL(inbuf,smb_vwv0); + unsigned smb_off2 = SVAL(inbuf,smb_vwv1); + char *inbuf2, *outbuf2; + 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); + + /* maybe its not chained */ + if (smb_com2 == 0xFF) { + CVAL(outbuf,smb_vwv0) = 0xFF; + return outsize; + } + if (chain_size == 0) { + /* this is the first part of the chain */ + orig_inbuf = inbuf; + orig_outbuf = outbuf; + } - insize_deleted = 0; - inbuf2 -= insize_deleted; - insize_remaining = size - PTR_DIFF(inbuf2,inbuf); - insize_deleted += size - (insize_remaining + smb_wct); + /* 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; - in_chain = True; - last_outbuf = outbuf; + /* remember how much the caller added to the chain, only counting stuff + after the parameter words */ + chain_size += outsize - smb_wct; + /* work out pointers into the original packets. The + headers on these need to be filled in */ + inbuf2 = orig_inbuf + smb_off2 + 4 - smb_wct; + outbuf2 = orig_outbuf + SVAL(outbuf,smb_vwv1) + 4 - smb_wct; - /* allocate some space for the in and out buffers of the chained message */ - ibuf = (char *)malloc(size + SAFETY_MARGIN); - obuf = (char *)malloc(bufsize + SAFETY_MARGIN); + /* remember the original command type */ + smb_com1 = CVAL(orig_inbuf,smb_com); - if (!ibuf || !obuf) - { - DEBUG(0,("Out of memory in chain reply\n")); - return(ERROR(ERRSRV,ERRnoresource)); - } + /* save the data which will be overwritten by the new headers */ + memcpy(inbuf_saved,inbuf2,smb_wct); + memcpy(outbuf_saved,outbuf2,smb_wct); - ibuf += SMB_ALIGNMENT; - obuf += SMB_ALIGNMENT; + /* give the new packet the same header as the last part of the SMB */ + memmove(inbuf2,inbuf,smb_wct); /* create the in buffer */ - memcpy(ibuf,inbuf,smb_wct); - memcpy(ibuf+smb_wct,inbuf2,insize_remaining); - CVAL(ibuf,smb_com) = type; + CVAL(inbuf2,smb_com) = smb_com2; /* create the out buffer */ - bzero(obuf,smb_size); - - set_message(obuf,0,0,True); - CVAL(obuf,smb_com) = CVAL(ibuf,smb_com); + bzero(outbuf2,smb_size); + set_message(outbuf2,0,0,True); + CVAL(outbuf2,smb_com) = CVAL(inbuf2,smb_com); - memcpy(obuf+4,ibuf+4,4); - CVAL(obuf,smb_rcls) = SUCCESS; - CVAL(obuf,smb_reh) = 0; - CVAL(obuf,smb_flg) = 0x80 | (CVAL(ibuf,smb_flg) & 0x8); /* bit 7 set - means a reply */ - SSVAL(obuf,smb_flg2,1); /* say we support long filenames */ - SSVAL(obuf,smb_err,SUCCESS); - SSVAL(obuf,smb_tid,SVAL(inbuf,smb_tid)); - SSVAL(obuf,smb_pid,SVAL(inbuf,smb_pid)); - SSVAL(obuf,smb_uid,SVAL(inbuf,smb_uid)); - SSVAL(obuf,smb_mid,SVAL(inbuf,smb_mid)); + memcpy(outbuf2+4,inbuf2+4,4); + CVAL(outbuf2,smb_rcls) = 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_tid,SVAL(inbuf2,smb_tid)); + SSVAL(outbuf2,smb_pid,SVAL(inbuf2,smb_pid)); + SSVAL(outbuf2,smb_uid,SVAL(inbuf2,smb_uid)); + SSVAL(outbuf2,smb_mid,SVAL(inbuf2,smb_mid)); DEBUG(3,("Chained message\n")); - show_msg(ibuf); + show_msg(inbuf2); /* process the request */ - outsize = switch_message(type,ibuf,obuf,smb_wct+insize_remaining, - bufsize-chain_size); - - /* copy the new reply header over the old one, but preserve - the smb_com field */ - memcpy(outbuf+smb_com+1,obuf+smb_com+1,smb_wct-(smb_com+1)); + outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size, + bufsize-chain_size); - /* and copy the data from the reply to the right spot */ - memcpy(outbuf2,obuf+smb_wct,outsize - smb_wct); + /* copy the new reply and request headers over the old ones, but + preserve the smb_com field */ + memmove(orig_outbuf,outbuf2,smb_wct); + CVAL(orig_outbuf,smb_com) = smb_com1; - /* free the allocated buffers */ - if (ibuf) free(ibuf-SMB_ALIGNMENT); - if (obuf) free(obuf-SMB_ALIGNMENT); - - in_chain = was_inchain; + /* restore the saved data, being careful not to overwrite any + data from the reply header */ + memcpy(inbuf2,inbuf_saved,smb_wct); + { + int ofs = smb_wct - PTR_DIFF(outbuf2,orig_outbuf); + if (ofs < 0) ofs = 0; + memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs); + } - /* return how much extra has been added to the packet */ - return(outsize - smb_wct); + return outsize2; } @@ -3347,10 +3736,12 @@ 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); chain_size = 0; + chain_fnum = -1; bzero(outbuf,smb_size); @@ -3374,6 +3765,8 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize) outsize = switch_message(type,inbuf,outbuf,size,bufsize); + outsize += chain_size; + if(outsize > 4) smb_setlen(outbuf,outsize - 4); return(outsize); @@ -3383,15 +3776,12 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize) /**************************************************************************** process commands from the client ****************************************************************************/ -void process(void ) +static void process(void) { static int trans_num = 0; int nread; - extern struct from_host Client_info; extern int Client; - fromhost(Client,&Client_info); - InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); if ((InBuffer == NULL) || (OutBuffer == NULL)) @@ -3407,7 +3797,7 @@ void process(void ) ip = *interpret_addr2("localhost"); if (zero_ip(ip)) ip = *interpret_addr2("127.0.0.1"); *OutBuffer = 0; - send_one_packet(OutBuffer,1,ip,137,SOCK_DGRAM); + send_one_packet(OutBuffer,1,ip,NMB_PORT,SOCK_DGRAM); } #endif @@ -3427,24 +3817,6 @@ void process(void ) if (lp_readprediction()) do_read_prediction(); - { - extern pstring share_del_pending; - if (*share_del_pending) { - unbecome_user(); - if (!unlink(share_del_pending)) - DEBUG(3,("Share file deleted %s\n",share_del_pending)); - else - DEBUG(2,("Share del failed of %s\n",share_del_pending)); - share_del_pending[0] = 0; - } - } - - if (share_mode_pending) { - unbecome_user(); - check_share_modes(); - share_mode_pending=False; - } - errno = 0; for (counter=SMBD_SELECT_LOOP; @@ -3456,9 +3828,14 @@ void process(void ) BOOL allidle = True; extern int keepalive; - /* check for socket failure */ - if (errno) { - DEBUG(3,("receive_smb error (%s) exiting\n",strerror(errno))); + if (smb_read_error == READ_EOF) { + DEBUG(3,("end of file from client\n")); + return; + } + + if (smb_read_error == READ_ERROR) { + DEBUG(3,("receive_smb error (%s) exiting\n", + strerror(errno))); return; } @@ -3471,13 +3848,15 @@ void process(void ) if (!(counter%SMBD_RELOAD_CHECK)) reload_services(True); +#if 0 /* JRA */ /* check the share modes every 10 secs */ if (!(counter%SHARE_MODES_CHECK)) check_share_modes(); /* clean the share modes every 5 minutes */ if (!(counter%SHARE_MODES_CLEAN)) - clean_share_files(); + clean_share_modes(); +#endif /* JRA */ /* automatic timeout if all connections are closed */ if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) { @@ -3540,7 +3919,7 @@ void process(void ) if (msg_type == 0) show_msg(InBuffer); - nread = construct_reply(InBuffer,OutBuffer,nread,maxxmit); + nread = construct_reply(InBuffer,OutBuffer,nread,max_send); if(nread > 0) { if (CVAL(OutBuffer,0) == 0) @@ -3566,7 +3945,7 @@ void process(void ) static void init_structs(void ) { int i; - get_myname(myhostname,&myip); + get_myname(myhostname,NULL); for (i=0;iref_count = 0; + fd_ptr->dev = (int32)-1; + fd_ptr->inode = (int32)-1; + fd_ptr->fd = -1; + fd_ptr->fd_readonly = -1; + fd_ptr->fd_writeonly = -1; + fd_ptr->real_open_flags = -1; } init_dptrs(); @@ -3592,7 +3984,7 @@ static void init_structs(void ) /**************************************************************************** usage on the program ****************************************************************************/ -void usage(char *pname) +static void usage(char *pname) { DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n")); @@ -3612,14 +4004,15 @@ void usage(char *pname) /**************************************************************************** main program ****************************************************************************/ -int main(int argc,char *argv[]) + int main(int argc,char *argv[]) { extern BOOL append_log; /* shall I run as a daemon */ BOOL is_daemon = False; - int port = 139; + int port = SMB_PORT; int opt; extern char *optarg; + char pidFile[100] = { 0 }; #ifdef NEED_AUTH_PARAMETERS set_auth_parameters(argc,argv); @@ -3651,8 +4044,13 @@ int main(int argc,char *argv[]) #endif fault_setup(exit_server); + signal(SIGTERM , SIGNAL_CAST dflt_sig); - umask(0777 & ~DEF_CREATE_MASK); + /* we want total control over the permissions on created files, + so set our umask to 0 */ + umask(0); + + GetWd(OriginalDir); init_uid(); @@ -3663,9 +4061,12 @@ int main(int argc,char *argv[]) argc--; } - while ((opt = getopt(argc, argv, "O:i:l:s:d:Dp:hPa")) != EOF) + 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; @@ -3744,6 +4145,8 @@ int main(int argc,char *argv[]) if (!reload_services(False)) return(-1); + strcpy(myworkgroup, lp_workgroup()); + #ifndef NO_SIGNAL_TEST signal(SIGHUP,SIGNAL_CAST sig_hup); #endif @@ -3762,13 +4165,43 @@ int main(int argc,char *argv[]) become_daemon(); } + if (*pidFile) + { + int fd; + char buf[20]; + + if ((fd = open(pidFile, + O_NONBLOCK | 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 (!open_sockets(is_daemon,port)) exit(1); +#ifdef FAST_SHARE_MODES + if (!start_share_mode_mgmt()) + exit(1); +#endif /* FAST_SHARE_MODES */ + /* possibly reload the services file. */ reload_services(True); - maxxmit = MIN(lp_maxxmit(),BUFFER_SIZE); + max_recv = MIN(lp_maxxmit(),BUFFER_SIZE); if (*lp_rootdir()) {