diff options
Diffstat (limited to 'source/smbd/server.c')
-rw-r--r-- | source/smbd/server.c | 891 |
1 files changed, 186 insertions, 705 deletions
diff --git a/source/smbd/server.c b/source/smbd/server.c index 5d8facef33f..1fb6358794a 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -20,13 +20,9 @@ */ #include "includes.h" -#include "loadparm.h" -#include "pcap.h" #include "trans2.h" -#include "reply.h" pstring servicesf = CONFIGFILE; -pstring OriginalDir ="/"; extern pstring debugf; extern pstring sesssetup_user; @@ -34,16 +30,8 @@ char *InBuffer = NULL; char *OutBuffer = NULL; char *last_inbuf = NULL; -int initial_uid = 0; -int initial_gid = 0; - BOOL share_mode_pending = False; -/* have I done a become_user? */ -static struct { - int cnum, uid; -} last_user; - /* the last message the was processed */ int last_message = -1; @@ -60,6 +48,8 @@ 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]; @@ -69,8 +59,6 @@ extern int Protocol; int maxxmit = BUFFER_SIZE; -int chain_size = 0; - /* a fnum to use when chaining */ int chain_fnum = -1; @@ -88,16 +76,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) @@ -148,31 +129,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; @@ -257,8 +227,8 @@ int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st) unixmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH); unixmode |= tmp; } - - return(chmod(fname,unixmode)); + + return(sys_chmod(fname,unixmode)); } @@ -326,7 +296,7 @@ static BOOL scan_directory(char *path, char *name,int snum,BOOL docache) void *cur_dir; char *dname; BOOL mangled; - fstring name2; + pstring name2; mangled = is_mangled(name); @@ -410,8 +380,12 @@ BOOL unix_convert(char *name,int cnum) { if ((! *name) || strchr(name,'/') || !is_8_3(name)) { + char *s; fstring name2; sprintf(name2,"%.6s.XXXXXX",remote_machine); + /* sanitise the name */ + for (s=name2 ; *s ; s++) + if (!issafe(*s)) *s = '_'; strcpy(name,(char *)mktemp(name2)); } return(True); @@ -522,251 +496,6 @@ BOOL unix_convert(char *name,int cnum) } - - -#ifdef QUOTAS -#ifdef LINUX -/**************************************************************************** -try to get the disk space from disk quotas (LINUX version) -****************************************************************************/ -/* -If you didn't make the symlink to the quota package, too bad :( -*/ -#include "quota/quotactl.c" -#include "quota/hasquota.c" -static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize) -{ - uid_t euser_id; - struct dqblk D; - struct stat S; - dev_t devno ; - struct mntent *mnt; - FILE *fp; - int found ; - int qcmd, fd ; - char *qfpathname; - - /* find the block device file */ - - if ( stat(path, &S) == -1 ) - return(False) ; - - devno = S.st_dev ; - - fp = setmntent(MOUNTED,"r"); - found = False ; - - while ((mnt = getmntent(fp)) != (struct mntent *) 0) { - if ( stat(mnt->mnt_dir,&S) == -1 ) - continue ; - if (S.st_dev == devno) { - found = True ; - break ; - } - } - endmntent(fp) ; - - if ( ! found ) - return(False) ; - - qcmd = QCMD(Q_GETQUOTA, USRQUOTA); - - if (hasmntopt(mnt, MNTOPT_NOAUTO) || hasmntopt(mnt, MNTOPT_NOQUOTA)) - return(False) ; - - if (!hasquota(mnt, USRQUOTA, &qfpathname)) - return(False) ; - - euser_id = geteuid(); - seteuid(0); - - if (quotactl(qcmd, mnt->mnt_fsname, euser_id, (caddr_t)&D) != 0) { - if ((fd = open(qfpathname, O_RDONLY)) < 0) { - seteuid(euser_id); - return(False); - } - lseek(fd, (long) dqoff(euser_id), L_SET); - switch (read(fd, &D, sizeof(struct dqblk))) { - case 0:/* EOF */ - memset((caddr_t)&D, 0, sizeof(struct dqblk)); - break; - case sizeof(struct dqblk): /* OK */ - break; - default: /* ERROR */ - close(fd); - seteuid(euser_id); - return(False); - } - } - seteuid(euser_id); - *bsize=1024; - - if (D.dqb_bsoftlimit==0) - return(False); - if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curinodes>D.dqb_isoftlimit)) - { - *dfree = 0; - *dsize = D.dqb_curblocks; - } - else { - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - *dsize = D.dqb_bsoftlimit; - } - return (True); -} -#else -#ifndef CRAY -/**************************************************************************** -try to get the disk space from disk quotas -****************************************************************************/ -static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize) -{ - uid_t user_id, euser_id; - int r; - char dev_disk[256]; - struct dqblk D; - struct stat S; - /* find the block device file */ - if ((stat(path, &S)<0) || - (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False); - - euser_id = geteuid(); - -#ifdef USE_SETRES - /* for HPUX, real uid must be same as euid to execute quotactl for euid */ - user_id = getuid(); - setresuid(euser_id,-1,-1); -#endif - r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D); - #ifdef USE_SETRES - if (setresuid(user_id,-1,-1)) - DEBUG(5,("Unable to reset uid to %d\n", user_id)); - #endif - /* Use softlimit to determine disk space, except when it has been exceeded */ - *bsize = 1024; - if (r) - { - if (errno == EDQUOT) - { - *dfree =0; - *dsize =D.dqb_curblocks; - return (True); - } - else return(False); - } - /* Use softlimit to determine disk space, except when it has been exceeded */ - if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curfiles>D.dqb_fsoftlimit)) - { - *dfree = 0; - *dsize = D.dqb_curblocks; - } - else { - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - *dsize = D.dqb_bsoftlimit; - } - return (True); -} -#else -/**************************************************************************** -try to get the disk space from disk quotas (CRAY VERSION) -****************************************************************************/ -static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize) -{ - struct mntent *mnt; - FILE *fd; - struct stat sbuf; - dev_t devno ; - static dev_t devno_cached = 0 ; - static char name[MNTMAXSTR] ; - struct q_request request ; - struct qf_header header ; - static int quota_default = 0 ; - int found ; - - if ( stat(path,&sbuf) == -1 ) - return(False) ; - - devno = sbuf.st_dev ; - - if ( devno != devno_cached ) { - - devno_cached = devno ; - - if ((fd = setmntent(KMTAB)) == NULL) - return(False) ; - - found = False ; - - while ((mnt = getmntent(fd)) != NULL) { - - if ( stat(mnt->mnt_dir,&sbuf) == -1 ) - continue ; - - if (sbuf.st_dev == devno) { - - found = True ; - break ; - - } - - } - - strcpy(name,mnt->mnt_dir) ; - endmntent(fd) ; - - if ( ! found ) - return(False) ; - } - - request.qf_magic = QF_MAGIC ; - request.qf_entry.id = geteuid() ; - - if (quotactl(name, Q_GETQUOTA, &request) == -1) - return(False) ; - - if ( ! request.user ) - return(False) ; - - if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) { - - if ( ! quota_default ) { - - if ( quotactl(name, Q_GETHEADER, &header) == -1 ) - return(False) ; - else - quota_default = header.user_h.def_fq ; - } - - *dfree = quota_default ; - - }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) { - - *dfree = 0 ; - - }else{ - - *dfree = request.qf_entry.user_q.f_quota ; - - } - - *dsize = request.qf_entry.user_q.f_use ; - - if ( *dfree ) - *dfree -= *dsize ; - - if ( *dfree < 0 ) - *dfree = 0 ; - - *bsize = 4096 ; /* Cray blocksize */ - - return(True) ; - -} -#endif /* CRAY */ -#endif /* LINUX */ -#endif /* QUOTAS */ - - /**************************************************************************** normalise for DOS usage ****************************************************************************/ @@ -1227,16 +956,6 @@ void close_file(int fnum) if (lp_share_modes(SNUM(cnum))) del_share_mode(fnum); - if (Files[fnum].modified) { - struct stat st; - if (fstat(Files[fnum].fd,&st) == 0) { - int dosmode = dos_mode(cnum,Files[fnum].name,&st); - if (!IS_DOS_ARCHIVE(dosmode)) { - dos_chmod(cnum,Files[fnum].name,dosmode | aARCH,&st); - } - } - } - close(Files[fnum].fd); /* NT uses smbclose to start a print - weird */ @@ -1544,41 +1263,35 @@ int seek_file(int fnum,int 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,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) @@ -1587,13 +1300,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,data,n); + if (readret > 0) ret += readret; + } return(ret); } @@ -1609,14 +1319,21 @@ int write_file(int fnum,char *data,int n) return(0); } - Files[fnum].modified = True; + if (!Files[fnum].modified) { + struct stat st; + Files[fnum].modified = True; + if (fstat(Files[fnum].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); + } + } + } return(write_data(Files[fnum].fd,data,n)); } -static int old_umask = 022; - /**************************************************************************** load parameters specific to a connection/service ****************************************************************************/ @@ -1662,261 +1379,6 @@ BOOL become_service(int cnum,BOOL do_chdir) /**************************************************************************** - become the specified uid -****************************************************************************/ -static BOOL become_uid(int uid) -{ - if (initial_uid != 0) - return(True); - -#ifdef AIX - { - /* AIX 3 stuff - inspired by a code fragment in wu-ftpd */ - priv_t priv; - - priv.pv_priv[0] = 0; - priv.pv_priv[1] = 0; - if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_EFFECTIVE|PRIV_BEQUEATH, - &priv, sizeof(priv_t)) < 0 || - setuidx(ID_REAL|ID_EFFECTIVE, (uid_t)uid) < 0 || - seteuid((uid_t)uid) < 0) - DEBUG(1,("Can't set uid (AIX3)")); - } -#endif - -#ifdef USE_SETRES - if (setresuid(-1,uid,-1) != 0) -#else - if ((seteuid(uid) != 0) && - (setuid(uid) != 0)) -#endif - { - DEBUG(0,("Couldn't set uid %d currently set to (%d,%d)\n", - uid,getuid(), geteuid())); - if (uid > 32000) - DEBUG(0,("Looks like your OS doesn't like high uid values - try using a different account\n")); - return(False); - } - - if (((uid == -1) || (uid == 65535)) && geteuid() != uid) - { - DEBUG(0,("Invalid uid -1. perhaps you have a account with uid 65535?\n")); - return(False); - } - - return(True); -} - - -/**************************************************************************** - become the specified gid -****************************************************************************/ -static BOOL become_gid(int gid) -{ - if (initial_uid != 0) - return(True); - -#ifdef USE_SETRES - if (setresgid(-1,gid,-1) != 0) -#else - if (setgid(gid) != 0) -#endif - { - DEBUG(0,("Couldn't set gid %d currently set to (%d,%d)\n", - gid,getgid(),getegid())); - if (gid > 32000) - DEBUG(0,("Looks like your OS doesn't like high gid values - try using a different account\n")); - return(False); - } - - return(True); -} - - -/**************************************************************************** - become the specified uid and gid -****************************************************************************/ -static BOOL become_id(int uid,int gid) -{ - return(become_gid(gid) && become_uid(uid)); -} - -/**************************************************************************** -become the guest user -****************************************************************************/ -static BOOL become_guest(void) -{ - BOOL ret; - static struct passwd *pass=NULL; - - if (initial_uid != 0) - return(True); - - if (!pass) - pass = Get_Pwnam(lp_guestaccount(-1),True); - if (!pass) return(False); - - ret = become_id(pass->pw_uid,pass->pw_gid); - - if (!ret) - DEBUG(1,("Failed to become guest. Invalid guest account?\n")); - - last_user.cnum = -2; - - return(ret); -} - -/******************************************************************* -check if a username is OK -********************************************************************/ -static BOOL check_user_ok(int cnum,user_struct *vuser,int snum) -{ - int i; - for (i=0;i<Connections[cnum].uid_cache.entries;i++) - if (Connections[cnum].uid_cache.list[i] == vuser->uid) return(True); - - if (!user_ok(vuser->name,snum)) return(False); - - i = Connections[cnum].uid_cache.entries % UID_CACHE_SIZE; - Connections[cnum].uid_cache.list[i] = vuser->uid; - - if (Connections[cnum].uid_cache.entries < UID_CACHE_SIZE) - Connections[cnum].uid_cache.entries++; - - return(True); -} - - -/**************************************************************************** - become the user of a connection number -****************************************************************************/ -BOOL become_user(int cnum, int uid) -{ - int new_umask; - user_struct *vuser; - int snum,gid; - int ngroups; - gid_t *groups; - - if (last_user.cnum == cnum && last_user.uid == uid) { - DEBUG(4,("Skipping become_user - already user\n")); - return(True); - } - - unbecome_user(); - - if (!OPEN_CNUM(cnum)) { - DEBUG(2,("Connection %d not open\n",cnum)); - return(False); - } - - snum = Connections[cnum].service; - - if (Connections[cnum].force_user || - lp_security() == SEC_SHARE || - !(vuser = get_valid_user_struct(uid)) || - !check_user_ok(cnum,vuser,snum)) { - uid = Connections[cnum].uid; - gid = Connections[cnum].gid; - groups = Connections[cnum].groups; - ngroups = Connections[cnum].ngroups; - } else { - if (!vuser) { - DEBUG(2,("Invalid vuid used %d\n",uid)); - return(False); - } - uid = vuser->uid; - if(!*lp_force_group(snum)) - gid = vuser->gid; - else - gid = Connections[cnum].gid; - groups = vuser->user_groups; - ngroups = vuser->user_ngroups; - } - - if (initial_uid == 0) - { - if (!become_gid(gid)) return(False); - -#ifndef NO_SETGROUPS - if (!IS_IPC(cnum)) { - /* groups stuff added by ih/wreu */ - if (ngroups > 0) - if (setgroups(ngroups,groups)<0) - DEBUG(0,("setgroups call failed!\n")); - } -#endif - - if (!Connections[cnum].admin_user && !become_uid(uid)) - return(False); - } - - new_umask = 0777 & ~CREATE_MODE(cnum); - old_umask = umask(new_umask); - - last_user.cnum = cnum; - last_user.uid = uid; - - DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d) new_umask=0%o\n", - getuid(),geteuid(),getgid(),getegid(),new_umask)); - - return(True); -} - -/**************************************************************************** - unbecome the user of a connection number -****************************************************************************/ -BOOL unbecome_user(void ) -{ - if (last_user.cnum == -1) - return(False); - - ChDir(OriginalDir); - - umask(old_umask); - - if (initial_uid == 0) - { -#ifdef USE_SETRES - setresuid(-1,getuid(),-1); - setresgid(-1,getgid(),-1); -#else - if (seteuid(initial_uid) != 0) - setuid(initial_uid); - setgid(initial_gid); -#endif - } -#ifdef NO_EID - if (initial_uid == 0) - DEBUG(2,("Running with no EID\n")); - initial_uid = getuid(); - initial_gid = getgid(); -#else - if (geteuid() != initial_uid) - { - DEBUG(0,("Warning: You appear to have a trapdoor uid system\n")); - initial_uid = geteuid(); - } - if (getegid() != initial_gid) - { - DEBUG(0,("Warning: You appear to have a trapdoor gid system\n")); - initial_gid = getegid(); - } -#endif - - if (ChDir(OriginalDir) != 0) - DEBUG(0,("%s chdir(%s) failed in unbecome_user\n", - timestring(),OriginalDir)); - - DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n", - getuid(),geteuid(),getgid(),getegid())); - - last_user.cnum = -1; - - return(True); -} - -/**************************************************************************** find a service entry ****************************************************************************/ int find_service(char *service) @@ -2120,7 +1582,7 @@ static int sig_cld() } depth++; - BlockSignals(True); + BlockSignals(True,SIGCLD); DEBUG(5,("got SIGCLD\n")); #ifdef USE_WAITPID @@ -2146,7 +1608,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 @@ -2181,7 +1643,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); @@ -2206,7 +1668,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 @@ -2222,6 +1684,9 @@ static BOOL open_sockets(BOOL is_daemon,int port) 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(); @@ -2299,6 +1764,8 @@ BOOL reload_services(BOOL test) reopen_logs(); + load_interfaces(); + { extern int Client; if (Client != -1) { @@ -2322,13 +1789,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); } @@ -2633,7 +2100,8 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de if (ChDir(pcon->connectpath) != 0) { - DEBUG(0,("Can't change directory to %s\n",pcon->connectpath)); + DEBUG(0,("Can't change directory to %s (%s)\n", + pcon->connectpath,strerror(errno))); pcon->open = False; unbecome_user(); if (!IS_IPC(cnum)) { @@ -2694,6 +2162,8 @@ 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;i<MAX_OPEN_FILES;i++) if (!Files[i].open) return(i); @@ -2864,6 +2334,7 @@ int reply_nt1(char *outbuf) int capabilities=0x300; /* has dual names + lock_and_read */ int secword=0; BOOL doencrypt = SMBENCRYPT(); + time_t t = time(NULL); if (lp_security()>=SEC_USER) secword |= 1; if (doencrypt) secword |= 2; @@ -2898,8 +2369,8 @@ int reply_nt1(char *outbuf) SIVAL(outbuf,smb_vwv3+1,0xFFFF); /* max buffer */ SIVAL(outbuf,smb_vwv5+1,0xFFFF); /* raw size */ SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */ - put_long_date(outbuf+smb_vwv11+1,time(NULL)); - SSVALS(outbuf,smb_vwv15+1,TimeDiff(time(NULL))/60); + put_long_date(outbuf+smb_vwv11+1,t); + SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60); return (smb_len(outbuf)+4); } @@ -3538,7 +3009,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}, @@ -3553,7 +3024,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}, @@ -3581,7 +3052,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}, @@ -3686,8 +3157,17 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize 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,uid)) { + 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)) @@ -3739,103 +3219,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) -{ - 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; + construct a chained reply and add it to the already made reply + **************************************************************************/ +int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) +{ + 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_outbuf,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 first part of the SMB */ + memmove(inbuf2,orig_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); + outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size, + 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)); + memmove(orig_outbuf,outbuf2,smb_wct); + CVAL(orig_outbuf,smb_com) = smb_com1; - /* and copy the data from the reply to the right spot */ - memcpy(outbuf2,obuf+smb_wct,outsize - smb_wct); - - /* 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; } @@ -3848,10 +3324,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); @@ -3875,6 +3353,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); @@ -3884,7 +3364,7 @@ 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; @@ -3908,12 +3388,10 @@ 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 - last_user.cnum = -1; - while (True) { int32 len; @@ -3959,9 +3437,14 @@ void process(void ) BOOL allidle = True; extern int keepalive; - /* check for socket failure */ - if (errno == EBADF) { - DEBUG(3,("%s Bad file descriptor - exiting\n",timestring())); + 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; } @@ -3980,7 +3463,7 @@ void process(void ) /* clean the share modes every 5 minutes */ if (!(counter%SHARE_MODES_CLEAN)) - clean_share_files(); + clean_share_modes(); /* automatic timeout if all connections are closed */ if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) { @@ -3989,10 +3472,15 @@ void process(void ) } 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; } @@ -4064,7 +3552,7 @@ void process(void ) static void init_structs(void ) { int i; - get_myname(myhostname,&myip); + get_myname(myhostname,NULL); for (i=0;i<MAX_CONNECTIONS;i++) { @@ -4090,7 +3578,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")); @@ -4110,12 +3598,12 @@ 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; @@ -4152,22 +3640,7 @@ int main(int argc,char *argv[]) umask(0777 & ~DEF_CREATE_MASK); - initial_uid = geteuid(); - initial_gid = getegid(); - - if (initial_gid != 0 && initial_uid == 0) - { -#ifdef HPUX - setresgid(0,0,0); -#else - setgid(0); - setegid(0); -#endif - } - - initial_uid = geteuid(); - initial_gid = getegid(); - + init_uid(); /* this is for people who can't start the program correctly */ while (argc > 1 && (*argv[1] != '-')) @@ -4229,8 +3702,6 @@ int main(int argc,char *argv[]) DEBUG(2,("%s smbd version %s started\n",timestring(),VERSION)); DEBUG(2,("Copyright Andrew Tridgell 1992-1995\n")); - GetWd(OriginalDir); - #ifndef NO_GETRLIMIT #ifdef RLIMIT_NOFILE { @@ -4277,22 +3748,32 @@ int main(int argc,char *argv[]) become_daemon(); } - if (open_sockets(is_daemon,port)) - { - /* possibly reload the services file. */ - reload_services(True); + if (!open_sockets(is_daemon,port)) + exit(1); - maxxmit = MIN(lp_maxxmit(),BUFFER_SIZE); +#if FAST_SHARE_MODES + if (!start_share_mode_mgmt()) + exit(1); +#endif - if (*lp_rootdir()) - { - if (sys_chroot(lp_rootdir()) == 0) - DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir())); - } + /* possibly reload the services file. */ + reload_services(True); - process(); - close_sockets(); + maxxmit = MIN(lp_maxxmit(),BUFFER_SIZE); + + if (*lp_rootdir()) + { + if (sys_chroot(lp_rootdir()) == 0) + DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir())); } + + process(); + close_sockets(); + +#if FAST_SHARE_MODES + stop_share_mode_mgmt(); +#endif + exit_server("normal exit"); return(0); } |