diff options
Diffstat (limited to 'source/smbd')
-rw-r--r-- | source/smbd/chgpasswd.c | 400 | ||||
-rw-r--r-- | source/smbd/dir.c | 996 | ||||
-rw-r--r-- | source/smbd/ipc.c | 3133 | ||||
-rw-r--r-- | source/smbd/mangle.c | 673 | ||||
-rw-r--r-- | source/smbd/message.c | 201 | ||||
-rw-r--r-- | source/smbd/password.c | 1707 | ||||
-rw-r--r-- | source/smbd/pipes.c | 1196 | ||||
-rw-r--r-- | source/smbd/predict.c | 158 | ||||
-rw-r--r-- | source/smbd/quotas.c | 657 | ||||
-rw-r--r-- | source/smbd/reply.c | 3821 | ||||
-rw-r--r-- | source/smbd/server.c | 5024 | ||||
-rw-r--r-- | source/smbd/smbrun.c | 97 | ||||
-rw-r--r-- | source/smbd/trans2.c | 1794 | ||||
-rw-r--r-- | source/smbd/uid.c | 478 | ||||
-rw-r--r-- | source/smbd/vt_mode.c | 490 |
15 files changed, 0 insertions, 20825 deletions
diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c deleted file mode 100644 index bed81138b24..00000000000 --- a/source/smbd/chgpasswd.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - Samba utility functions - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* fork a child process to exec passwd and write to its -* tty to change a users password. This is running as the -* user who is attempting to change the password. -*/ - -/* - * This code was copied/borrowed and stolen from various sources. - * The primary source was the poppasswd.c from the authors of POPMail. This software - * was included as a client to change passwords using the 'passwd' program - * on the remote machine. - * - * This routine is called by set_user_password() in password.c only if ALLOW_PASSWORD_CHANGE - * is defined in the compiler directives located in the Makefile. - * - * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson - * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences - * and rights to modify, distribute or incorporate this change to the CAP suite or - * using it for any other reason are granted, so long as this disclaimer is left intact. - */ - -/* - This code was hacked considerably for inclusion in Samba, primarily - by Andrew.Tridgell@anu.edu.au. The biggest change was the addition - of the "password chat" option, which allows the easy runtime - specification of the expected sequence of events to change a - password. - */ - -#include "includes.h" - -extern int DEBUGLEVEL; - -#ifdef ALLOW_CHANGE_PASSWORD - -#define MINPASSWDLENGTH 5 -#define BUFSIZE 512 - -static int findpty(char **slave) -{ - int master; -#if defined(SVR4) || defined(SUNOS5) - extern char *ptsname(); -#else /* defined(SVR4) || defined(SUNOS5) */ - static char line[12]; - void *dirp; - char *dpname; -#endif /* defined(SVR4) || defined(SUNOS5) */ - -#if defined(SVR4) || defined(SUNOS5) - if ((master = open("/dev/ptmx", O_RDWR)) >= 1) { - grantpt(master); - unlockpt(master); - *slave = ptsname(master); - return (master); - } -#else /* defined(SVR4) || defined(SUNOS5) */ - strcpy( line, "/dev/ptyXX" ); - - dirp = OpenDir(-1, "/dev", True); - if (!dirp) return(-1); - while ((dpname = ReadDirName(dirp)) != NULL) { - if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) { - DEBUG(3,("pty: try to open %s, line was %s\n", dpname, line ) ); - line[8] = dpname[3]; - line[9] = dpname[4]; - if ((master = open(line, O_RDWR)) >= 0) { - DEBUG(3,("pty: opened %s\n", line ) ); - line[5] = 't'; - *slave = line; - CloseDir(dirp); - return (master); - } - } - } - CloseDir(dirp); -#endif /* defined(SVR4) || defined(SUNOS5) */ - return (-1); -} - -static int dochild(int master,char *slavedev, char *name, char *passwordprogram) -{ - int slave; - struct termios stermios; - struct passwd *pass = Get_Pwnam(name,True); - int gid = pass->pw_gid; - int uid = pass->pw_uid; - -#ifdef USE_SETRES - setresuid(0,0,0); -#else /* USE_SETRES */ - setuid(0); -#endif /* USE_SETRES */ - - /* Start new session - gets rid of controlling terminal. */ - if (setsid() < 0) { - DEBUG(3,("Weirdness, couldn't let go of controlling terminal\n")); - return(False); - } - - /* Open slave pty and acquire as new controlling terminal. */ - if ((slave = open(slavedev, O_RDWR)) < 0) { - DEBUG(3,("More weirdness, could not open %s\n", - slavedev)); - return(False); - } -#if defined(SVR4) || defined(SUNOS5) - ioctl(slave, I_PUSH, "ptem"); - ioctl(slave, I_PUSH, "ldterm"); -#else /* defined(SVR4) || defined(SUNOS5) */ - if (ioctl(slave,TIOCSCTTY,0) <0) { - DEBUG(3,("Error in ioctl call for slave pty\n")); - /* return(False); */ - } -#endif /* defined(SVR4) || defined(SUNOS5) */ - - /* Close master. */ - close(master); - - /* Make slave stdin/out/err of child. */ - - if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) { - DEBUG(3,("Could not re-direct stdin\n")); - return(False); - } - if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) { - DEBUG(3,("Could not re-direct stdout\n")); - return(False); - } - if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) { - DEBUG(3,("Could not re-direct stderr\n")); - return(False); - } - if (slave > 2) close(slave); - - /* Set proper terminal attributes - no echo, canonical input processing, - no map NL to CR/NL on output. */ - - if (tcgetattr(0, &stermios) < 0) { - DEBUG(3,("could not read default terminal attributes on pty\n")); - return(False); - } - stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); - stermios.c_lflag |= ICANON; - stermios.c_oflag &= ~(ONLCR); - if (tcsetattr(0, TCSANOW, &stermios) < 0) { - DEBUG(3,("could not set attributes of pty\n")); - return(False); - } - - /* make us completely into the right uid */ -#ifdef USE_SETRES - setresgid(0,0,0); - setresuid(0,0,0); - setresgid(gid,gid,gid); - setresuid(uid,uid,uid); -#else - setuid(0); - seteuid(0); - setgid(gid); - setegid(gid); - setuid(uid); - seteuid(uid); -#endif - - /* execl() password-change application */ - if (execl("/bin/sh","sh","-c",passwordprogram,NULL) < 0) { - DEBUG(3,("Bad status returned from %s\n",passwordprogram)); - return(False); - } - return(True); -} - -static int expect(int master,char *expected,char *buf) -{ - int n, m; - - n = 0; - buf[0] = 0; - while (1) { - if (n >= BUFSIZE-1) { - return False; - } - - /* allow 4 seconds for some output to appear */ - m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000); - if (m < 0) - return False; - - n += m; - buf[n] = 0; - - { - pstring s1,s2; - pstrcpy(s1,buf); - pstrcpy(s2,expected); - if (do_match(s1, s2, False)) - return(True); - } - } -} - -static void pwd_sub(char *buf) -{ - string_sub(buf,"\\n","\n"); - string_sub(buf,"\\r","\r"); - string_sub(buf,"\\s"," "); - string_sub(buf,"\\t","\t"); -} - -static void writestring(int fd,char *s) -{ - int l; - - l = strlen (s); - write (fd, s, l); -} - - -static int talktochild(int master, char *chatsequence) -{ - char buf[BUFSIZE]; - int count=0; - char *ptr=chatsequence; - fstring chatbuf; - - *buf = 0; - sleep(1); - - while (next_token(&ptr,chatbuf,NULL)) { - BOOL ok=True; - count++; - pwd_sub(chatbuf); - if (!strequal(chatbuf,".")) - ok = expect(master,chatbuf,buf); - -#if DEBUG_PASSWORD - DEBUG(100,("chatbuf=[%s] responsebuf=[%s]\n",chatbuf,buf)); -#endif - - if (!ok) { - DEBUG(3,("response %d incorrect\n",count)); - return(False); - } - - if (!next_token(&ptr,chatbuf,NULL)) break; - pwd_sub(chatbuf); - if (!strequal(chatbuf,".")) - writestring(master,chatbuf); - -#if DEBUG_PASSWORD - DEBUG(100,("sendbuf=[%s]\n",chatbuf)); -#endif - } - - if (count<1) return(False); - - return (True); -} - - -BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence) -{ - char *slavedev; - int master; - pid_t pid, wpid; - int wstat; - BOOL chstat; - - /* allocate a pseudo-terminal device */ - if ((master = findpty (&slavedev)) < 0) { - DEBUG(3,("Cannot Allocate pty for password change: %s",name)); - return(False); - } - - if ((pid = fork()) < 0) { - DEBUG(3,("Cannot fork() child for password change: %s",name)); - return(False); - } - - /* we now have a pty */ - if (pid > 0){ /* This is the parent process */ - if ((chstat = talktochild(master, chatsequence)) == False) { - DEBUG(3,("Child failed to change password: %s\n",name)); - kill(pid, SIGKILL); /* be sure to end this process */ - return(False); - } - if ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) { - DEBUG(3,("The process is no longer waiting!\n\n")); - return(False); - } - if (pid != wpid) { - DEBUG(3,("We were waiting for the wrong process ID\n")); - return(False); - } - if (WIFEXITED(wstat) == 0) { - DEBUG(3,("The process exited while we were waiting\n")); - return(False); - } - if (WEXITSTATUS(wstat) != 0) { - DEBUG(3,("The status of the process exiting was %d\n", wstat)); - return(False); - } - - } else { - /* CHILD */ - - /* make sure it doesn't freeze */ - alarm(20); - - DEBUG(3,("Dochild for user %s (uid=%d,gid=%d)\n",name,getuid(),getgid())); - chstat = dochild(master, slavedev, name, passwordprogram); - } - DEBUG(3,("Password change %ssuccessful for user %s\n", (chstat?"":"un"), name)); - return (chstat); -} - - -BOOL chgpasswd(char *name,char *oldpass,char *newpass) -{ - pstring passwordprogram; - pstring chatsequence; - - strlower(name); - DEBUG(3,("Password change for user: %s\n",name)); - -#if DEBUG_PASSWORD - DEBUG(100,("Passwords: old=%s new=%s\n",oldpass,newpass)); -#endif - - /* Take the passed information and test it for minimum criteria */ - /* Minimum password length */ - if (strlen(newpass) < MINPASSWDLENGTH) /* too short, must be at least MINPASSWDLENGTH */ - { - DEBUG(2,("Password Change: %s, New password is shorter than MINPASSWDLENGTH\n",name)); - return (False); /* inform the user */ - } - - /* Password is same as old password */ - if (strcmp(oldpass,newpass) == 0) /* don't allow same password */ - { - DEBUG(2,("Password Change: %s, New password is same as old\n",name)); /* log the attempt */ - return (False); /* inform the user */ - } - -#if (defined(PASSWD_PROGRAM) && defined(PASSWD_CHAT)) - pstrcpy(passwordprogram,PASSWD_PROGRAM); - pstrcpy(chatsequence,PASSWD_CHAT); -#else - pstrcpy(passwordprogram,lp_passwd_program()); - pstrcpy(chatsequence,lp_passwd_chat()); -#endif - - if (!*chatsequence) { - DEBUG(2,("Null chat sequence - no password changing\n")); - return(False); - } - - if (!*passwordprogram) { - DEBUG(2,("Null password program - no password changing\n")); - return(False); - } - - string_sub(passwordprogram,"%u",name); - string_sub(passwordprogram,"%o",oldpass); - string_sub(passwordprogram,"%n",newpass); - - string_sub(chatsequence,"%u",name); - string_sub(chatsequence,"%o",oldpass); - string_sub(chatsequence,"%n",newpass); - return(chat_with_program(passwordprogram,name,chatsequence)); -} - -#else -BOOL chgpasswd(char *name,char *oldpass,char *newpass) -{ - DEBUG(0,("Password changing not compiled in (user=%s)\n",name)); - return(False); -} -#endif diff --git a/source/smbd/dir.c b/source/smbd/dir.c deleted file mode 100644 index 316b58818fd..00000000000 --- a/source/smbd/dir.c +++ /dev/null @@ -1,996 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - Directory handling routines - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -extern int DEBUGLEVEL; -extern connection_struct Connections[]; - -/* - This module implements directory related functions for Samba. -*/ - - - -uint32 dircounter = 0; - - -#define NUMDIRPTRS 256 - - -static struct dptr_struct -{ - int pid; - int cnum; - uint32 lastused; - void *ptr; - BOOL valid; - BOOL finished; - BOOL expect_close; - char *wcard; /* Field only used for lanman2 trans2_findfirst/next searches */ - uint16 attr; /* Field only used for lanman2 trans2_findfirst/next searches */ - char *path; -} -dirptrs[NUMDIRPTRS]; - - -static int dptrs_open = 0; - -/**************************************************************************** -initialise the dir array -****************************************************************************/ -void init_dptrs(void) -{ - static BOOL dptrs_init=False; - int i; - - if (dptrs_init) return; - for (i=0;i<NUMDIRPTRS;i++) - { - dirptrs[i].valid = False; - dirptrs[i].wcard = NULL; - dirptrs[i].ptr = NULL; - string_init(&dirptrs[i].path,""); - } - dptrs_init = True; -} - -/**************************************************************************** -idle a dptr - the directory is closed but the control info is kept -****************************************************************************/ -static void dptr_idle(int key) -{ - if (dirptrs[key].valid && dirptrs[key].ptr) { - DEBUG(4,("Idling dptr key %d\n",key)); - dptrs_open--; - CloseDir(dirptrs[key].ptr); - dirptrs[key].ptr = NULL; - } -} - -/**************************************************************************** -idle the oldest dptr -****************************************************************************/ -static void dptr_idleoldest(void) -{ - int i; - uint32 old=dircounter+1; - int oldi= -1; - for (i=0;i<NUMDIRPTRS;i++) - if (dirptrs[i].valid && dirptrs[i].ptr && dirptrs[i].lastused < old) { - old = dirptrs[i].lastused; - oldi = i; - } - if (oldi != -1) - dptr_idle(oldi); - else - DEBUG(0,("No dptrs available to idle??\n")); -} - -/**************************************************************************** -get the dir ptr for a dir index -****************************************************************************/ -static void *dptr_get(int key,uint32 lastused) -{ - struct dptr_struct *dp = &dirptrs[key]; - - if (dp->valid) { - if (lastused) dp->lastused = lastused; - if (!dp->ptr) { - if (dptrs_open >= MAXDIR) - dptr_idleoldest(); - DEBUG(4,("Reopening dptr key %d\n",key)); - if ((dp->ptr = OpenDir(dp->cnum, dp->path, True))) - dptrs_open++; - } - return(dp->ptr); - } - return(NULL); -} - -/**************************************************************************** -get the dir path for a dir index -****************************************************************************/ -char *dptr_path(int key) -{ - if (dirptrs[key].valid) - return(dirptrs[key].path); - return(NULL); -} - -/**************************************************************************** -get the dir wcard for a dir index (lanman2 specific) -****************************************************************************/ -char *dptr_wcard(int key) -{ - if (dirptrs[key].valid) - return(dirptrs[key].wcard); - return(NULL); -} - -/**************************************************************************** -set the dir wcard for a dir index (lanman2 specific) -Returns 0 on ok, 1 on fail. -****************************************************************************/ -BOOL dptr_set_wcard(int key, char *wcard) -{ - if (dirptrs[key].valid) { - dirptrs[key].wcard = wcard; - return True; - } - return False; -} - -/**************************************************************************** -set the dir attrib for a dir index (lanman2 specific) -Returns 0 on ok, 1 on fail. -****************************************************************************/ -BOOL dptr_set_attr(int key, uint16 attr) -{ - if (dirptrs[key].valid) { - dirptrs[key].attr = attr; - return True; - } - return False; -} - -/**************************************************************************** -get the dir attrib for a dir index (lanman2 specific) -****************************************************************************/ -uint16 dptr_attr(int key) -{ - if (dirptrs[key].valid) - return(dirptrs[key].attr); - return(0); -} - -/**************************************************************************** -close a dptr -****************************************************************************/ -void dptr_close(int key) -{ - /* OS/2 seems to use -1 to indicate "close all directories" */ - if (key == -1) { - int i; - for (i=0;i<NUMDIRPTRS;i++) - dptr_close(i); - return; - } - - if (key < 0 || key >= NUMDIRPTRS) { - DEBUG(3,("Invalid key %d given to dptr_close\n",key)); - return; - } - - if (dirptrs[key].valid) { - DEBUG(4,("closing dptr key %d\n",key)); - if (dirptrs[key].ptr) { - CloseDir(dirptrs[key].ptr); - dptrs_open--; - } - /* Lanman 2 specific code */ - if (dirptrs[key].wcard) - free(dirptrs[key].wcard); - dirptrs[key].valid = False; - string_set(&dirptrs[key].path,""); - } -} - -/**************************************************************************** -close all dptrs for a cnum -****************************************************************************/ -void dptr_closecnum(int cnum) -{ - int i; - for (i=0;i<NUMDIRPTRS;i++) - if (dirptrs[i].valid && dirptrs[i].cnum == cnum) - dptr_close(i); -} - -/**************************************************************************** -idle all dptrs for a cnum -****************************************************************************/ -void dptr_idlecnum(int cnum) -{ - int i; - for (i=0;i<NUMDIRPTRS;i++) - if (dirptrs[i].valid && dirptrs[i].cnum == cnum && dirptrs[i].ptr) - dptr_idle(i); -} - -/**************************************************************************** -close a dptr that matches a given path, only if it matches the pid also -****************************************************************************/ -void dptr_closepath(char *path,int pid) -{ - int i; - for (i=0;i<NUMDIRPTRS;i++) - if (dirptrs[i].valid && pid == dirptrs[i].pid && - strequal(dirptrs[i].path,path)) - dptr_close(i); -} - -/**************************************************************************** - start a directory listing -****************************************************************************/ -static BOOL start_dir(int cnum,char *directory) -{ - DEBUG(5,("start_dir cnum=%d dir=%s\n",cnum,directory)); - - if (!check_name(directory,cnum)) - return(False); - - if (! *directory) - directory = "."; - - Connections[cnum].dirptr = OpenDir(cnum, directory, True); - if (Connections[cnum].dirptr) { - dptrs_open++; - string_set(&Connections[cnum].dirpath,directory); - return(True); - } - - return(False); -} - - -/**************************************************************************** -create a new dir ptr -****************************************************************************/ -int dptr_create(int cnum,char *path, BOOL expect_close,int pid) -{ - int i; - uint32 old; - int oldi; - - if (!start_dir(cnum,path)) - return(-2); /* Code to say use a unix error return code. */ - - if (dptrs_open >= MAXDIR) - dptr_idleoldest(); - - for (i=0;i<NUMDIRPTRS;i++) - if (!dirptrs[i].valid) - break; - if (i == NUMDIRPTRS) i = -1; - - - /* as a 2nd option, grab the oldest not marked for expect_close */ - if (i == -1) { - old=dircounter+1; - oldi= -1; - for (i=0;i<NUMDIRPTRS;i++) - if (!dirptrs[i].expect_close && dirptrs[i].lastused < old) { - old = dirptrs[i].lastused; - oldi = i; - } - i = oldi; - } - - /* a 3rd option - grab the oldest one */ - if (i == -1) { - old=dircounter+1; - oldi= -1; - for (i=0;i<NUMDIRPTRS;i++) - if (dirptrs[i].lastused < old) { - old = dirptrs[i].lastused; - oldi = i; - } - i = oldi; - } - - if (i == -1) { - DEBUG(0,("Error - all dirptrs in use??\n")); - return(-1); - } - - if (dirptrs[i].valid) - dptr_close(i); - - dirptrs[i].ptr = Connections[cnum].dirptr; - string_set(&dirptrs[i].path,path); - dirptrs[i].lastused = dircounter++; - dirptrs[i].finished = False; - dirptrs[i].cnum = cnum; - dirptrs[i].pid = pid; - dirptrs[i].expect_close = expect_close; - dirptrs[i].wcard = NULL; /* Only used in lanman2 searches */ - dirptrs[i].attr = 0; /* Only used in lanman2 searches */ - dirptrs[i].valid = True; - - DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n", - i,path,expect_close)); - - return(i); -} - -#define DPTR_MASK ((uint32)(((uint32)1)<<31)) - -/**************************************************************************** -fill the 5 byte server reserved dptr field -****************************************************************************/ -BOOL dptr_fill(char *buf1,unsigned int key) -{ - unsigned char *buf = (unsigned char *)buf1; - void *p = dptr_get(key,0); - uint32 offset; - if (!p) { - DEBUG(1,("filling null dirptr %d\n",key)); - return(False); - } - offset = TellDir(p); - DEBUG(6,("fill on key %d dirptr 0x%x now at %d\n",key,p,offset)); - buf[0] = key; - SIVAL(buf,1,offset | DPTR_MASK); - return(True); -} - - -/**************************************************************************** -return True is the offset is at zero -****************************************************************************/ -BOOL dptr_zero(char *buf) -{ - return((IVAL(buf,1)&~DPTR_MASK) == 0); -} - -/**************************************************************************** -fetch the dir ptr and seek it given the 5 byte server field -****************************************************************************/ -void *dptr_fetch(char *buf,int *num) -{ - unsigned int key = *(unsigned char *)buf; - void *p = dptr_get(key,dircounter++); - uint32 offset; - if (!p) { - DEBUG(3,("fetched null dirptr %d\n",key)); - return(NULL); - } - *num = key; - offset = IVAL(buf,1)&~DPTR_MASK; - SeekDir(p,offset); - DEBUG(3,("fetching dirptr %d for path %s at offset %d\n", - key,dptr_path(key),offset)); - return(p); -} - -/**************************************************************************** -fetch the dir ptr and seek it given the lanman2 parameter block -****************************************************************************/ -void *dptr_fetch_lanman2(char *params,int dptr_num) -{ - void *p = dptr_get(dptr_num,dircounter++); - uint32 resume_key = SVAL(params,6); - BOOL uses_resume_key = BITSETW(params+10,2); - BOOL continue_bit = BITSETW(params+10,3); - - if (!p) { - DEBUG(3,("fetched null dirptr %d\n",dptr_num)); - return(NULL); - } - if(uses_resume_key && !continue_bit) - SeekDir(p,resume_key); - DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num))); - return(p); -} - -/**************************************************************************** -check a filetype for being valid -****************************************************************************/ -BOOL dir_check_ftype(int cnum,int mode,struct stat *st,int dirtype) -{ - if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0) - return False; - return True; -} - -/**************************************************************************** - get a directory entry -****************************************************************************/ -BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend) -{ - char *dname; - BOOL found = False; - struct stat sbuf; - pstring path; - pstring pathreal; - BOOL isrootdir; - pstring filename; - BOOL matched; - BOOL needslash; - - *path = *pathreal = *filename = 0; - - isrootdir = (strequal(Connections[cnum].dirpath,"./") || - strequal(Connections[cnum].dirpath,".") || - strequal(Connections[cnum].dirpath,"/")); - - needslash = - ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/'); - - if (!Connections[cnum].dirptr) - return(False); - - while (!found) - { - dname = ReadDirName(Connections[cnum].dirptr); - - DEBUG(6,("readdir on dirptr 0x%x now at offset %d\n", - Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr))); - - if (dname == NULL) - return(False); - - matched = False; - - pstrcpy(filename,dname); - - if ((strcmp(filename,mask) == 0) || - (name_map_mangle(filename,True,SNUM(cnum)) && - mask_match(filename,mask,False,False))) - { - if (isrootdir && (strequal(filename,"..") || strequal(filename,"."))) - continue; - - pstrcpy(fname,filename); - *path = 0; - pstrcpy(path,Connections[cnum].dirpath); - if(needslash) - strcat(path,"/"); - pstrcpy(pathreal,path); - strcat(path,fname); - strcat(pathreal,dname); - if (sys_stat(pathreal,&sbuf) != 0) - { - DEBUG(5,("Couldn't stat 1 [%s]\n",path)); - continue; - } - - if (check_descend && - !strequal(fname,".") && !strequal(fname,"..")) - continue; - - *mode = dos_mode(cnum,pathreal,&sbuf); - - if (!dir_check_ftype(cnum,*mode,&sbuf,dirtype)) { - DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype)); - continue; - } - - *size = sbuf.st_size; - *date = sbuf.st_mtime; - - DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname)); - - found = True; - } - } - - return(found); -} - - - -typedef struct -{ - int pos; - int numentries; - int mallocsize; - char *data; - char *current; -} Dir; - - -/******************************************************************* -open a directory -********************************************************************/ -void *OpenDir(int cnum, char *name, BOOL use_veto) -{ - Dir *dirp; - char *n; - void *p = sys_opendir(name); - int used=0; - - if (!p) return(NULL); - dirp = (Dir *)malloc(sizeof(Dir)); - if (!dirp) { - closedir(p); - return(NULL); - } - dirp->pos = dirp->numentries = dirp->mallocsize = 0; - dirp->data = dirp->current = NULL; - - while ((n = readdirname(p))) - { - int l = strlen(n)+1; - - /* If it's a vetoed file, pretend it doesn't even exist */ - if (use_veto && IS_VETO_PATH(cnum, n)) continue; - - if (used + l > dirp->mallocsize) { - int s = MAX(used+l,used+2000); - char *r; - r = (char *)Realloc(dirp->data,s); - if (!r) { - DEBUG(0,("Out of memory in OpenDir\n")); - break; - } - dirp->data = r; - dirp->mallocsize = s; - dirp->current = dirp->data; - } - strcpy(dirp->data+used,n); - used += l; - dirp->numentries++; - } - - closedir(p); - return((void *)dirp); -} - - -/******************************************************************* -close a directory -********************************************************************/ -void CloseDir(void *p) -{ - Dir *dirp = (Dir *)p; - if (!dirp) return; - if (dirp->data) free(dirp->data); - free(dirp); -} - -/******************************************************************* -read from a directory -********************************************************************/ -char *ReadDirName(void *p) -{ - char *ret; - Dir *dirp = (Dir *)p; - - if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL); - - ret = dirp->current; - dirp->current = skip_string(dirp->current,1); - dirp->pos++; - - return(ret); -} - - -/******************************************************************* -seek a dir -********************************************************************/ -BOOL SeekDir(void *p,int pos) -{ - Dir *dirp = (Dir *)p; - - if (!dirp) return(False); - - if (pos < dirp->pos) { - dirp->current = dirp->data; - dirp->pos = 0; - } - - while (dirp->pos < pos && ReadDirName(p)) ; - - return(dirp->pos == pos); -} - -/******************************************************************* -tell a dir position -********************************************************************/ -int TellDir(void *p) -{ - Dir *dirp = (Dir *)p; - - if (!dirp) return(-1); - - return(dirp->pos); -} - - -static int dir_cache_size = 0; -static struct dir_cache { - struct dir_cache *next; - struct dir_cache *prev; - char *path; - char *name; - char *dname; - int snum; -} *dir_cache = NULL; - -/******************************************************************* -add an entry to the directory cache -********************************************************************/ -void DirCacheAdd(char *path,char *name,char *dname,int snum) -{ - int count; - struct dir_cache *entry = (struct dir_cache *)malloc(sizeof(*entry)); - if (!entry) return; - entry->path = strdup(path); - entry->name = strdup(name); - entry->dname = strdup(dname); - entry->snum = snum; - if (!entry->path || !entry->name || !entry->dname) return; - - entry->next = dir_cache; - entry->prev = NULL; - if (entry->next) entry->next->prev = entry; - dir_cache = entry; - - DEBUG(4,("Added dir cache entry %s %s -> %s\n",path,name,dname)); - - if (dir_cache_size == DIRCACHESIZE) { - for (entry=dir_cache, count=1; - entry->next && count < dir_cache_size + 1; - entry=entry->next, count++) ; - if (entry->next || count != dir_cache_size + 1) { - DEBUG(0,("DirCache bug - please report %d %d\n",dir_cache_size,count)); - } - free(entry->path); - free(entry->name); - free(entry->dname); - if (entry->prev) entry->prev->next = entry->next; - free(entry); - } else { - dir_cache_size++; - } -} - - -/******************************************************************* -check for an entry in the directory cache -********************************************************************/ -char *DirCacheCheck(char *path,char *name,int snum) -{ - struct dir_cache *entry; - - for (entry=dir_cache; entry; entry=entry->next) { - if (entry->snum == snum && - strcmp(path,entry->path) == 0 && - strcmp(name,entry->name) == 0) { - DEBUG(4,("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname)); - return(entry->dname); - } - } - - return(NULL); -} - -/******************************************************************* -flush entries in the dir_cache -********************************************************************/ -void DirCacheFlush(int snum) -{ - struct dir_cache *entry,*next; - - for (entry=dir_cache; entry; entry=next) { - if (entry->snum == snum) { - free(entry->path); - free(entry->dname); - free(entry->name); - next = entry->next; - if (entry->prev) entry->prev->next = entry->next; - if (entry->next) entry->next->prev = entry->prev; - if (dir_cache == entry) dir_cache = entry->next; - free(entry); - dir_cache_size--; - } else { - next = entry->next; - } - } -} - - -#ifdef REPLACE_GETWD -/* This is getcwd.c from bash. It is needed in Interactive UNIX. To - * add support for another OS you need to determine which of the - * conditional compilation macros you need to define. All the options - * are defined for Interactive UNIX. - */ -#ifdef ISC -#define HAVE_UNISTD_H -#define USGr3 -#define USG -#endif - -#if defined (HAVE_UNISTD_H) -# include <unistd.h> -#endif - -#if defined (__STDC__) -# define CONST const -# define PTR void * -#else /* !__STDC__ */ -# define CONST -# define PTR char * -#endif /* !__STDC__ */ - -#if !defined (PATH_MAX) -# if defined (MAXPATHLEN) -# define PATH_MAX MAXPATHLEN -# else /* !MAXPATHLEN */ -# define PATH_MAX 1024 -# endif /* !MAXPATHLEN */ -#endif /* !PATH_MAX */ - -#if defined (_POSIX_VERSION) || defined (USGr3) || defined (HAVE_DIRENT_H) -# if !defined (HAVE_DIRENT) -# define HAVE_DIRENT -# endif /* !HAVE_DIRENT */ -#endif /* _POSIX_VERSION || USGr3 || HAVE_DIRENT_H */ - -#if defined (HAVE_DIRENT) -# define D_NAMLEN(d) (strlen ((d)->d_name)) -#else -# define D_NAMLEN(d) ((d)->d_namlen) -#endif /* ! (_POSIX_VERSION || USGr3) */ - -#if defined (USG) || defined (USGr3) -# define d_fileno d_ino -#endif - -#if !defined (alloca) -extern char *alloca (); -#endif /* alloca */ - -/* Get the pathname of the current working directory, - and put it in SIZE bytes of BUF. Returns NULL if the - directory couldn't be determined or SIZE was too small. - If successful, returns BUF. In GNU, if BUF is NULL, - an array is allocated with `malloc'; the array is SIZE - bytes long, unless SIZE <= 0, in which case it is as - big as necessary. */ -#if defined (__STDC__) -char * -getcwd (char *buf, size_t size) -#else /* !__STDC__ */ -char * -getcwd (buf, size) - char *buf; - int size; -#endif /* !__STDC__ */ -{ - static CONST char dots[] - = "../../../../../../../../../../../../../../../../../../../../../../../\ -../../../../../../../../../../../../../../../../../../../../../../../../../../\ -../../../../../../../../../../../../../../../../../../../../../../../../../.."; - CONST char *dotp, *dotlist; - size_t dotsize; - dev_t rootdev, thisdev; - ino_t rootino, thisino; - char path[PATH_MAX + 1]; - register char *pathp; - char *pathbuf; - size_t pathsize; - struct stat st; - - if (buf != NULL && size == 0) - { - errno = EINVAL; - return ((char *)NULL); - } - - pathsize = sizeof (path); - pathp = &path[pathsize]; - *--pathp = '\0'; - pathbuf = path; - - if (stat (".", &st) < 0) - return ((char *)NULL); - thisdev = st.st_dev; - thisino = st.st_ino; - - if (stat ("/", &st) < 0) - return ((char *)NULL); - rootdev = st.st_dev; - rootino = st.st_ino; - - dotsize = sizeof (dots) - 1; - dotp = &dots[sizeof (dots)]; - dotlist = dots; - while (!(thisdev == rootdev && thisino == rootino)) - { - register DIR *dirstream; - register struct dirent *d; - dev_t dotdev; - ino_t dotino; - char mount_point; - int namlen; - - /* Look at the parent directory. */ - if (dotp == dotlist) - { - /* My, what a deep directory tree you have, Grandma. */ - char *new; - if (dotlist == dots) - { - new = malloc (dotsize * 2 + 1); - if (new == NULL) - goto lose; - memcpy (new, dots, dotsize); - } - else - { - new = realloc ((PTR) dotlist, dotsize * 2 + 1); - if (new == NULL) - goto lose; - } - memcpy (&new[dotsize], new, dotsize); - dotp = &new[dotsize]; - dotsize *= 2; - new[dotsize] = '\0'; - dotlist = new; - } - - dotp -= 3; - - /* Figure out if this directory is a mount point. */ - if (stat (dotp, &st) < 0) - goto lose; - dotdev = st.st_dev; - dotino = st.st_ino; - mount_point = dotdev != thisdev; - - /* Search for the last directory. */ - dirstream = opendir(dotp); - if (dirstream == NULL) - goto lose; - while ((d = (struct dirent *)readdir(dirstream)) != NULL) - { - if (d->d_name[0] == '.' && - (d->d_name[1] == '\0' || - (d->d_name[1] == '.' && d->d_name[2] == '\0'))) - continue; - if (mount_point || d->d_fileno == thisino) - { - char *name; - - namlen = D_NAMLEN(d); - name = (char *) - alloca (dotlist + dotsize - dotp + 1 + namlen + 1); - memcpy (name, dotp, dotlist + dotsize - dotp); - name[dotlist + dotsize - dotp] = '/'; - memcpy (&name[dotlist + dotsize - dotp + 1], - d->d_name, namlen + 1); - if (lstat (name, &st) < 0) - { - int save = errno; - closedir(dirstream); - errno = save; - goto lose; - } - if (st.st_dev == thisdev && st.st_ino == thisino) - break; - } - } - if (d == NULL) - { - int save = errno; - closedir(dirstream); - errno = save; - goto lose; - } - else - { - size_t space; - - while ((space = pathp - pathbuf) <= namlen) - { - char *new; - - if (pathbuf == path) - { - new = malloc (pathsize * 2); - if (!new) - goto lose; - } - else - { - new = realloc ((PTR) pathbuf, (pathsize * 2)); - if (!new) - goto lose; - pathp = new + space; - } - (void) memcpy (new + pathsize + space, pathp, pathsize - space); - pathp = new + pathsize + space; - pathbuf = new; - pathsize *= 2; - } - - pathp -= namlen; - (void) memcpy (pathp, d->d_name, namlen); - *--pathp = '/'; - closedir(dirstream); - } - - thisdev = dotdev; - thisino = dotino; - } - - if (pathp == &path[sizeof(path) - 1]) - *--pathp = '/'; - - if (dotlist != dots) - free ((PTR) dotlist); - - { - size_t len = pathbuf + pathsize - pathp; - if (buf == NULL) - { - if (len < (size_t) size) - len = size; - buf = (char *) malloc (len); - if (buf == NULL) - goto lose2; - } - else if ((size_t) size < len) - { - errno = ERANGE; - goto lose2; - } - (void) memcpy((PTR) buf, (PTR) pathp, len); - } - - if (pathbuf != path) - free (pathbuf); - - return (buf); - - lose: - if ((dotlist != dots) && dotlist) - { - int e = errno; - free ((PTR) dotlist); - errno = e; - } - - lose2: - if ((pathbuf != path) && pathbuf) - { - int e = errno; - free ((PTR) pathbuf); - errno = e; - } - return ((char *)NULL); -} -#endif diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c deleted file mode 100644 index 28cdb22889a..00000000000 --- a/source/smbd/ipc.c +++ /dev/null @@ -1,3133 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - Inter-process communication and named pipe handling - Copyright (C) Andrew Tridgell 1992-1997 - - SMB Version handling - Copyright (C) John H Terpstra 1995-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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* - This file handles the named pipe and mailslot calls - in the SMBtrans protocol - */ - -#include "includes.h" - -#ifdef CHECK_TYPES -#undef CHECK_TYPES -#endif -#define CHECK_TYPES 0 - -extern int DEBUGLEVEL; -extern int max_send; -extern files_struct Files[]; -extern connection_struct Connections[]; - -extern fstring local_machine; -extern fstring myworkgroup; - -#define NERR_Success 0 -#define NERR_badpass 86 -#define NERR_notsupported 50 - -#define NERR_BASE (2100) -#define NERR_BufTooSmall (NERR_BASE+23) -#define NERR_JobNotFound (NERR_BASE+51) -#define NERR_DestNotFound (NERR_BASE+52) -#define ERROR_INVALID_LEVEL 124 -#define ERROR_MORE_DATA 234 - -#define REALLOC(ptr,size) Realloc(ptr,MAX((size),4*1024)) - -#define ACCESS_READ 0x01 -#define ACCESS_WRITE 0x02 -#define ACCESS_CREATE 0x04 - -#define SHPWLEN 8 /* share password length */ -#define NNLEN 12 /* 8.3 net name length */ -#define SNLEN 15 /* service name length */ -#define QNLEN 12 /* queue name maximum length */ - -extern int Client; - -static BOOL api_Unsupported(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len); -static BOOL api_TooSmall(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len); - - -static int CopyExpanded(int cnum, int snum, char** dst, char* src, int* n) -{ - pstring buf; - int l; - - if (!src || !dst || !n || !(*dst)) return(0); - - StrnCpy(buf,src,sizeof(buf)/2); - string_sub(buf,"%S",lp_servicename(snum)); - standard_sub(cnum,buf); - StrnCpy(*dst,buf,*n); - l = strlen(*dst) + 1; - (*dst) += l; - (*n) -= l; - return l; -} - -static int CopyAndAdvance(char** dst, char* src, int* n) -{ - int l; - if (!src || !dst || !n || !(*dst)) return(0); - StrnCpy(*dst,src,*n); - l = strlen(*dst) + 1; - (*dst) += l; - (*n) -= l; - return l; -} - -static int StrlenExpanded(int cnum, int snum, char* s) -{ - pstring buf; - if (!s) return(0); - StrnCpy(buf,s,sizeof(buf)/2); - string_sub(buf,"%S",lp_servicename(snum)); - standard_sub(cnum,buf); - return strlen(buf) + 1; -} - -static char* Expand(int cnum, int snum, char* s) -{ - static pstring buf; - if (!s) return(NULL); - StrnCpy(buf,s,sizeof(buf)/2); - string_sub(buf,"%S",lp_servicename(snum)); - standard_sub(cnum,buf); - return &buf[0]; -} - -/******************************************************************* - check a API string for validity when we only need to check the prefix - ******************************************************************/ -static BOOL prefix_ok(char *str,char *prefix) -{ - return(strncmp(str,prefix,strlen(prefix)) == 0); -} - - -/**************************************************************************** - send a trans reply - ****************************************************************************/ -static void send_trans_reply(char *outbuf,char *data,char *param,uint16 *setup, - int ldata,int lparam,int lsetup) -{ - int i; - int this_ldata,this_lparam; - int tot_data=0,tot_param=0; - int align; - - this_lparam = MIN(lparam,max_send - (500+lsetup*SIZEOFWORD)); /* hack */ - this_ldata = MIN(ldata,max_send - (500+lsetup*SIZEOFWORD+this_lparam)); - - align = (this_lparam%4); - - set_message(outbuf,10+lsetup,align+this_ldata+this_lparam,True); - if (this_lparam) - memcpy(smb_buf(outbuf),param,this_lparam); - if (this_ldata) - memcpy(smb_buf(outbuf)+this_lparam+align,data,this_ldata); - - SSVAL(outbuf,smb_vwv0,lparam); - SSVAL(outbuf,smb_vwv1,ldata); - SSVAL(outbuf,smb_vwv3,this_lparam); - SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf),outbuf)); - SSVAL(outbuf,smb_vwv5,0); - SSVAL(outbuf,smb_vwv6,this_ldata); - SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+this_lparam+align,outbuf)); - SSVAL(outbuf,smb_vwv8,0); - SSVAL(outbuf,smb_vwv9,lsetup); - for (i=0;i<lsetup;i++) - SSVAL(outbuf,smb_vwv10+i*SIZEOFWORD,setup[i]); - - show_msg(outbuf); - send_smb(Client,outbuf); - - tot_data = this_ldata; - tot_param = this_lparam; - - while (tot_data < ldata || tot_param < lparam) - { - this_lparam = MIN(lparam-tot_param,max_send - 500); /* hack */ - this_ldata = MIN(ldata-tot_data,max_send - (500+this_lparam)); - - align = (this_lparam%4); - - set_message(outbuf,10,this_ldata+this_lparam+align,False); - if (this_lparam) - memcpy(smb_buf(outbuf),param+tot_param,this_lparam); - if (this_ldata) - memcpy(smb_buf(outbuf)+this_lparam+align,data+tot_data,this_ldata); - - SSVAL(outbuf,smb_vwv3,this_lparam); - SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf),outbuf)); - SSVAL(outbuf,smb_vwv5,tot_param); - SSVAL(outbuf,smb_vwv6,this_ldata); - SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+this_lparam+align,outbuf)); - SSVAL(outbuf,smb_vwv8,tot_data); - SSVAL(outbuf,smb_vwv9,0); - - show_msg(outbuf); - send_smb(Client,outbuf); - - tot_data += this_ldata; - tot_param += this_lparam; - } -} - -struct pack_desc { - char* format; /* formatstring for structure */ - char* subformat; /* subformat for structure */ - char* base; /* baseaddress of buffer */ - int buflen; /* remaining size for fixed part; on init: length of base */ - int subcount; /* count of substructures */ - char* structbuf; /* pointer into buffer for remaining fixed part */ - int stringlen; /* remaining size for variable part */ - char* stringbuf; /* pointer into buffer for remaining variable part */ - int neededlen; /* total needed size */ - int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */ - char* curpos; /* current position; pointer into format or subformat */ - int errcode; -}; - -static int get_counter(char** p) -{ - int i, n; - if (!p || !(*p)) return(1); - if (!isdigit(**p)) return 1; - for (n = 0;;) { - i = **p; - if (isdigit(i)) - n = 10 * n + (i - '0'); - else - return n; - (*p)++; - } -} - -static int getlen(char* p) -{ - int n = 0; - if (!p) return(0); - while (*p) { - switch( *p++ ) { - case 'W': /* word (2 byte) */ - n += 2; - break; - case 'N': /* count of substructures (word) at end */ - n += 2; - break; - case 'D': /* double word (4 byte) */ - case 'z': /* offset to zero terminated string (4 byte) */ - case 'l': /* offset to user data (4 byte) */ - n += 4; - break; - case 'b': /* offset to data (with counter) (4 byte) */ - n += 4; - get_counter(&p); - break; - case 'B': /* byte (with optional counter) */ - n += get_counter(&p); - break; - } - } - return n; -} - -static BOOL init_package(struct pack_desc* p, int count, int subcount) -{ - int n = p->buflen; - int i; - - if (!p->format || !p->base) return(False); - - i = count * getlen(p->format); - if (p->subformat) i += subcount * getlen(p->subformat); - p->structbuf = p->base; - p->neededlen = 0; - p->usedlen = 0; - p->subcount = 0; - p->curpos = p->format; - if (i > n) { - i = n = 0; - p->errcode = NERR_BufTooSmall; - } - - p->errcode = NERR_Success; - p->buflen = i; - n -= i; - p->stringbuf = p->base + i; - p->stringlen = n; - return(p->errcode == NERR_Success); -} - -#ifdef __STDC__ -static int package(struct pack_desc* p, ...) -{ -#else -static int package(va_alist) -va_dcl -{ - struct pack_desc* p; -#endif - va_list args; - int needed=0, stringneeded; - char* str=NULL; - int is_string=0, stringused; - int32 temp; - -#ifdef __STDC__ - va_start(args,p); -#else - va_start(args); - p = va_arg(args,struct pack_desc *); -#endif - - if (!*p->curpos) { - if (!p->subcount) - p->curpos = p->format; - else { - p->curpos = p->subformat; - p->subcount--; - } - } -#if CHECK_TYPES - str = va_arg(args,char*); - if (strncmp(str,p->curpos,strlen(str)) != 0) { - DEBUG(2,("type error in package: %s instead of %*s\n",str, - strlen(str),p->curpos)); - va_end(args); -#if AJT - ajt_panic(); -#endif - return 0; - } -#endif - stringneeded = -1; - - if (!p->curpos) return(0); - - switch( *p->curpos++ ) { - case 'W': /* word (2 byte) */ - needed = 2; - temp = va_arg(args,int); - if (p->buflen >= needed) SSVAL(p->structbuf,0,temp); - break; - case 'N': /* count of substructures (word) at end */ - needed = 2; - p->subcount = va_arg(args,int); - if (p->buflen >= needed) SSVAL(p->structbuf,0,p->subcount); - break; - case 'D': /* double word (4 byte) */ - needed = 4; - temp = va_arg(args,int); - if (p->buflen >= needed) SIVAL(p->structbuf,0,temp); - break; - case 'B': /* byte (with optional counter) */ - needed = get_counter(&p->curpos); - { - char *s = va_arg(args,char*); - if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed); - } - break; - case 'z': /* offset to zero terminated string (4 byte) */ - str = va_arg(args,char*); - stringneeded = (str ? strlen(str)+1 : 0); - is_string = 1; - break; - case 'l': /* offset to user data (4 byte) */ - str = va_arg(args,char*); - stringneeded = va_arg(args,int); - is_string = 0; - break; - case 'b': /* offset to data (with counter) (4 byte) */ - str = va_arg(args,char*); - stringneeded = get_counter(&p->curpos); - is_string = 0; - break; - } - va_end(args); - if (stringneeded >= 0) { - needed = 4; - if (p->buflen >= needed) { - stringused = stringneeded; - if (stringused > p->stringlen) { - stringused = (is_string ? p->stringlen : 0); - if (p->errcode == NERR_Success) p->errcode = ERROR_MORE_DATA; - } - if (!stringused) - SIVAL(p->structbuf,0,0); - else { - SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base)); - memcpy(p->stringbuf,str?str:"",stringused); - if (is_string) p->stringbuf[stringused-1] = '\0'; - p->stringbuf += stringused; - p->stringlen -= stringused; - p->usedlen += stringused; - } - } - p->neededlen += stringneeded; - } - p->neededlen += needed; - if (p->buflen >= needed) { - p->structbuf += needed; - p->buflen -= needed; - p->usedlen += needed; - } - else { - if (p->errcode == NERR_Success) p->errcode = NERR_BufTooSmall; - } - return 1; -} - -#if CHECK_TYPES -#define PACK(desc,t,v) package(desc,t,v,0,0,0,0) -#define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0) -#else -#define PACK(desc,t,v) package(desc,v) -#define PACKl(desc,t,v,l) package(desc,v,l) -#endif - -static void PACKI(struct pack_desc* desc,char *t,int v) -{ - PACK(desc,t,v); -} - -static void PACKS(struct pack_desc* desc,char *t,char *v) -{ - PACK(desc,t,v); -} - - -/**************************************************************************** - get a print queue - ****************************************************************************/ - -static void PackDriverData(struct pack_desc* desc) -{ - char drivdata[4+4+32]; - SIVAL(drivdata,0,sizeof drivdata); /* cb */ - SIVAL(drivdata,4,1000); /* lVersion */ - memset(drivdata+8,0,32); /* szDeviceName */ - strcpy(drivdata+8,"NULL"); - PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */ -} - -static int check_printq_info(struct pack_desc* desc, - int uLevel, char *id1, char *id2) -{ - desc->subformat = NULL; - switch( uLevel ) { - case 0: - desc->format = "B13"; - break; - case 1: - desc->format = "B13BWWWzzzzzWW"; - break; - case 2: - desc->format = "B13BWWWzzzzzWN"; - desc->subformat = "WB21BB16B10zWWzDDz"; - break; - case 3: - desc->format = "zWWWWzzzzWWzzl"; - break; - case 4: - desc->format = "zWWWWzzzzWNzzl"; - desc->subformat = "WWzWWDDzz"; - break; - case 5: - desc->format = "z"; - break; - default: return False; - } - if (strcmp(desc->format,id1) != 0) return False; - if (desc->subformat && strcmp(desc->subformat,id2) != 0) return False; - return True; -} - -static void fill_printjob_info(int cnum, int snum, int uLevel, - struct pack_desc* desc, - print_queue_struct* queue, int n) -{ - time_t t = queue->time; - - /* the client expects localtime */ - t -= TimeDiff(t); - - PACKI(desc,"W",printjob_encode(snum, queue->job)); /* uJobId */ - if (uLevel == 1) { - PACKS(desc,"B21",queue->user); /* szUserName */ - PACKS(desc,"B",""); /* pad */ - PACKS(desc,"B16",""); /* szNotifyName */ - PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */ - PACKS(desc,"z",""); /* pszParms */ - PACKI(desc,"W",n+1); /* uPosition */ - PACKI(desc,"W",queue->status); /* fsStatus */ - PACKS(desc,"z",""); /* pszStatus */ - PACKI(desc,"D",t); /* ulSubmitted */ - PACKI(desc,"D",queue->size); /* ulSize */ - PACKS(desc,"z",queue->file); /* pszComment */ - } - if (uLevel == 2 || uLevel == 3) { - PACKI(desc,"W",queue->priority); /* uPriority */ - PACKS(desc,"z",queue->user); /* pszUserName */ - PACKI(desc,"W",n+1); /* uPosition */ - PACKI(desc,"W",queue->status); /* fsStatus */ - PACKI(desc,"D",t); /* ulSubmitted */ - PACKI(desc,"D",queue->size); /* ulSize */ - PACKS(desc,"z","Samba"); /* pszComment */ - PACKS(desc,"z",queue->file); /* pszDocument */ - if (uLevel == 3) { - PACKS(desc,"z",""); /* pszNotifyName */ - PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */ - PACKS(desc,"z",""); /* pszParms */ - PACKS(desc,"z",""); /* pszStatus */ - PACKS(desc,"z",SERVICE(snum)); /* pszQueue */ - PACKS(desc,"z","lpd"); /* pszQProcName */ - PACKS(desc,"z",""); /* pszQProcParms */ - PACKS(desc,"z","NULL"); /* pszDriverName */ - PackDriverData(desc); /* pDriverData */ - PACKS(desc,"z",""); /* pszPrinterName */ - } - } -} - -static void fill_printq_info(int cnum, int snum, int uLevel, - struct pack_desc* desc, - int count, print_queue_struct* queue, - print_status_struct* status) -{ - if (uLevel < 3) { - PACKS(desc,"B13",SERVICE(snum)); - } else { - PACKS(desc,"z",Expand(cnum,snum,SERVICE(snum))); - } - if (uLevel == 1 || uLevel == 2) { - PACKS(desc,"B",""); /* alignment */ - PACKI(desc,"W",5); /* priority */ - PACKI(desc,"W",0); /* start time */ - PACKI(desc,"W",0); /* until time */ - PACKS(desc,"z",""); /* pSepFile */ - PACKS(desc,"z","lpd"); /* pPrProc */ - PACKS(desc,"z",SERVICE(snum)); /* pDestinations */ - PACKS(desc,"z",""); /* pParms */ - if (snum < 0) { - PACKS(desc,"z","UNKNOWN PRINTER"); - PACKI(desc,"W",LPSTAT_ERROR); - } - else if (!status || !status->message[0]) { - PACKS(desc,"z",Expand(cnum,snum,lp_comment(snum))); - PACKI(desc,"W",LPSTAT_OK); /* status */ - } else { - PACKS(desc,"z",status->message); - PACKI(desc,"W",status->status); /* status */ - } - PACKI(desc,(uLevel == 1 ? "W" : "N"),count); - } - if (uLevel == 3 || uLevel == 4) { - PACKI(desc,"W",5); /* uPriority */ - PACKI(desc,"W",0); /* uStarttime */ - PACKI(desc,"W",0); /* uUntiltime */ - PACKI(desc,"W",5); /* pad1 */ - PACKS(desc,"z",""); /* pszSepFile */ - PACKS(desc,"z","WinPrint"); /* pszPrProc */ - PACKS(desc,"z",""); /* pszParms */ - if (!status || !status->message[0]) { - PACKS(desc,"z",Expand(cnum,snum,lp_comment(snum))); /* pszComment */ - PACKI(desc,"W",LPSTAT_OK); /* fsStatus */ - } else { - PACKS(desc,"z",status->message); /* pszComment */ - PACKI(desc,"W",status->status); /* fsStatus */ - } - PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */ - PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */ - PACKS(desc,"z",lp_printerdriver(snum)); /* pszDriverName */ - PackDriverData(desc); /* pDriverData */ - } - if (uLevel == 2 || uLevel == 4) { - int i; - for (i=0;i<count;i++) - fill_printjob_info(cnum,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i); - } - - DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",SERVICE(snum),count)); -} - -static BOOL api_DosPrintQGetInfo(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - char *QueueName = p; - int uLevel,cbBuf; - int count=0; - int snum; - char* str3; - struct pack_desc desc; - print_queue_struct *queue=NULL; - print_status_struct status; - - bzero(&status,sizeof(status)); - bzero(&desc,sizeof(desc)); - - p = skip_string(p,1); - uLevel = SVAL(p,0); - cbBuf = SVAL(p,2); - str3 = p + 4; - - /* remove any trailing username */ - if ((p = strchr(QueueName,'%'))) *p = 0; - - DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName)); - - /* check it's a supported varient */ - if (!prefix_ok(str1,"zWrLh")) return False; - if (!check_printq_info(&desc,uLevel,str2,str3)) return False; - - snum = lp_servicenumber(QueueName); - if (snum < 0 && pcap_printername_ok(QueueName,NULL)) { - int pnum = lp_servicenumber(PRINTERS_NAME); - if (pnum >= 0) { - lp_add_printer(QueueName,pnum); - snum = lp_servicenumber(QueueName); - } - } - - if (snum < 0 || !VALID_SNUM(snum)) return(False); - - count = get_printqueue(snum,cnum,&queue,&status); - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - if (init_package(&desc,1,count)) { - desc.subcount = count; - fill_printq_info(cnum,snum,uLevel,&desc,count,queue,&status); - } - - *rdata_len = desc.usedlen; - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,desc.neededlen); - - DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode)); - - if (queue) free(queue); - - return(True); -} - - -/**************************************************************************** - view list of all print jobs on all queues - ****************************************************************************/ -static BOOL api_DosPrintQEnum(int cnum, uint16 vuid, char* param, char* data, - int mdrcnt, int mprcnt, - char **rdata, char** rparam, - int *rdata_len, int *rparam_len) -{ - char *param_format = param+2; - char *output_format1 = skip_string(param_format,1); - char *p = skip_string(output_format1,1); - int uLevel = SVAL(p,0); - char *output_format2 = p + 4; - int services = lp_numservices(); - int i, n; - struct pack_desc desc; - print_queue_struct **queue = NULL; - print_status_struct *status = NULL; - int* subcntarr = NULL; - int queuecnt, subcnt=0, succnt=0; - - bzero(&desc,sizeof(desc)); - - DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel)); - - if (!prefix_ok(param_format,"WrLeh")) return False; - if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) - return False; - queuecnt = 0; - for (i = 0; i < services; i++) - if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) - queuecnt++; - if (uLevel > 0) { - queue = (print_queue_struct**)malloc(queuecnt*sizeof(print_queue_struct*)); - memset(queue,0,queuecnt*sizeof(print_queue_struct*)); - status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_struct)); - memset(status,0,queuecnt*sizeof(print_status_struct)); - subcntarr = (int*)malloc(queuecnt*sizeof(int)); - subcnt = 0; - n = 0; - for (i = 0; i < services; i++) - if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) { - subcntarr[n] = get_printqueue(i,cnum,&queue[n],&status[n]); - subcnt += subcntarr[n]; - n++; - } - } - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - - if (init_package(&desc,queuecnt,subcnt)) { - n = 0; - succnt = 0; - for (i = 0; i < services; i++) - if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) { - fill_printq_info(cnum,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]); - n++; - if (desc.errcode == NERR_Success) succnt = n; - } - } - - if (subcntarr) free(subcntarr); - - *rdata_len = desc.usedlen; - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,queuecnt); - - for (i = 0; i < queuecnt; i++) { - if (queue && queue[i]) free(queue[i]); - } - - if (queue) free(queue); - if (status) free(status); - - return True; -} - -/**************************************************************************** - get info level for a server list query - ****************************************************************************/ -static BOOL check_server_info(int uLevel, char* id) -{ - switch( uLevel ) { - case 0: - if (strcmp(id,"B16") != 0) return False; - break; - case 1: - if (strcmp(id,"B16BBDz") != 0) return False; - break; - default: - return False; - } - return True; -} - -struct srv_info_struct -{ - fstring name; - uint32 type; - fstring comment; - fstring domain; - BOOL server_added; -}; - - -/******************************************************************* - get server info lists from the files saved by nmbd. Return the - number of entries - ******************************************************************/ -static int get_server_info(uint32 servertype, - struct srv_info_struct **servers, - char *domain) -{ - FILE *f; - pstring fname; - int count=0; - int alloced=0; - pstring line; - BOOL local_list_only; - - pstrcpy(fname,lp_lockdir()); - trim_string(fname,NULL,"/"); - strcat(fname,"/"); - strcat(fname,SERVER_LIST); - - f = fopen(fname,"r"); - - if (!f) { - DEBUG(4,("Can't open %s - %s\n",fname,strerror(errno))); - return(0); - } - - /* request for everything is code for request all servers */ - if (servertype == SV_TYPE_ALL) - servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY); - - local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY); - - DEBUG(4,("Servertype search: %8x\n",servertype)); - - while (!feof(f)) - { - fstring stype; - struct srv_info_struct *s; - char *ptr = line; - BOOL ok = True; - *ptr = 0; - - fgets(line,sizeof(line)-1,f); - if (!*line) continue; - - if (count == alloced) { - alloced += 10; - (*servers) = (struct srv_info_struct *) - Realloc(*servers,sizeof(**servers)*alloced); - if (!(*servers)) return(0); - bzero((char *)((*servers)+count),sizeof(**servers)*(alloced-count)); - } - s = &(*servers)[count]; - - if (!next_token(&ptr,s->name , NULL)) continue; - if (!next_token(&ptr,stype , NULL)) continue; - if (!next_token(&ptr,s->comment, NULL)) continue; - if (!next_token(&ptr,s->domain , NULL)) { - /* this allows us to cope with an old nmbd */ - strcpy(s->domain,myworkgroup); - } - - if (sscanf(stype,"%X",&s->type) != 1) { - DEBUG(4,("r:host file ")); - ok = False; - } - - /* Filter the servers/domains we return based on what was asked for. */ - - /* Check to see if we are being asked for a local list only. */ - if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) { - DEBUG(4,("r: local list only")); - ok = False; - } - - /* doesn't match up: don't want it */ - if (!(servertype & s->type)) { - DEBUG(4,("r:serv type ")); - ok = False; - } - - if ((servertype & SV_TYPE_DOMAIN_ENUM) != - (s->type & SV_TYPE_DOMAIN_ENUM)) - { - DEBUG(4,("s: dom mismatch ")); - ok = False; - } - - if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) - { - ok = False; - } - - /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */ - s->type &= ~SV_TYPE_LOCAL_LIST_ONLY; - - if (ok) - { - DEBUG(4,("**SV** %20s %8x %25s %15s\n", - s->name, s->type, s->comment, s->domain)); - - s->server_added = True; - count++; - } - else - { - DEBUG(4,("%20s %8x %25s %15s\n", - s->name, s->type, s->comment, s->domain)); - } - } - - fclose(f); - return(count); -} - - -/******************************************************************* - fill in a server info structure - ******************************************************************/ -static int fill_srv_info(struct srv_info_struct *service, - int uLevel, char **buf, int *buflen, - char **stringbuf, int *stringspace, char *baseaddr) -{ - int struct_len; - char* p; - char* p2; - int l2; - int len; - - switch (uLevel) { - case 0: struct_len = 16; break; - case 1: struct_len = 26; break; - default: return -1; - } - - if (!buf) - { - len = 0; - switch (uLevel) - { - case 1: - len = strlen(service->comment)+1; - break; - } - - if (buflen) *buflen = struct_len; - if (stringspace) *stringspace = len; - return struct_len + len; - } - - len = struct_len; - p = *buf; - if (*buflen < struct_len) return -1; - if (stringbuf) - { - p2 = *stringbuf; - l2 = *stringspace; - } - else - { - p2 = p + struct_len; - l2 = *buflen - struct_len; - } - if (!baseaddr) baseaddr = p; - - switch (uLevel) - { - case 0: - StrnCpy(p,service->name,15); - break; - - case 1: - StrnCpy(p,service->name,15); - SIVAL(p,18,service->type); - SIVAL(p,22,PTR_DIFF(p2,baseaddr)); - len += CopyAndAdvance(&p2,service->comment,&l2); - break; - } - - if (stringbuf) - { - *buf = p + struct_len; - *buflen -= struct_len; - *stringbuf = p2; - *stringspace = l2; - } - else - { - *buf = p2; - *buflen -= len; - } - return len; -} - - -static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2) -{ - return(strcmp(s1->name,s2->name)); -} - -/**************************************************************************** - view list of servers available (or possibly domains). The info is - extracted from lists saved by nmbd on the local host - ****************************************************************************/ -static BOOL api_RNetServerEnum(int cnum, uint16 vuid, char *param, char *data, - int mdrcnt, int mprcnt, char **rdata, - char **rparam, int *rdata_len, int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - int buf_len = SVAL(p,2); - uint32 servertype = IVAL(p,4); - char *p2; - int data_len, fixed_len, string_len; - int f_len, s_len; - struct srv_info_struct *servers=NULL; - int counted=0,total=0; - int i,missed; - fstring domain; - BOOL domain_request; - BOOL local_request; - - /* If someone sets all the bits they don't really mean to set - DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the - known servers. */ - - if (servertype == SV_TYPE_ALL) - servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY); - - /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set - any other bit (they may just set this bit on it's own) they - want all the locally seen servers. However this bit can be - set on its own so set the requested servers to be - ALL - DOMAIN_ENUM. */ - - if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) - servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM); - - domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0); - local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0); - - p += 8; - - if (!prefix_ok(str1,"WrLehD")) return False; - if (!check_server_info(uLevel,str2)) return False; - - DEBUG(4, ("server request level: %s %8x ", str2, servertype)); - DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request))); - DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request))); - - if (strcmp(str1, "WrLehDz") == 0) { - StrnCpy(domain, p, sizeof(fstring)-1); - } else { - StrnCpy(domain, myworkgroup, sizeof(fstring)-1); - } - - if (lp_browse_list()) - total = get_server_info(servertype,&servers,domain); - - data_len = fixed_len = string_len = 0; - missed = 0; - - qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp); - - { - char *lastname=NULL; - - for (i=0;i<total;i++) - { - struct srv_info_struct *s = &servers[i]; - if (lastname && strequal(lastname,s->name)) continue; - lastname = s->name; - data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0); - DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n", - s->name, s->type, s->comment, s->domain)); - - if (data_len <= buf_len) { - counted++; - fixed_len += f_len; - string_len += s_len; - } else { - missed++; - } - } - } - - *rdata_len = fixed_len + string_len; - *rdata = REALLOC(*rdata,*rdata_len); - bzero(*rdata,*rdata_len); - - p2 = (*rdata) + fixed_len; /* auxilliary data (strings) will go here */ - p = *rdata; - f_len = fixed_len; - s_len = string_len; - - { - char *lastname=NULL; - int count2 = counted; - for (i = 0; i < total && count2;i++) - { - struct srv_info_struct *s = &servers[i]; - if (lastname && strequal(lastname,s->name)) continue; - lastname = s->name; - fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata); - DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n", - s->name, s->type, s->comment, s->domain)); - count2--; - } - } - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERROR_MORE_DATA)); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,counted); - SSVAL(*rparam,6,counted+missed); - - if (servers) free(servers); - - DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n", - domain,uLevel,counted,counted+missed)); - - return(True); -} - - -/**************************************************************************** - get info about a share - ****************************************************************************/ -static BOOL check_share_info(int uLevel, char* id) -{ - switch( uLevel ) { - case 0: - if (strcmp(id,"B13") != 0) return False; - break; - case 1: - if (strcmp(id,"B13BWz") != 0) return False; - break; - case 2: - if (strcmp(id,"B13BWzWWWzB9B") != 0) return False; - break; - case 91: - if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) return False; - break; - default: return False; - } - return True; -} - -static int fill_share_info(int cnum, int snum, int uLevel, - char** buf, int* buflen, - char** stringbuf, int* stringspace, char* baseaddr) -{ - int struct_len; - char* p; - char* p2; - int l2; - int len; - - switch( uLevel ) { - case 0: struct_len = 13; break; - case 1: struct_len = 20; break; - case 2: struct_len = 40; break; - case 91: struct_len = 68; break; - default: return -1; - } - - - if (!buf) - { - len = 0; - if (uLevel > 0) len += StrlenExpanded(cnum,snum,lp_comment(snum)); - if (uLevel > 1) len += strlen(lp_pathname(snum)) + 1; - if (buflen) *buflen = struct_len; - if (stringspace) *stringspace = len; - return struct_len + len; - } - - len = struct_len; - p = *buf; - if ((*buflen) < struct_len) return -1; - if (stringbuf) - { - p2 = *stringbuf; - l2 = *stringspace; - } - else - { - p2 = p + struct_len; - l2 = (*buflen) - struct_len; - } - if (!baseaddr) baseaddr = p; - - StrnCpy(p,lp_servicename(snum),13); - - if (uLevel > 0) - { - int type; - CVAL(p,13) = 0; - type = STYPE_DISKTREE; - if (lp_print_ok(snum)) type = STYPE_PRINTQ; - if (strequal("IPC$",lp_servicename(snum))) type = STYPE_IPC; - SSVAL(p,14,type); /* device type */ - SIVAL(p,16,PTR_DIFF(p2,baseaddr)); - len += CopyExpanded(cnum,snum,&p2,lp_comment(snum),&l2); - } - - if (uLevel > 1) - { - SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */ - SSVALS(p,22,-1); /* max uses */ - SSVAL(p,24,1); /* current uses */ - SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */ - len += CopyAndAdvance(&p2,lp_pathname(snum),&l2); - memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */ - } - - if (uLevel > 2) - { - memset(p+40,0,SHPWLEN+2); - SSVAL(p,50,0); - SIVAL(p,52,0); - SSVAL(p,56,0); - SSVAL(p,58,0); - SIVAL(p,60,0); - SSVAL(p,64,0); - SSVAL(p,66,0); - } - - if (stringbuf) - { - (*buf) = p + struct_len; - (*buflen) -= struct_len; - (*stringbuf) = p2; - (*stringspace) = l2; - } - else - { - (*buf) = p2; - (*buflen) -= len; - } - return len; -} - -static BOOL api_RNetShareGetInfo(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *netname = skip_string(str2,1); - char *p = skip_string(netname,1); - int uLevel = SVAL(p,0); - int snum = find_service(netname); - - if (snum < 0) return False; - - /* check it's a supported varient */ - if (!prefix_ok(str1,"zWrLh")) return False; - if (!check_share_info(uLevel,str2)) return False; - - *rdata = REALLOC(*rdata,mdrcnt); - p = *rdata; - *rdata_len = fill_share_info(cnum,snum,uLevel,&p,&mdrcnt,0,0,0); - if (*rdata_len < 0) return False; - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - SSVAL(*rparam,4,*rdata_len); - - return(True); -} - -/**************************************************************************** - view list of shares available - ****************************************************************************/ -static BOOL api_RNetShareEnum(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - int buf_len = SVAL(p,2); - char *p2; - int count=lp_numservices(); - int total=0,counted=0; - int i; - int data_len, fixed_len, string_len; - int f_len, s_len; - - if (!prefix_ok(str1,"WrLeh")) return False; - if (!check_share_info(uLevel,str2)) return False; - - data_len = fixed_len = string_len = 0; - for (i=0;i<count;i++) - if (lp_browseable(i) && lp_snum_ok(i)) - { - total++; - data_len += fill_share_info(cnum,i,uLevel,0,&f_len,0,&s_len,0); - if (data_len <= buf_len) - { - counted++; - fixed_len += f_len; - string_len += s_len; - } - } - *rdata_len = fixed_len + string_len; - *rdata = REALLOC(*rdata,*rdata_len); - memset(*rdata,0,*rdata_len); - - p2 = (*rdata) + fixed_len; /* auxillery data (strings) will go here */ - p = *rdata; - f_len = fixed_len; - s_len = string_len; - for (i = 0; i < count;i++) - if (lp_browseable(i) && lp_snum_ok(i)) - if (fill_share_info(cnum,i,uLevel,&p,&f_len,&p2,&s_len,*rdata) < 0) - break; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,counted); - SSVAL(*rparam,6,total); - - DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n", - counted,total,uLevel, - buf_len,*rdata_len,mdrcnt)); - return(True); -} - - - -/**************************************************************************** - get the time of day info - ****************************************************************************/ -static BOOL api_NetRemoteTOD(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *p; - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 21; - *rdata = REALLOC(*rdata,*rdata_len); - - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - - p = *rdata; - - { - struct tm *t; - time_t unixdate = time(NULL); - - put_dos_date3(p,0,unixdate); /* this is the time that is looked at - by NT in a "net time" operation, - it seems to ignore the one below */ - - /* the client expects to get localtime, not GMT, in this bit - (I think, this needs testing) */ - t = LocalTime(&unixdate); - - SIVAL(p,4,0); /* msecs ? */ - CVAL(p,8) = t->tm_hour; - CVAL(p,9) = t->tm_min; - CVAL(p,10) = t->tm_sec; - CVAL(p,11) = 0; /* hundredths of seconds */ - SSVALS(p,12,TimeDiff(unixdate)/60); /* timezone in minutes from GMT */ - SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */ - CVAL(p,16) = t->tm_mday; - CVAL(p,17) = t->tm_mon + 1; - SSVAL(p,18,1900+t->tm_year); - CVAL(p,20) = t->tm_wday; - } - - - return(True); -} - -/**************************************************************************** - set the user password - ****************************************************************************/ -static BOOL api_SetUserPassword(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *p = skip_string(param+2,2); - fstring user; - fstring pass1,pass2; - - fstrcpy(user,p); - - p = skip_string(p,1); - - StrnCpy(pass1,p,16); - StrnCpy(pass2,p+16,16); - - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; - - SSVAL(*rparam,0,NERR_badpass); - SSVAL(*rparam,2,0); /* converter word */ - - DEBUG(3,("Set password for <%s>\n",user)); - - if (password_ok(user,pass1,strlen(pass1),NULL) && - chgpasswd(user,pass1,pass2)) - { - SSVAL(*rparam,0,NERR_Success); - } - - bzero(pass1,sizeof(fstring)); - bzero(pass2,sizeof(fstring)); - - return(True); -} - -/**************************************************************************** - delete a print job - Form: <W> <> - ****************************************************************************/ -static BOOL api_RDosPrintJobDel(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - int function = SVAL(param,0); - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int jobid, snum; - int i, count; - - printjob_decode(SVAL(p,0), &snum, &jobid); - - /* check it's a supported varient */ - if (!(strcsequal(str1,"W") && strcsequal(str2,""))) - return(False); - - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; - - SSVAL(*rparam,0,NERR_Success); - - if (snum >= 0 && VALID_SNUM(snum)) - { - print_queue_struct *queue=NULL; - lpq_reset(snum); - count = get_printqueue(snum,cnum,&queue,NULL); - - for (i=0;i<count;i++) - if ((queue[i].job&0xFF) == jobid) - { - switch (function) { - case 81: /* delete */ - DEBUG(3,("Deleting queue entry %d\n",queue[i].job)); - del_printqueue(cnum,snum,queue[i].job); - break; - case 82: /* pause */ - case 83: /* resume */ - DEBUG(3,("%s queue entry %d\n", - (function==82?"pausing":"resuming"),queue[i].job)); - status_printjob(cnum,snum,queue[i].job, - (function==82?LPQ_PAUSED:LPQ_QUEUED)); - break; - } - break; - } - - if (i==count) - SSVAL(*rparam,0,NERR_JobNotFound); - - if (queue) free(queue); - } - - SSVAL(*rparam,2,0); /* converter word */ - - return(True); -} - -static BOOL api_WPrintQueuePurge(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *QueueName = skip_string(str2,1); - int snum; - - /* check it's a supported varient */ - if (!(strcsequal(str1,"z") && strcsequal(str2,""))) - return(False); - - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; - - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - - snum = lp_servicenumber(QueueName); - if (snum < 0 && pcap_printername_ok(QueueName,NULL)) { - int pnum = lp_servicenumber(PRINTERS_NAME); - if (pnum >= 0) { - lp_add_printer(QueueName,pnum); - snum = lp_servicenumber(QueueName); - } - } - - if (snum >= 0 && VALID_SNUM(snum)) { - print_queue_struct *queue=NULL; - int i, count; - lpq_reset(snum); - - count = get_printqueue(snum,cnum,&queue,NULL); - for (i = 0; i < count; i++) - del_printqueue(cnum,snum,queue[i].job); - - if (queue) free(queue); - } - - DEBUG(3,("Print queue purge, queue=%s\n",QueueName)); - - return(True); -} - - -/**************************************************************************** - set the property of a print job (undocumented?) - ? function = 0xb -> set name of print job - ? function = 0x6 -> move print job up/down - Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> - or <WWsTP> <WB21BB16B10zWWzDDz> -****************************************************************************/ -static int check_printjob_info(struct pack_desc* desc, - int uLevel, char* id) -{ - desc->subformat = NULL; - switch( uLevel ) { - case 0: desc->format = "W"; break; - case 1: desc->format = "WB21BB16B10zWWzDDz"; break; - case 2: desc->format = "WWzWWDDzz"; break; - case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break; - default: return False; - } - if (strcmp(desc->format,id) != 0) return False; - return True; -} - -static BOOL api_PrintJobInfo(int cnum,uint16 vuid,char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - struct pack_desc desc; - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int jobid, snum; - int uLevel = SVAL(p,2); - int function = SVAL(p,4); /* what is this ?? */ - int i; - char *s = data; - - printjob_decode(SVAL(p,0), &snum, &jobid); - - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; - - /* check it's a supported varient */ - if ((strcmp(str1,"WWsTP")) || (!check_printjob_info(&desc,uLevel,str2))) - return(False); - - switch (function) { - case 0x6: /* change job place in the queue, data gives the new place */ - if (snum >= 0 && VALID_SNUM(snum)) - { - print_queue_struct *queue=NULL; - int count; - - lpq_reset(snum); - count = get_printqueue(snum,cnum,&queue,NULL); - for (i=0;i<count;i++) /* find job */ - if ((queue[i].job&0xFF) == jobid) break; - - if (i==count) { - desc.errcode=NERR_JobNotFound; - if (queue) free(queue); - } - else { - desc.errcode=NERR_Success; - i++; -#if 0 - { - int place= SVAL(data,0); - /* we currently have no way of doing this. Can any unix do it? */ - if (i < place) /* move down */; - else if (i > place ) /* move up */; - } -#endif - desc.errcode=NERR_notsupported; /* not yet supported */ - if (queue) free(queue); - } - } - else desc.errcode=NERR_JobNotFound; - break; - case 0xb: /* change print job name, data gives the name */ - /* jobid, snum should be zero */ - if (isalpha(*s)) - { - pstring name; - int l = 0; - while (l<64 && *s) - { - if (issafe(*s)) name[l++] = *s; - s++; - } - name[l] = 0; - - DEBUG(3,("Setting print name to %s\n",name)); - - for (i=0;i<MAX_OPEN_FILES;i++) - if (Files[i].open && Files[i].print_file) - { - pstring wd; - GetWd(wd); - unbecome_user(); - - if (!become_user(Files[i].cnum,vuid) || - !become_service(Files[i].cnum,True)) - break; - - if (sys_rename(Files[i].name,name) == 0) - string_set(&Files[i].name,name); - break; - } - } - desc.errcode=NERR_Success; - - break; - default: /* not implemented */ - return False; - } - - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); /* converter word */ - - return(True); -} - - -/**************************************************************************** - get info about the server - ****************************************************************************/ -static BOOL api_RNetServerGetInfo(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel = SVAL(p,0); - char *p2; - int struct_len; - - DEBUG(4,("NetServerGetInfo level %d\n",uLevel)); - - /* check it's a supported varient */ - if (!prefix_ok(str1,"WrLh")) return False; - switch( uLevel ) { - case 0: - if (strcmp(str2,"B16") != 0) return False; - struct_len = 16; - break; - case 1: - if (strcmp(str2,"B16BBDz") != 0) return False; - struct_len = 26; - break; - case 2: - if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz") - != 0) return False; - struct_len = 134; - break; - case 3: - if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") - != 0) return False; - struct_len = 144; - break; - case 20: - if (strcmp(str2,"DN") != 0) return False; - struct_len = 6; - break; - case 50: - if (strcmp(str2,"B16BBDzWWzzz") != 0) return False; - struct_len = 42; - break; - default: return False; - } - - *rdata_len = mdrcnt; - *rdata = REALLOC(*rdata,*rdata_len); - - p = *rdata; - p2 = p + struct_len; - if (uLevel != 20) { - StrnCpy(p,local_machine,16); - strupper(p); - } - p += 16; - if (uLevel > 0) - { - struct srv_info_struct *servers=NULL; - int i,count; - pstring comment; - uint32 servertype= lp_default_server_announce(); - - pstrcpy(comment,lp_serverstring()); - - if ((count=get_server_info(SV_TYPE_ALL,&servers,myworkgroup))>0) { - for (i=0;i<count;i++) - if (strequal(servers[i].name,local_machine)) - { - servertype = servers[i].type; - pstrcpy(comment,servers[i].comment); - } - } - if (servers) free(servers); - - SCVAL(p,0,lp_major_announce_version()); - SCVAL(p,1,lp_minor_announce_version()); - SIVAL(p,2,servertype); - - if (mdrcnt == struct_len) { - SIVAL(p,6,0); - } else { - SIVAL(p,6,PTR_DIFF(p2,*rdata)); - standard_sub(cnum,comment); - StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0)); - p2 = skip_string(p2,1); - } - } - if (uLevel > 1) - { - return False; /* not yet implemented */ - } - - *rdata_len = PTR_DIFF(p2,*rdata); - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - SSVAL(*rparam,4,*rdata_len); - - return(True); -} - - -/**************************************************************************** - get info about the server - ****************************************************************************/ -static BOOL api_NetWkstaGetInfo(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - char *p2; - extern pstring sesssetup_user; - int level = SVAL(p,0); - - DEBUG(4,("NetWkstaGetInfo level %d\n",level)); - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - - /* check it's a supported varient */ - if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) - return(False); - - *rdata_len = mdrcnt + 1024; - *rdata = REALLOC(*rdata,*rdata_len); - - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - - p = *rdata; - p2 = p + 22; - - - SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */ - strcpy(p2,local_machine); - strupper(p2); - p2 = skip_string(p2,1); - p += 4; - - SIVAL(p,0,PTR_DIFF(p2,*rdata)); - strcpy(p2,sesssetup_user); - p2 = skip_string(p2,1); - p += 4; - - SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */ - strcpy(p2,myworkgroup); - strupper(p2); - p2 = skip_string(p2,1); - p += 4; - - SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */ - SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */ - p += 2; - - SIVAL(p,0,PTR_DIFF(p2,*rdata)); - strcpy(p2,myworkgroup); /* don't know. login domain?? */ - p2 = skip_string(p2,1); - p += 4; - - SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */ - strcpy(p2,""); - p2 = skip_string(p2,1); - p += 4; - - *rdata_len = PTR_DIFF(p2,*rdata); - - SSVAL(*rparam,4,*rdata_len); - - return(True); -} - -/**************************************************************************** - get info about a user - - struct user_info_11 { - char usri11_name[21]; 0-20 - char usri11_pad; 21 - char *usri11_comment; 22-25 - char *usri11_usr_comment; 26-29 - unsigned short usri11_priv; 30-31 - unsigned long usri11_auth_flags; 32-35 - long usri11_password_age; 36-39 - char *usri11_homedir; 40-43 - char *usri11_parms; 44-47 - long usri11_last_logon; 48-51 - long usri11_last_logoff; 52-55 - unsigned short usri11_bad_pw_count; 56-57 - unsigned short usri11_num_logons; 58-59 - char *usri11_logon_server; 60-63 - unsigned short usri11_country_code; 64-65 - char *usri11_workstations; 66-69 - unsigned long usri11_max_storage; 70-73 - unsigned short usri11_units_per_week; 74-75 - unsigned char *usri11_logon_hours; 76-79 - unsigned short usri11_code_page; 80-81 - }; - -where: - - usri11_name specifies the user name for which information is retireved - - usri11_pad aligns the next data structure element to a word boundary - - usri11_comment is a null terminated ASCII comment - - usri11_user_comment is a null terminated ASCII comment about the user - - usri11_priv specifies the level of the privilege assigned to the user. - The possible values are: - -Name Value Description -USER_PRIV_GUEST 0 Guest privilege -USER_PRIV_USER 1 User privilege -USER_PRV_ADMIN 2 Administrator privilege - - usri11_auth_flags specifies the account operator privileges. The - possible values are: - -Name Value Description -AF_OP_PRINT 0 Print operator - - -Leach, Naik [Page 28]
- - -INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997 - - -AF_OP_COMM 1 Communications operator -AF_OP_SERVER 2 Server operator -AF_OP_ACCOUNTS 3 Accounts operator - - - usri11_password_age specifies how many seconds have elapsed since the - password was last changed. - - usri11_home_dir points to a null terminated ASCII string that contains - the path name of the user's home directory. - - usri11_parms points to a null terminated ASCII string that is set - aside for use by applications. - - usri11_last_logon specifies the time when the user last logged on. - This value is stored as the number of seconds elapsed since - 00:00:00, January 1, 1970. - - usri11_last_logoff specifies the time when the user last logged off. - This value is stored as the number of seconds elapsed since - 00:00:00, January 1, 1970. A value of 0 means the last logoff - time is unknown. - - usri11_bad_pw_count specifies the number of incorrect passwords - entered since the last successful logon. - - usri11_log1_num_logons specifies the number of times this user has - logged on. A value of -1 means the number of logons is unknown. - - usri11_logon_server points to a null terminated ASCII string that - contains the name of the server to which logon requests are sent. - A null string indicates logon requests should be sent to the - domain controller. - - usri11_country_code specifies the country code for the user's language - of choice. - - usri11_workstations points to a null terminated ASCII string that - contains the names of workstations the user may log on from. - There may be up to 8 workstations, with the names separated by - commas. A null strings indicates there are no restrictions. - - usri11_max_storage specifies the maximum amount of disk space the user - can occupy. A value of 0xffffffff indicates there are no - restrictions. - - usri11_units_per_week specifies the equal number of time units into - which a week is divided. This value must be equal to 168. - - usri11_logon_hours points to a 21 byte (168 bits) string that - specifies the time during which the user can log on. Each bit - represents one unique hour in a week. The first bit (bit 0, word - 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is - - - -Leach, Naik [Page 29]
- - -INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997 - - - Sunday, 1:00 to 1:59 and so on. A null pointer indicates there - are no restrictions. - - usri11_code_page specifies the code page for the user's language of - choice - -All of the pointers in this data structure need to be treated -specially. The pointer is a 32 bit pointer. The higher 16 bits need -to be ignored. The converter word returned in the parameters section -needs to be subtracted from the lower 16 bits to calculate an offset -into the return buffer where this ASCII string resides. - -There is no auxiliary data in the response. - - ****************************************************************************/ - -#define usri11_name 0 -#define usri11_pad 21 -#define usri11_comment 22 -#define usri11_usr_comment 26 -#define usri11_full_name 30 -#define usri11_priv 34 -#define usri11_auth_flags 36 -#define usri11_password_age 40 -#define usri11_homedir 44 -#define usri11_parms 48 -#define usri11_last_logon 52 -#define usri11_last_logoff 56 -#define usri11_bad_pw_count 60 -#define usri11_num_logons 62 -#define usri11_logon_server 64 -#define usri11_country_code 68 -#define usri11_workstations 70 -#define usri11_max_storage 74 -#define usri11_units_per_week 78 -#define usri11_logon_hours 80 -#define usri11_code_page 84 -#define usri11_end 86 - -#define USER_PRIV_GUEST 0 -#define USER_PRIV_USER 1 -#define USER_PRIV_ADMIN 2 - -#define AF_OP_PRINT 0 -#define AF_OP_COMM 1 -#define AF_OP_SERVER 2 -#define AF_OP_ACCOUNTS 3 - - -static BOOL api_RNetUserGetInfo(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *UserName = skip_string(str2,1); - char *p = skip_string(UserName,1); - int uLevel = SVAL(p,0); - char *p2; - - /* get NIS home of a previously validated user - simeon */ - user_struct *vuser = get_valid_user_struct(vuid); - DEBUG(3,(" Username of UID %d is %s\n", vuser->uid, vuser->name)); -#if (defined(NETGROUP) && defined(AUTOMOUNT)) - DEBUG(3,(" HOMESHR for %s is %s\n", vuser->name, vuser->home_share)); -#endif - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - - /* check it's a supported variant */ - if (strcmp(str1,"zWrLh") != 0) return False; - switch( uLevel ) - { - case 0: p2 = "B21"; break; - case 1: p2 = "B21BB16DWzzWz"; break; - case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break; - case 10: p2 = "B21Bzzz"; break; - case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break; - default: return False; - } - - if (strcmp(p2,str2) != 0) return False; - - *rdata_len = mdrcnt + 1024; - *rdata = REALLOC(*rdata,*rdata_len); - - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - - p = *rdata; - p2 = p + usri11_end; - - memset(p,0,21); - fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */ - - if (uLevel > 0) - { - SCVAL(p,usri11_pad,0); /* padding - 1 byte */ - *p2 = 0; - } - if (uLevel >= 10) - { - SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */ - strcpy(p2,"Comment"); - p2 = skip_string(p2,1); - - SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */ - strcpy(p2,"UserComment"); - p2 = skip_string(p2,1); - - /* EEK! the cifsrap.txt doesn't have this in!!!! */ - SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */ - strcpy(p2,vuser->real_name); /* simeon */ - p2 = skip_string(p2,1); - } - - if (uLevel == 11) /* modelled after NTAS 3.51 reply */ - { - SSVAL(p,usri11_priv,Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); - SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */ - SIVALS(p,usri11_password_age,0xffffffff); /* password age */ - SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */ - if (*lp_logon_path()) - { - strcpy(p2,lp_logon_path()); - } - else - { -#if (defined(NETGROUP) && defined(AUTOMOUNT)) - strcpy(p2, vuser->home_share); -#else - strcpy(p2,"\\\\%L\\%U"); -#endif - } - standard_sub_basic(p2); - p2 = skip_string(p2,1); - SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */ - strcpy(p2,""); - p2 = skip_string(p2,1); - SIVAL(p,usri11_last_logon,0); /* last logon */ - SIVAL(p,usri11_last_logoff,0); /* last logoff */ - SSVALS(p,usri11_bad_pw_count,0xffffffff); /* bad pw counts */ - SSVALS(p,usri11_num_logons,0xffffffff); /* num logons */ - SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */ - strcpy(p2,"\\\\*"); - p2 = skip_string(p2,1); - SSVAL(p,usri11_country_code,0); /* country code */ - - SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */ - strcpy(p2,""); - p2 = skip_string(p2,1); - - SIVALS(p,usri11_max_storage,0xffffffff); /* max storage */ - SSVAL(p,usri11_units_per_week,168); /* units per week */ - SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */ - - /* a simple way to get logon hours at all times. */ - memset(p2,0xff,21); - SCVAL(p2,21,0); /* fix zero termination */ - p2 = skip_string(p2,1); - - SSVAL(p,usri11_code_page,0); /* code page */ - } - if (uLevel == 1 || uLevel == 2) - { - memset(p+22,' ',16); /* password */ - SIVALS(p,38,-1); /* password age */ - SSVAL(p,42, - Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); - SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */ - if (*lp_logon_path()) - { - strcpy(p2,lp_logon_path()); - } - else - { -#if (defined(NETGROUP) && defined(AUTOMOUNT)) - strcpy(p2, vuser->home_share); -#else - strcpy(p2,"\\\\%L\\%U"); -#endif - } - standard_sub_basic(p2); - p2 = skip_string(p2,1); - SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */ - *p2++ = 0; - SSVAL(p,52,0); /* flags */ - SIVAL(p,54,0); /* script_path */ - if (uLevel == 2) - { - SIVAL(p,60,0); /* auth_flags */ - SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */ - strcpy(p2,vuser->real_name); /* simeon */ - p2 = skip_string(p2,1); - SIVAL(p,68,0); /* urs_comment */ - SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */ - strcpy(p2,""); - p2 = skip_string(p2,1); - SIVAL(p,76,0); /* workstations */ - SIVAL(p,80,0); /* last_logon */ - SIVAL(p,84,0); /* last_logoff */ - SIVALS(p,88,-1); /* acct_expires */ - SIVALS(p,92,-1); /* max_storage */ - SSVAL(p,96,168); /* units_per_week */ - SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */ - memset(p2,-1,21); - p2 += 21; - SSVALS(p,102,-1); /* bad_pw_count */ - SSVALS(p,104,-1); /* num_logons */ - SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */ - strcpy(p2,"\\\\%L"); - standard_sub_basic(p2); - p2 = skip_string(p2,1); - SSVAL(p,110,49); /* country_code */ - SSVAL(p,112,860); /* code page */ - } - } - - *rdata_len = PTR_DIFF(p2,*rdata); - - SSVAL(*rparam,4,*rdata_len); /* is this right?? */ - - return(True); -} - -/******************************************************************* - get groups that a user is a member of - ******************************************************************/ -static BOOL api_NetUserGetGroups(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *UserName = skip_string(str2,1); - char *p = skip_string(UserName,1); - int uLevel = SVAL(p,0); - char *p2; - int count=0; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - - /* check it's a supported varient */ - if (strcmp(str1,"zWrLeh") != 0) return False; - switch( uLevel ) { - case 0: p2 = "B21"; break; - default: return False; - } - if (strcmp(p2,str2) != 0) return False; - - *rdata_len = mdrcnt + 1024; - *rdata = REALLOC(*rdata,*rdata_len); - - SSVAL(*rparam,0,NERR_Success); - SSVAL(*rparam,2,0); /* converter word */ - - p = *rdata; - - /* XXXX we need a real SAM database some day */ - strcpy(p,"Users"); p += 21; count++; - strcpy(p,"Domain Users"); p += 21; count++; - strcpy(p,"Guests"); p += 21; count++; - strcpy(p,"Domain Guests"); p += 21; count++; - - *rdata_len = PTR_DIFF(p,*rdata); - - SSVAL(*rparam,4,count); /* is this right?? */ - SSVAL(*rparam,6,count); /* is this right?? */ - - return(True); -} - - -static BOOL api_WWkstaUserLogon(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel; - struct pack_desc desc; - char* name; - char* logon_script; - - uLevel = SVAL(p,0); - name = p + 2; - - bzero(&desc,sizeof(desc)); - - DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name)); - - /* check it's a supported varient */ - if (strcmp(str1,"OOWb54WrLh") != 0) return False; - if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) return False; - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - desc.subformat = NULL; - desc.format = str2; - - if (init_package(&desc,1,0)) - { - PACKI(&desc,"W",0); /* code */ - PACKS(&desc,"B21",name); /* eff. name */ - PACKS(&desc,"B",""); /* pad */ - PACKI(&desc,"W", - Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); - PACKI(&desc,"D",0); /* auth flags XXX */ - PACKI(&desc,"W",0); /* num logons */ - PACKI(&desc,"W",0); /* bad pw count */ - PACKI(&desc,"D",0); /* last logon */ - PACKI(&desc,"D",-1); /* last logoff */ - PACKI(&desc,"D",-1); /* logoff time */ - PACKI(&desc,"D",-1); /* kickoff time */ - PACKI(&desc,"D",0); /* password age */ - PACKI(&desc,"D",0); /* password can change */ - PACKI(&desc,"D",-1); /* password must change */ - { - fstring mypath; - strcpy(mypath,"\\\\"); - strcat(mypath,local_machine); - strupper(mypath); - PACKS(&desc,"z",mypath); /* computer */ - } - PACKS(&desc,"z",myworkgroup);/* domain */ - -/* JHT - By calling lp_logon_script() and standard_sub() we have */ -/* made sure all macros are fully substituted and available */ - logon_script = lp_logon_script(); - standard_sub( cnum, logon_script ); - PACKS(&desc,"z", logon_script); /* script path */ -/* End of JHT mods */ - - PACKI(&desc,"D",0x00000000); /* reserved */ - } - - *rdata_len = desc.usedlen; - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,desc.neededlen); - - DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode)); - return(True); -} - - -/**************************************************************************** - api_WAccessGetUserPerms - ****************************************************************************/ -static BOOL api_WAccessGetUserPerms(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *user = skip_string(str2,1); - char *resource = skip_string(user,1); - - DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource)); - - /* check it's a supported varient */ - if (strcmp(str1,"zzh") != 0) return False; - if (strcmp(str2,"") != 0) return False; - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,0); /* errorcode */ - SSVAL(*rparam,2,0); /* converter word */ - SSVAL(*rparam,4,0x7f); /* permission flags */ - - return(True); -} - -/**************************************************************************** - api_WPrintJobEnumerate - ****************************************************************************/ -static BOOL api_WPrintJobGetInfo(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel,cbBuf; - int count; - int i; - int snum; - int job; - struct pack_desc desc; - print_queue_struct *queue=NULL; - print_status_struct status; - - uLevel = SVAL(p,2); - cbBuf = SVAL(p,4); - - bzero(&desc,sizeof(desc)); - bzero(&status,sizeof(status)); - - DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0))); - - /* check it's a supported varient */ - if (strcmp(str1,"WWrLh") != 0) return False; - if (!check_printjob_info(&desc,uLevel,str2)) return False; - - printjob_decode(SVAL(p,0), &snum, &job); - - if (snum < 0 || !VALID_SNUM(snum)) return(False); - - count = get_printqueue(snum,cnum,&queue,&status); - for (i = 0; i < count; i++) { - if ((queue[i].job & 0xFF) == job) break; - } - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - - if (init_package(&desc,1,0)) { - if (i < count) { - fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i); - *rdata_len = desc.usedlen; - } - else { - desc.errcode = NERR_JobNotFound; - *rdata_len = 0; - } - } - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,desc.neededlen); - - if (queue) free(queue); - - DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode)); - return(True); -} - -static BOOL api_WPrintJobEnumerate(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - char* name = p; - int uLevel,cbBuf; - int count; - int i, succnt=0; - int snum; - struct pack_desc desc; - print_queue_struct *queue=NULL; - print_status_struct status; - - bzero(&desc,sizeof(desc)); - bzero(&status,sizeof(status)); - - p = skip_string(p,1); - uLevel = SVAL(p,0); - cbBuf = SVAL(p,2); - - DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name)); - - /* check it's a supported varient */ - if (strcmp(str1,"zWrLeh") != 0) return False; - if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */ - if (!check_printjob_info(&desc,uLevel,str2)) return False; - - snum = lp_servicenumber(name); - if (snum < 0 && pcap_printername_ok(name,NULL)) { - int pnum = lp_servicenumber(PRINTERS_NAME); - if (pnum >= 0) { - lp_add_printer(name,pnum); - snum = lp_servicenumber(name); - } - } - - if (snum < 0 || !VALID_SNUM(snum)) return(False); - - count = get_printqueue(snum,cnum,&queue,&status); - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - - if (init_package(&desc,count,0)) { - succnt = 0; - for (i = 0; i < count; i++) { - fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i); - if (desc.errcode == NERR_Success) succnt = i+1; - } - } - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,count); - - if (queue) free(queue); - - DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode)); - return(True); -} - -static int check_printdest_info(struct pack_desc* desc, - int uLevel, char* id) -{ - desc->subformat = NULL; - switch( uLevel ) { - case 0: desc->format = "B9"; break; - case 1: desc->format = "B9B21WWzW"; break; - case 2: desc->format = "z"; break; - case 3: desc->format = "zzzWWzzzWW"; break; - default: return False; - } - if (strcmp(desc->format,id) != 0) return False; - return True; -} - -static void fill_printdest_info(int cnum, int snum, int uLevel, - struct pack_desc* desc) -{ - char buf[100]; - strncpy(buf,SERVICE(snum),sizeof(buf)-1); - buf[sizeof(buf)-1] = 0; - strupper(buf); - if (uLevel <= 1) { - PACKS(desc,"B9",buf); /* szName */ - if (uLevel == 1) { - PACKS(desc,"B21",""); /* szUserName */ - PACKI(desc,"W",0); /* uJobId */ - PACKI(desc,"W",0); /* fsStatus */ - PACKS(desc,"z",""); /* pszStatus */ - PACKI(desc,"W",0); /* time */ - } - } - if (uLevel == 2 || uLevel == 3) { - PACKS(desc,"z",buf); /* pszPrinterName */ - if (uLevel == 3) { - PACKS(desc,"z",""); /* pszUserName */ - PACKS(desc,"z",""); /* pszLogAddr */ - PACKI(desc,"W",0); /* uJobId */ - PACKI(desc,"W",0); /* fsStatus */ - PACKS(desc,"z",""); /* pszStatus */ - PACKS(desc,"z",""); /* pszComment */ - PACKS(desc,"z","NULL"); /* pszDrivers */ - PACKI(desc,"W",0); /* time */ - PACKI(desc,"W",0); /* pad1 */ - } - } -} - -static BOOL api_WPrintDestGetInfo(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - char* PrinterName = p; - int uLevel,cbBuf; - struct pack_desc desc; - int snum; - - bzero(&desc,sizeof(desc)); - - p = skip_string(p,1); - uLevel = SVAL(p,0); - cbBuf = SVAL(p,2); - - DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName)); - - /* check it's a supported varient */ - if (strcmp(str1,"zWrLh") != 0) return False; - if (!check_printdest_info(&desc,uLevel,str2)) return False; - - snum = lp_servicenumber(PrinterName); - if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) { - int pnum = lp_servicenumber(PRINTERS_NAME); - if (pnum >= 0) { - lp_add_printer(PrinterName,pnum); - snum = lp_servicenumber(PrinterName); - } - } - - if (snum < 0) { - *rdata_len = 0; - desc.errcode = NERR_DestNotFound; - desc.neededlen = 0; - } - else { - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - if (init_package(&desc,1,0)) { - fill_printdest_info(cnum,snum,uLevel,&desc); - } - *rdata_len = desc.usedlen; - } - - *rparam_len = 6; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,desc.neededlen); - - DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode)); - return(True); -} - -static BOOL api_WPrintDestEnum(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel,cbBuf; - int queuecnt; - int i, n, succnt=0; - struct pack_desc desc; - int services = lp_numservices(); - - bzero(&desc,sizeof(desc)); - - uLevel = SVAL(p,0); - cbBuf = SVAL(p,2); - - DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel)); - - /* check it's a supported varient */ - if (strcmp(str1,"WrLeh") != 0) return False; - if (!check_printdest_info(&desc,uLevel,str2)) return False; - - queuecnt = 0; - for (i = 0; i < services; i++) - if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) - queuecnt++; - - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - if (init_package(&desc,queuecnt,0)) { - succnt = 0; - n = 0; - for (i = 0; i < services; i++) { - if (lp_snum_ok(i) && lp_print_ok(i) && lp_browseable(i)) { - fill_printdest_info(cnum,i,uLevel,&desc); - n++; - if (desc.errcode == NERR_Success) succnt = n; - } - } - } - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,queuecnt); - - DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode)); - return(True); -} - -static BOOL api_WPrintDriverEnum(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel,cbBuf; - int succnt; - struct pack_desc desc; - - bzero(&desc,sizeof(desc)); - - uLevel = SVAL(p,0); - cbBuf = SVAL(p,2); - - DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel)); - - /* check it's a supported varient */ - if (strcmp(str1,"WrLeh") != 0) return False; - if (uLevel != 0 || strcmp(str2,"B41") != 0) return False; - - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - if (init_package(&desc,1,0)) { - PACKS(&desc,"B41","NULL"); - } - - succnt = (desc.errcode == NERR_Success ? 1 : 0); - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,1); - - DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode)); - return(True); -} - -static BOOL api_WPrintQProcEnum(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel,cbBuf; - int succnt; - struct pack_desc desc; - - bzero(&desc,sizeof(desc)); - - uLevel = SVAL(p,0); - cbBuf = SVAL(p,2); - - DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel)); - - /* check it's a supported varient */ - if (strcmp(str1,"WrLeh") != 0) return False; - if (uLevel != 0 || strcmp(str2,"B13") != 0) return False; - - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - desc.base = *rdata; - desc.buflen = mdrcnt; - desc.format = str2; - if (init_package(&desc,1,0)) { - PACKS(&desc,"B13","lpd"); - } - - succnt = (desc.errcode == NERR_Success ? 1 : 0); - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,1); - - DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode)); - return(True); -} - -static BOOL api_WPrintPortEnum(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - char *str1 = param+2; - char *str2 = skip_string(str1,1); - char *p = skip_string(str2,1); - int uLevel,cbBuf; - int succnt; - struct pack_desc desc; - - bzero(&desc,sizeof(desc)); - - uLevel = SVAL(p,0); - cbBuf = SVAL(p,2); - - DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel)); - - /* check it's a supported varient */ - if (strcmp(str1,"WrLeh") != 0) return False; - if (uLevel != 0 || strcmp(str2,"B9") != 0) return False; - - if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt); - bzero(&desc,sizeof(desc)); - desc.base = *rdata; - desc.buflen = mdrcnt; - desc.format = str2; - if (init_package(&desc,1,0)) { - PACKS(&desc,"B13","lp0"); - } - - succnt = (desc.errcode == NERR_Success ? 1 : 0); - - *rdata_len = desc.usedlen; - - *rparam_len = 8; - *rparam = REALLOC(*rparam,*rparam_len); - SSVALS(*rparam,0,desc.errcode); - SSVAL(*rparam,2,0); - SSVAL(*rparam,4,succnt); - SSVAL(*rparam,6,1); - - DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode)); - return(True); -} - - -struct -{ - char * name; - char * pipename; - int subcommand; - BOOL (*fn) (); -} api_fd_commands [] = - { - { "SetNmdPpHndState", "lsarpc", 1, api_LsarpcSNPHS }, -#ifdef NTDOMAIN - { "TransactNmPipe", "lsarpc", 0x26, api_ntLsarpcTNP }, -#else - { "TransactNmPipe", "lsarpc", 0x26, api_LsarpcTNP }, -#endif - { NULL, NULL, -1, (BOOL (*)())api_Unsupported } - }; - -/**************************************************************************** - handle remote api calls delivered to a named pipe already opened. - ****************************************************************************/ -static int api_fd_reply(int cnum,uint16 vuid,char *outbuf, - uint16 *setup,char *data,char *params, - int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt) -{ - char *rdata = NULL; - char *rparam = NULL; - int rdata_len = 0; - int rparam_len = 0; - BOOL reply=False; - int i; - int fd; - int subcommand; - - /* First find out the name of this file. */ - if (suwcnt != 2) - { - DEBUG(0,("Unexpected named pipe transaction.\n")); - return(-1); - } - - /* Get the file handle and hence the file name. */ - fd = setup[1]; - subcommand = setup[0]; - - DEBUG(3,("Got API command %d on pipe %s ",subcommand,Files[fd].name)); - DEBUG(3,("(tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n", - tdscnt,tpscnt,mdrcnt,mprcnt)); - - for (i=0;api_fd_commands[i].name;i++) - if (strequal(api_fd_commands[i].pipename, Files[fd].name) && - api_fd_commands[i].subcommand == subcommand && - api_fd_commands[i].fn) - { - DEBUG(3,("Doing %s\n",api_fd_commands[i].name)); - break; - } - - rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024); - rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024); - - reply = api_fd_commands[i].fn(cnum,vuid,params,data,mdrcnt,mprcnt, - &rdata,&rparam,&rdata_len,&rparam_len); - - if (rdata_len > mdrcnt || - rparam_len > mprcnt) - { - reply = api_TooSmall(cnum,vuid,params,data,mdrcnt,mprcnt, - &rdata,&rparam,&rdata_len,&rparam_len); - } - - - /* if we get False back then it's actually unsupported */ - if (!reply) - api_Unsupported(cnum,vuid,params,data,mdrcnt,mprcnt, - &rdata,&rparam,&rdata_len,&rparam_len); - - /* now send the reply */ - send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0); - - if (rdata) - free(rdata); - if (rparam) - free(rparam); - - return(-1); -} - - - -/**************************************************************************** - the buffer was too small - ****************************************************************************/ -static BOOL api_TooSmall(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - *rparam_len = MIN(*rparam_len,mprcnt); - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; - - SSVAL(*rparam,0,NERR_BufTooSmall); - - DEBUG(3,("Supplied buffer too small in API command\n")); - - return(True); -} - - -/**************************************************************************** - the request is not supported - ****************************************************************************/ -static BOOL api_Unsupported(int cnum,uint16 vuid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - *rparam_len = 4; - *rparam = REALLOC(*rparam,*rparam_len); - - *rdata_len = 0; - - SSVAL(*rparam,0,NERR_notsupported); - SSVAL(*rparam,2,0); /* converter word */ - - DEBUG(3,("Unsupported API command\n")); - - return(True); -} - - - - -struct -{ - char *name; - int id; - BOOL (*fn)(); - int flags; -} api_commands[] = { - {"RNetShareEnum", 0, (BOOL (*)())api_RNetShareEnum,0}, - {"RNetShareGetInfo", 1, (BOOL (*)())api_RNetShareGetInfo,0}, - {"RNetServerGetInfo", 13, (BOOL (*)())api_RNetServerGetInfo,0}, - {"RNetUserGetInfo", 56, (BOOL (*)())api_RNetUserGetInfo,0}, - {"NetUserGetGroups", 59, (BOOL (*)())api_NetUserGetGroups,0}, - {"NetWkstaGetInfo", 63, (BOOL (*)())api_NetWkstaGetInfo,0}, - {"DosPrintQEnum", 69, (BOOL (*)())api_DosPrintQEnum,0}, - {"DosPrintQGetInfo", 70, (BOOL (*)())api_DosPrintQGetInfo,0}, - {"WPrintJobEnumerate",76, (BOOL (*)())api_WPrintJobEnumerate,0}, - {"WPrintJobGetInfo", 77, (BOOL (*)())api_WPrintJobGetInfo,0}, - {"RDosPrintJobDel", 81, (BOOL (*)())api_RDosPrintJobDel,0}, - {"RDosPrintJobPause", 82, (BOOL (*)())api_RDosPrintJobDel,0}, - {"RDosPrintJobResume",83, (BOOL (*)())api_RDosPrintJobDel,0}, - {"WPrintDestEnum", 84, (BOOL (*)())api_WPrintDestEnum,0}, - {"WPrintDestGetInfo", 85, (BOOL (*)())api_WPrintDestGetInfo,0}, - {"NetRemoteTOD", 91, (BOOL (*)())api_NetRemoteTOD,0}, - {"WPrintQueuePurge", 103, (BOOL (*)())api_WPrintQueuePurge,0}, - {"NetServerEnum", 104, (BOOL (*)())api_RNetServerEnum,0}, - {"WAccessGetUserPerms",105, (BOOL (*)())api_WAccessGetUserPerms,0}, - {"SetUserPassword", 115, (BOOL (*)())api_SetUserPassword,0}, - {"WWkstaUserLogon", 132, (BOOL (*)())api_WWkstaUserLogon,0}, - {"PrintJobInfo", 147, (BOOL (*)())api_PrintJobInfo,0}, - {"WPrintDriverEnum", 205, (BOOL (*)())api_WPrintDriverEnum,0}, - {"WPrintQProcEnum", 206, (BOOL (*)())api_WPrintQProcEnum,0}, - {"WPrintPortEnum", 207, (BOOL (*)())api_WPrintPortEnum,0}, - {NULL, -1, (BOOL (*)())api_Unsupported,0}}; - - -/**************************************************************************** - handle remote api calls - ****************************************************************************/ -static int api_reply(int cnum,uint16 vuid,char *outbuf,char *data,char *params, - int tdscnt,int tpscnt,int mdrcnt,int mprcnt) -{ - int api_command = SVAL(params,0); - char *rdata = NULL; - char *rparam = NULL; - int rdata_len = 0; - int rparam_len = 0; - BOOL reply=False; - int i; - - DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n", - api_command,params+2,skip_string(params+2,1), - tdscnt,tpscnt,mdrcnt,mprcnt)); - - for (i=0;api_commands[i].name;i++) - if (api_commands[i].id == api_command && api_commands[i].fn) - { - DEBUG(3,("Doing %s\n",api_commands[i].name)); - break; - } - - rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024); - rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024); - - reply = api_commands[i].fn(cnum,vuid,params,data,mdrcnt,mprcnt, - &rdata,&rparam,&rdata_len,&rparam_len); - - - if (rdata_len > mdrcnt || - rparam_len > mprcnt) - { - reply = api_TooSmall(cnum,vuid,params,data,mdrcnt,mprcnt, - &rdata,&rparam,&rdata_len,&rparam_len); - } - - - /* if we get False back then it's actually unsupported */ - if (!reply) - api_Unsupported(cnum,vuid,params,data,mdrcnt,mprcnt, - &rdata,&rparam,&rdata_len,&rparam_len); - - - - /* now send the reply */ - send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0); - - if (rdata) - free(rdata); - if (rparam) - free(rparam); - - return(-1); -} - -/**************************************************************************** - handle named pipe commands - ****************************************************************************/ -static int named_pipe(int cnum,uint16 vuid, char *outbuf,char *name, - uint16 *setup,char *data,char *params, - int suwcnt,int tdscnt,int tpscnt, - int msrcnt,int mdrcnt,int mprcnt) -{ - - if (strequal(name,"LANMAN")) - return(api_reply(cnum,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt)); - -if (strlen(name) < 1) - return(api_fd_reply(cnum,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt)); - - - DEBUG(3,("named pipe command on <%s> 0x%X setup1=%d\n", - name,(int)setup[0],(int)setup[1])); - - return(0); -} - - -/**************************************************************************** - reply to a SMBtrans - ****************************************************************************/ -int reply_trans(char *inbuf,char *outbuf) -{ - fstring name; - - char *data=NULL,*params=NULL; - uint16 *setup=NULL; - - int outsize = 0; - int cnum = SVAL(inbuf,smb_tid); - uint16 vuid = SVAL(inbuf,smb_uid); - - int tpscnt = SVAL(inbuf,smb_vwv0); - int tdscnt = SVAL(inbuf,smb_vwv1); - int mprcnt = SVAL(inbuf,smb_vwv2); - int mdrcnt = SVAL(inbuf,smb_vwv3); - int msrcnt = CVAL(inbuf,smb_vwv4); - BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0); - BOOL one_way = BITSETW(inbuf+smb_vwv5,1); - int pscnt = SVAL(inbuf,smb_vwv9); - int psoff = SVAL(inbuf,smb_vwv10); - int dscnt = SVAL(inbuf,smb_vwv11); - int dsoff = SVAL(inbuf,smb_vwv12); - int suwcnt = CVAL(inbuf,smb_vwv13); - - fstrcpy(name,smb_buf(inbuf)); - - if (dscnt > tdscnt || pscnt > tpscnt) { - exit_server("invalid trans parameters\n"); - } - - if (tdscnt) - { - data = (char *)malloc(tdscnt); - memcpy(data,smb_base(inbuf)+dsoff,dscnt); - } - if (tpscnt) - { - params = (char *)malloc(tpscnt); - memcpy(params,smb_base(inbuf)+psoff,pscnt); - } - - if (suwcnt) - { - int i; - setup = (uint16 *)malloc(suwcnt*sizeof(setup[0])); - for (i=0;i<suwcnt;i++) - setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD); - } - - - if (pscnt < tpscnt || dscnt < tdscnt) - { - /* We need to send an interim response then receive the rest - of the parameter/data bytes */ - outsize = set_message(outbuf,0,0,True); - show_msg(outbuf); - send_smb(Client,outbuf); - } - - /* receive the rest of the trans packet */ - while (pscnt < tpscnt || dscnt < tdscnt) - { - int pcnt,poff,dcnt,doff,pdisp,ddisp; - - if (!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT) || - CVAL(inbuf, smb_com) != SMBtrans) - { - DEBUG(2,("Invalid secondary trans2 packet\n")); - if (params) free(params); - if (data) free(data); - if (setup) free(setup); - return(ERROR(ERRSRV,ERRerror)); - } - - show_msg(inbuf); - - tpscnt = SVAL(inbuf,smb_vwv0); - tdscnt = SVAL(inbuf,smb_vwv1); - - pcnt = SVAL(inbuf,smb_vwv2); - poff = SVAL(inbuf,smb_vwv3); - pdisp = SVAL(inbuf,smb_vwv4); - - dcnt = SVAL(inbuf,smb_vwv5); - doff = SVAL(inbuf,smb_vwv6); - ddisp = SVAL(inbuf,smb_vwv7); - - pscnt += pcnt; - dscnt += dcnt; - - if (dscnt > tdscnt || pscnt > tpscnt) { - exit_server("invalid trans parameters\n"); - } - - if (pcnt) - memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt); - if (dcnt) - memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt); - } - - - DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",name,tdscnt,tpscnt,suwcnt)); - - - if (strncmp(name,"\\PIPE\\",strlen("\\PIPE\\")) == 0) - outsize = named_pipe(cnum,vuid,outbuf,name+strlen("\\PIPE\\"),setup,data,params, - suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt); - - - if (data) free(data); - if (params) free(params); - if (setup) free(setup); - - if (close_on_completion) - close_cnum(cnum,vuid); - - if (one_way) - return(-1); - - if (outsize == 0) - return(ERROR(ERRSRV,ERRnosupport)); - - return(outsize); -} diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c deleted file mode 100644 index b0a45ffb47c..00000000000 --- a/source/smbd/mangle.c +++ /dev/null @@ -1,673 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - Name mangling - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -extern int DEBUGLEVEL; -extern int case_default; -extern BOOL case_mangle; - -/**************************************************************************** -provide a checksum on a string -****************************************************************************/ -int str_checksum(char *s) -{ - int res = 0; - int c; - int i=0; - while (*s) - { - c = *s; - res ^= (c << (i % 15)) ^ (c >> (15-(i%15))); - s++; i++; - } - return(res); -} - -/**************************************************************************** -return True if a name is a special msdos reserved name -****************************************************************************/ -static BOOL is_reserved_msdos(char *fname) -{ - char upperFname[13]; - char *p; - - StrnCpy (upperFname, fname, 12); - - /* lpt1.txt and con.txt etc are also illegal */ - p=strchr(upperFname,'.'); - if (p) - *p='\0'; - strupper (upperFname); - if ((strcmp(upperFname,"CLOCK$") == 0) || - (strcmp(upperFname,"CON") == 0) || - (strcmp(upperFname,"AUX") == 0) || - (strcmp(upperFname,"COM1") == 0) || - (strcmp(upperFname,"COM2") == 0) || - (strcmp(upperFname,"COM3") == 0) || - (strcmp(upperFname,"COM4") == 0) || - (strcmp(upperFname,"LPT1") == 0) || - (strcmp(upperFname,"LPT2") == 0) || - (strcmp(upperFname,"LPT3") == 0) || - (strcmp(upperFname,"NUL") == 0) || - (strcmp(upperFname,"PRN") == 0)) - return (True) ; - - return (False); -} - - - -/**************************************************************************** -return True if a name is in 8.3 dos format -****************************************************************************/ -BOOL is_8_3(char *fname, BOOL check_case) -{ - int len; - char *dot_pos; - char *slash_pos = strrchr(fname,'/'); - int l; - - if (slash_pos) fname = slash_pos+1; - len = strlen(fname); - - DEBUG(5,("checking %s for 8.3\n",fname)); - - if (check_case && case_mangle) - switch (case_default) - { - case CASE_LOWER: - if (strhasupper(fname)) return(False); - break; - case CASE_UPPER: - if (strhaslower(fname)) return(False); - break; - } - - /* can't be longer than 12 chars */ - if (len == 0 || len > 12) - return(False); - - /* can't be an MS-DOS Special file such as lpt1 or even lpt1.txt */ - if (is_reserved_msdos(fname)) - return(False); - - /* can't contain invalid dos chars */ - /* Windows use the ANSI charset. - But filenames are translated in the PC charset. - This Translation may be more or less relaxed depending - the Windows application. */ - - /* %%% A nice improvment to name mangling would be to translate - filename to ANSI charset on the smb server host */ - - dot_pos = strchr(fname,'.'); - - { - char *p = fname; - if(lp_client_code_page() == KANJI_CODEPAGE) - { - dot_pos = 0; - while (*p) - { - if (is_shift_jis (*p)) - p += 2; - else if (is_kana (*p)) - p ++; - else - { - if (*p == '.' && !dot_pos) - dot_pos = (char *) p; - if (!isdoschar(*p)) - return(False); - p++; - } - } - } - else - { - while (*p) - { - if (!isdoschar(*p)) - return(False); - p++; - } - } - } - - /* no dot and less than 9 means OK */ - if (!dot_pos) - return(len <= 8); - - l = PTR_DIFF(dot_pos,fname); - - /* base must be at least 1 char except special cases . and .. */ - if (l == 0) - return(strcmp(fname,".") == 0 || strcmp(fname,"..") == 0); - - /* base can't be greater than 8 */ - if (l > 8) - return(False); - - if (lp_strip_dot() && - len - l == 1 && - !strchr(dot_pos+1,'.')) - { - *dot_pos = 0; - return(True); - } - - /* extension must be between 1 and 3 */ - if ( (len - l < 2 ) || (len - l > 4) ) - return(False); - - /* extension can't have a dot */ - if (strchr(dot_pos+1,'.')) - return(False); - - /* must be in 8.3 format */ - return(True); -} - - - -/* -keep a stack of name mangling results - just -so file moves and copies have a chance of working -*/ -fstring *mangled_stack = NULL; -int mangled_stack_size = 0; -int mangled_stack_len = 0; - -/**************************************************************************** -create the mangled stack -****************************************************************************/ -void create_mangled_stack(int size) -{ - if (mangled_stack) - { - free(mangled_stack); - mangled_stack_size = 0; - mangled_stack_len = 0; - } - if (size > 0) - mangled_stack = (fstring *)malloc(sizeof(fstring)*size); - if (mangled_stack) mangled_stack_size = size; -} - -/**************************************************************************** -push a mangled name onto the stack -****************************************************************************/ -static void push_mangled_name(char *s) -{ - int i; - char *p; - - if (!mangled_stack) - return; - - for (i=0;i<mangled_stack_len;i++) - if (strcmp(s,mangled_stack[i]) == 0) - { - array_promote(mangled_stack[0],sizeof(fstring),i); - return; - } - - memmove(mangled_stack[1],mangled_stack[0], - sizeof(fstring)*MIN(mangled_stack_len,mangled_stack_size-1)); - strcpy(mangled_stack[0],s); - p = strrchr(mangled_stack[0],'.'); - if (p && (!strhasupper(p+1)) && (strlen(p+1) < 4)) - *p = 0; - mangled_stack_len = MIN(mangled_stack_size,mangled_stack_len+1); -} - -/**************************************************************************** -check for a name on the mangled name stack -****************************************************************************/ -BOOL check_mangled_stack(char *s) -{ - int i; - pstring tmpname; - char extension[5]; - char *p = strrchr(s,'.'); - BOOL check_extension = False; - - extension[0] = 0; - - if (!mangled_stack) return(False); - - if (p) - { - check_extension = True; - StrnCpy(extension,p,4); - strlower(extension); /* XXXXXXX */ - } - - for (i=0;i<mangled_stack_len;i++) - { - strcpy(tmpname,mangled_stack[i]); - mangle_name_83(tmpname); - if (strequal(tmpname,s)) - { - strcpy(s,mangled_stack[i]); - break; - } - if (check_extension && !strchr(mangled_stack[i],'.')) - { - pstrcpy(tmpname,mangled_stack[i]); - strcat(tmpname,extension); - mangle_name_83(tmpname); - if (strequal(tmpname,s)) - { - strcpy(s,mangled_stack[i]); - strcat(s,extension); - break; - } - } - } - - if (i < mangled_stack_len) - { - DEBUG(3,("Found %s on mangled stack as %s\n",s,mangled_stack[i])); - array_promote(mangled_stack[0],sizeof(fstring),i); - return(True); - } - - return(False); -} - -static char *map_filename(char *s, /* This is null terminated */ - char *pattern, /* This isn't. */ - int len) /* This is the length of pattern. */ -{ - static pstring matching_bit; /* The bit of the string which matches */ - /* a * in pattern if indeed there is a * */ - char *sp; /* Pointer into s. */ - char *pp; /* Pointer into p. */ - char *match_start; /* Where the matching bit starts. */ - pstring pat; - - StrnCpy(pat, pattern, len); /* Get pattern into a proper string! */ - pstrcpy(matching_bit,""); /* Match but no star gets this. */ - pp = pat; /* Initialise the pointers. */ - sp = s; - if ((len == 1) && (*pattern == '*')) { - return NULL; /* Impossible, too ambiguous for */ - /* words! */ - } - - while ((*sp) /* Not the end of the string. */ - && (*pp) /* Not the end of the pattern. */ - && (*sp == *pp) /* The two match. */ - && (*pp != '*')) { /* No wildcard. */ - sp++; /* Keep looking. */ - pp++; - } - if (!*sp && !*pp) /* End of pattern. */ - return matching_bit; /* Simple match. Return empty string. */ - if (*pp == '*') { - pp++; /* Always interrested in the chacter */ - /* after the '*' */ - if (!*pp) { /* It is at the end of the pattern. */ - StrnCpy(matching_bit, s, sp-s); - return matching_bit; - } else { - /* The next character in pattern must match a character further */ - /* along s than sp so look for that character. */ - match_start = sp; - while ((*sp) /* Not the end of s. */ - && (*sp != *pp)) /* Not the same */ - sp++; /* Keep looking. */ - if (!*sp) { /* Got to the end without a match. */ - return NULL; - } else { /* Still hope for a match. */ - /* Now sp should point to a matching character. */ - StrnCpy(matching_bit, match_start, sp-match_start); - /* Back to needing a stright match again. */ - while ((*sp) /* Not the end of the string. */ - && (*pp) /* Not the end of the pattern. */ - && (*sp == *pp)) { /* The two match. */ - sp++; /* Keep looking. */ - pp++; - } - if (!*sp && !*pp) /* Both at end so it matched */ - return matching_bit; - else - return NULL; - } - } - } - return NULL; /* No match. */ -} - - -/* this is the magic char used for mangling */ -char magic_char = '~'; - - -/**************************************************************************** -determine whther is name could be a mangled name -****************************************************************************/ -BOOL is_mangled(char *s) -{ - char *m = strchr(s,magic_char); - if (!m) return(False); - - /* we use two base 36 chars efore the extension */ - if (m[1] == '.' || m[1] == 0 || - m[2] == '.' || m[2] == 0 || - (m[3] != '.' && m[3] != 0)) - return(is_mangled(m+1)); - - /* it could be */ - return(True); -} - - - -/**************************************************************************** -return a base 36 character. v must be from 0 to 35. -****************************************************************************/ -static char base36(unsigned int v) -{ - static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - return basechars[v % 36]; -} - - -static void do_fwd_mangled_map(char *s, char *MangledMap) -{ - /* MangledMap is a series of name pairs in () separated by spaces. - * If s matches the first of the pair then the name given is the - * second of the pair. A * means any number of any character and if - * present in the second of the pair as well as the first the - * matching part of the first string takes the place of the * in the - * second. - * - * I wanted this so that we could have RCS files which can be used - * by UNIX and DOS programs. My mapping string is (RCS rcs) which - * converts the UNIX RCS file subdirectory to lowercase thus - * preventing mangling. - */ - char *start=MangledMap; /* Use this to search for mappings. */ - char *end; /* Used to find the end of strings. */ - char *match_string; - pstring new_string; /* Make up the result here. */ - char *np; /* Points into new_string. */ - - DEBUG(5,("Mangled Mapping '%s' map '%s'\n", s, MangledMap)); - while (*start) { - while ((*start) && (*start != '(')) - start++; - if (!*start) - continue; /* Always check for the end. */ - start++; /* Skip the ( */ - end = start; /* Search for the ' ' or a ')' */ - DEBUG(5,("Start of first in pair '%s'\n", start)); - while ((*end) && !((*end == ' ') || (*end == ')'))) - end++; - if (!*end) { - start = end; - continue; /* Always check for the end. */ - } - DEBUG(5,("End of first in pair '%s'\n", end)); - if ((match_string = map_filename(s, start, end-start))) { - DEBUG(5,("Found a match\n")); - /* Found a match. */ - start = end+1; /* Point to start of what it is to become. */ - DEBUG(5,("Start of second in pair '%s'\n", start)); - end = start; - np = new_string; - while ((*end) /* Not the end of string. */ - && (*end != ')') /* Not the end of the pattern. */ - && (*end != '*')) /* Not a wildcard. */ - *np++ = *end++; - if (!*end) { - start = end; - continue; /* Always check for the end. */ - } - if (*end == '*') { - pstrcpy(np, match_string); - np += strlen(match_string); - end++; /* Skip the '*' */ - while ((*end) /* Not the end of string. */ - && (*end != ')') /* Not the end of the pattern. */ - && (*end != '*')) /* Not a wildcard. */ - *np++ = *end++; - } - if (!*end) { - start = end; - continue; /* Always check for the end. */ - } - *np++ = '\0'; /* NULL terminate it. */ - DEBUG(5,("End of second in pair '%s'\n", end)); - pstrcpy(s, new_string); /* Substitute with the new name. */ - DEBUG(5,("s is now '%s'\n", s)); - } - start = end; /* Skip a bit which cannot be wanted */ - /* anymore. */ - start++; - } -} - -/**************************************************************************** -do the actual mangling to 8.3 format -****************************************************************************/ -void mangle_name_83(char *s) -{ - int csum = str_checksum(s); - char *p; - char extension[4]; - char base[9]; - int baselen = 0; - int extlen = 0; - - extension[0]=0; - base[0]=0; - - p = strrchr(s,'.'); - if (p && (strlen(p+1)<4) ) - { - BOOL all_normal = (strisnormal(p+1)); /* XXXXXXXXX */ - if (all_normal && p[1] != 0) - { - *p = 0; - csum = str_checksum(s); - *p = '.'; - } - } - - - strupper(s); - - DEBUG(5,("Mangling name %s to ",s)); - - if (p) - { - if (p == s) - strcpy(extension,"___"); - else - { - *p++ = 0; - while (*p && extlen < 3) - { - if(lp_client_code_page() == KANJI_CODEPAGE) - { - if (is_shift_jis (*p)) - { - if (extlen < 2) - { - extension[extlen++] = p[0]; - extension[extlen++] = p[1]; - } - else - { - extension[extlen++] = base36 (((unsigned char) *p) % 36); - } - p += 2; - } - else if (is_kana (*p)) - { - extension[extlen++] = p[0]; - p++; - } - else - { - if (isdoschar (*p) && *p != '.') - extension[extlen++] = p[0]; - p++; - } - } - else - { - if (isdoschar(*p) && *p != '.') - extension[extlen++] = *p; - p++; - } - } - extension[extlen] = 0; - } - } - - p = s; - - while (*p && baselen < 5) - { - if(lp_client_code_page() == KANJI_CODEPAGE) - { - if (is_shift_jis (*p)) - { - if (baselen < 4) - { - base[baselen++] = p[0]; - base[baselen++] = p[1]; - } - else - { - base[baselen++] = base36 (((unsigned char) *p) % 36); - } - p += 2; - } - else if (is_kana (*p)) - { - base[baselen++] = p[0]; - p++; - } - else - { - if (isdoschar (*p) && *p != '.') - base[baselen++] = p[0]; - p++; - } - } - else - { - if (isdoschar(*p) && *p != '.') - base[baselen++] = *p; - p++; - } - } - base[baselen] = 0; - - csum = csum % (36*36); - - sprintf(s,"%s%c%c%c",base,magic_char,base36(csum/36),base36(csum%36)); - - if (*extension) - { - strcat(s,"."); - strcat(s,extension); - } - DEBUG(5,("%s\n",s)); -} - - - -/******************************************************************* - work out if a name is illegal, even for long names - ******************************************************************/ -static BOOL illegal_name(char *name) -{ - static unsigned char illegal[256]; - static BOOL initialised=False; - unsigned char *s; - - if (!initialised) - { - char *ill = "*\\/?<>|\":{}"; - initialised = True; - - bzero((char *)illegal,256); - for (s = (unsigned char *)ill; *s; s++) - illegal[*s] = True; - } - - if(lp_client_code_page() == KANJI_CODEPAGE) - { - for (s = (unsigned char *)name; *s;) { - if (is_shift_jis (*s)) { - s += 2; - } else if (illegal[*s]) { - return(True); - } else { - s++; - } - } - } - else - { - for (s = (unsigned char *)name;*s;s++) - if (illegal[*s]) return(True); - } - - return(False); -} - - -/**************************************************************************** -convert a filename to DOS format. return True if successful. -****************************************************************************/ -BOOL name_map_mangle(char *OutName,BOOL need83,int snum) -{ -#ifdef MANGLE_LONG_FILENAMES - if (!need83 && illegal_name(OutName)) need83 = True; -#endif - - /* apply any name mappings */ - { - char *map = lp_mangled_map(snum); - if (map && *map) - do_fwd_mangled_map(OutName,map); - } - - /* check if it's already in 8.3 format */ - if (need83 && !is_8_3(OutName, True)) { - if (!lp_manglednames(snum)) return(False); - - /* mangle it into 8.3 */ - push_mangled_name(OutName); - mangle_name_83(OutName); - } - - return(True); -} - diff --git a/source/smbd/message.c b/source/smbd/message.c deleted file mode 100644 index 64253932abb..00000000000 --- a/source/smbd/message.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - SMB messaging - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* - This file handles the messaging system calls for winpopup style - messages -*/ - - -#include "includes.h" - -/* look in server.c for some explanation of these variables */ -extern int DEBUGLEVEL; - - -static char msgbuf[1600]; -static int msgpos=0; -static fstring msgfrom=""; -static fstring msgto=""; - -/**************************************************************************** -deliver the message -****************************************************************************/ -static void msg_deliver(void) -{ - pstring s; - fstring name; - int i; - int fd; - - if (! (*lp_msg_command())) - { - DEBUG(1,("no messaging command specified\n")); - msgpos = 0; - return; - } - - /* put it in a temporary file */ - sprintf(s,"%s/msg.XXXXXX",tmpdir()); - fstrcpy(name,(char *)mktemp(s)); - - fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_EXCL,0600); - if (fd == -1) { - DEBUG(1,("can't open message file %s\n",name)); - return; - } - - for (i=0;i<msgpos;) { - if (msgbuf[i]=='\r' && i<(msgpos-1) && msgbuf[i+1]=='\n') { - i++; continue; - } - write(fd,&msgbuf[i++],1); - } - close(fd); - - - /* run the command */ - if (*lp_msg_command()) - { - pstrcpy(s,lp_msg_command()); - string_sub(s,"%s",name); - string_sub(s,"%f",msgfrom); - string_sub(s,"%t",msgto); - standard_sub(-1,s); - smbrun(s,NULL,False); - } - - msgpos = 0; -} - - - -/**************************************************************************** - reply to a sends -****************************************************************************/ -int reply_sends(char *inbuf,char *outbuf) -{ - int len; - char *orig,*dest,*msg; - int outsize = 0; - - msgpos = 0; - - - if (! (*lp_msg_command())) - return(ERROR(ERRSRV,ERRmsgoff)); - - outsize = set_message(outbuf,0,0,True); - - orig = smb_buf(inbuf)+1; - dest = skip_string(orig,1)+1; - msg = skip_string(dest,1)+1; - - fstrcpy(msgfrom,orig); - fstrcpy(msgto,dest); - - len = SVAL(msg,0); - len = MIN(len,1600-msgpos); - - memcpy(&msgbuf[msgpos],msg+2,len); - msgpos += len; - - DEBUG(3,("%s SMBsends (from %s to %s)\n",timestring(),orig,dest)); - - msg_deliver(); - - return(outsize); -} - - -/**************************************************************************** - reply to a sendstrt -****************************************************************************/ -int reply_sendstrt(char *inbuf,char *outbuf) -{ - char *orig,*dest; - int outsize = 0; - - if (! (*lp_msg_command())) - return(ERROR(ERRSRV,ERRmsgoff)); - - outsize = set_message(outbuf,1,0,True); - - msgpos = 0; - - orig = smb_buf(inbuf)+1; - dest = skip_string(orig,1)+1; - - fstrcpy(msgfrom,orig); - fstrcpy(msgto,dest); - - DEBUG(3,("%s SMBsendstrt (from %s to %s)\n",timestring(),msgfrom,msgto)); - - return(outsize); -} - - -/**************************************************************************** - reply to a sendtxt -****************************************************************************/ -int reply_sendtxt(char *inbuf,char *outbuf) -{ - int len; - int outsize = 0; - char *msg; - - if (! (*lp_msg_command())) - return(ERROR(ERRSRV,ERRmsgoff)); - - outsize = set_message(outbuf,0,0,True); - - msg = smb_buf(inbuf) + 1; - - len = SVAL(msg,0); - len = MIN(len,1600-msgpos); - - memcpy(&msgbuf[msgpos],msg+2,len); - msgpos += len; - - DEBUG(3,("%s SMBsendtxt\n",timestring())); - - return(outsize); -} - - -/**************************************************************************** - reply to a sendend -****************************************************************************/ -int reply_sendend(char *inbuf,char *outbuf) -{ - int outsize = 0; - - if (! (*lp_msg_command())) - return(ERROR(ERRSRV,ERRmsgoff)); - - outsize = set_message(outbuf,0,0,True); - - DEBUG(3,("%s SMBsendend\n",timestring())); - - msg_deliver(); - - return(outsize); -} - diff --git a/source/smbd/password.c b/source/smbd/password.c deleted file mode 100644 index f4d94791cf3..00000000000 --- a/source/smbd/password.c +++ /dev/null @@ -1,1707 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - Password and authentication handling - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -#if (defined(NETGROUP) && defined (AUTOMOUNT)) -#include "rpcsvc/ypclnt.h" -#endif - -extern int DEBUGLEVEL; -extern int Protocol; - -/* users from session setup */ -static pstring session_users=""; - -/* these are kept here to keep the string_combinations function simple */ -static char this_user[100]=""; -static char this_salt[100]=""; -static char this_crypted[100]=""; - -/* Data to do lanman1/2 password challenge. */ -static unsigned char saved_challenge[8]; -static BOOL challenge_sent=False; - -/******************************************************************* -Get the next challenge value - no repeats. -********************************************************************/ -void generate_next_challenge(char *challenge) -{ - unsigned char buf[16]; - static int counter = 0; - struct timeval tval; - int v1,v2; - - /* get a sort-of random number */ - GetTimeOfDay(&tval); - v1 = (counter++) + getpid() + tval.tv_sec; - v2 = (counter++) * getpid() + tval.tv_usec; - SIVAL(challenge,0,v1); - SIVAL(challenge,4,v2); - - /* mash it up with md4 */ - mdfour(buf, (unsigned char *)challenge, 8); - - memcpy(saved_challenge, buf, 8); - memcpy(challenge,buf,8); - challenge_sent = True; -} - -/******************************************************************* -set the last challenge sent, usually from a password server -********************************************************************/ -BOOL set_challenge(char *challenge) -{ - memcpy(saved_challenge,challenge,8); - challenge_sent = True; - return(True); -} - -/******************************************************************* -get the last challenge sent -********************************************************************/ -BOOL last_challenge(char *challenge) -{ - if (!challenge_sent) return(False); - memcpy(challenge,saved_challenge,8); - return(True); -} - -/* this holds info on user ids that are already validated for this VC */ -static user_struct *validated_users = NULL; -static int num_validated_users = 0; - -/**************************************************************************** -check if a uid has been validated, and return an pointer to the user_struct -if it has. NULL if not. vuid is biased by an offset. This allows us to -tell random client vuid's (normally zero) from valid vuids. -****************************************************************************/ -user_struct *get_valid_user_struct(uint16 vuid) -{ - if(vuid == UID_FIELD_INVALID) - return NULL; - vuid -= VUID_OFFSET; - if((vuid >= (uint16)num_validated_users) || - (validated_users[vuid].uid == -1) || (validated_users[vuid].gid == -1)) - return NULL; - return &validated_users[vuid]; -} - -/**************************************************************************** -invalidate a uid -****************************************************************************/ -void invalidate_vuid(uint16 vuid) -{ - user_struct *vuser = get_valid_user_struct(vuid); - if(vuser == 0) - return; - - vuser->uid = -1; - vuser->gid = -1; - vuser->user_ngroups = 0; - if(vuser->user_groups && - (vuser->user_groups != (gid_t *)vuser->user_igroups)) - free(vuser->user_groups); - vuser->user_groups = NULL; - if(vuser->user_igroups) - free(vuser->user_igroups); - vuser->user_igroups = NULL; -} - - -/**************************************************************************** -return a validated username -****************************************************************************/ -char *validated_username(uint16 vuid) -{ - user_struct *vuser = get_valid_user_struct(vuid); - if(vuser == 0) - return 0; - return(vuser->name); -} - -/**************************************************************************** -register a uid/name pair as being valid and that a valid password -has been given. vuid is biased by an offset. This allows us to -tell random client vuid's (normally zero) from valid vuids. -****************************************************************************/ -uint16 register_vuid(int uid,int gid, char *name,BOOL guest) -{ - user_struct *vuser; - -#if (defined(NETGROUP) && defined (AUTOMOUNT)) - int nis_error; /* returned by yp all functions */ - char *nis_result; /* yp_match inits this */ - int nis_result_len; /* and set this */ - char *nis_domain; /* yp_get_default_domain inits this */ - char *nis_map = (char *)lp_nis_home_map_name(); - int home_server_len; -#endif - struct passwd *pwfile; /* for getting real name from passwd file */ - int real_name_len; - -#if 0 - /* - * After observing MS-Exchange services writing to a Samba share - * I belive this code is incorrect. Each service does it's own - * sessionsetup_and_X for the same user, and as each service shuts - * down, it does a user_logoff_and_X. As we are consolidating multiple - * sessionsetup_and_X's onto the same vuid here, when the first service - * shuts down, it invalidates all the open files for the other services. - * Hence I am removing this code and forcing each sessionsetup_and_X - * to get a new vuid. - * Jeremy Allison. (jallison@whistle.com). - */ - - int i; - for(i = 0; i < num_validated_users; i++) { - vuser = &validated_users[i]; - if( vuser->uid == uid ) - return (uint16)(i + VUID_OFFSET); /* User already validated */ - } -#endif - - validated_users = (user_struct *)Realloc(validated_users, - sizeof(user_struct)* - (num_validated_users+1)); - - if (!validated_users) - { - DEBUG(0,("Failed to realloc users struct!\n")); - num_validated_users = 0; - return UID_FIELD_INVALID; - } - - vuser = &validated_users[num_validated_users]; - num_validated_users++; - - vuser->uid = uid; - vuser->gid = gid; - vuser->guest = guest; - strcpy(vuser->name,name); - - vuser->user_ngroups = 0; - vuser->user_groups = NULL; - vuser->user_igroups = NULL; - - /* Find all the groups this uid is in and store them. - Used by become_user() */ - setup_groups(name,uid,gid, - &vuser->user_ngroups, - &vuser->user_igroups, - &vuser->user_groups); - - DEBUG(3,("uid %d registered to name %s\n",uid,name)); - -#if (defined(NETGROUP) && defined (AUTOMOUNT)) - vuser->home_share = NULL; - DEBUG(3, ("Setting default HOMESHR to: \\\\logon server\\HOMES\n")); - vuser->home_share = Realloc(vuser->home_share, 32); - strcpy(vuser->home_share,"\\\\%L\\HOMES"); - - if (nis_error = yp_get_default_domain(&nis_domain)) - DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error))); - DEBUG(3, ("NIS Domain: %s\n", nis_domain)); - - if (nis_error = yp_match(nis_domain, nis_map, vuser->name, strlen(vuser->name), - &nis_result, &nis_result_len)) - DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error))); - if (!nis_error && lp_nis_home_map()) { - home_server_len = strcspn(nis_result,":"); - DEBUG(3, ("NIS lookup succeeded\n\tHome server length: %d\n",home_server_len)); - vuser->home_share = (char *)Realloc(vuser->home_share, home_server_len+12); - DEBUG(3, ("\tAllocated %d bytes for HOMESHR\n",home_server_len+12 )); - strcpy(vuser->home_share,"\\\\"); - strncat(vuser->home_share, nis_result, home_server_len); - strcat(vuser->home_share,"\\homes"); - DEBUG(2,("\tUser = %s\n\tUID = %d\n\tNIS result = %s\n\tHOMESHR = %s\n", - vuser->name, vuser->uid, nis_result, vuser->home_share)); - } -#endif - - vuser->real_name = NULL; - DEBUG(3, ("Clearing default real name\n")); - vuser->real_name = Realloc(vuser->real_name, 15); - strcpy(vuser->real_name, "<Full Name>\0"); - if (lp_unix_realname()) { - if((pwfile=getpwnam(vuser->name))!= NULL) - { - DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos)); - real_name_len = strcspn(pwfile->pw_gecos, ","); - DEBUG(3, ("Real name length: %d\n", real_name_len)); - vuser->real_name = (char *)Realloc(vuser->real_name, real_name_len+1); - strncpy(vuser->real_name, pwfile->pw_gecos, real_name_len); - vuser->real_name[real_name_len]='\0'; - } - } - - return (uint16)((num_validated_users - 1) + VUID_OFFSET); -} - - -/**************************************************************************** -add a name to the session users list -****************************************************************************/ -void add_session_user(char *user) -{ - fstring suser; - StrnCpy(suser,user,sizeof(suser)-1); - - if (!Get_Pwnam(suser,True)) return; - - if (suser && *suser && !in_list(suser,session_users,False)) - { - if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring)) - DEBUG(1,("Too many session users??\n")); - else - { - strcat(session_users," "); - strcat(session_users,suser); - } - } -} - - -#ifdef NO_GETSPNAM -/* a fake shadow password routine which just fills a fake spwd struct - * with the sp_pwdp field. (sreiz@aie.nl) - */ -static struct spwd *getspnam(char *username) /* fake shadow password routine */ -{ - FILE *f; - char line[1024]; - static char pw[20]; - static struct spwd static_spwd; - - static_spwd.sp_pwdp=0; - if (!(f=fopen("/etc/master.passwd", "r"))) - return 0; - while (fgets(line, 1024, f)) { - if (!strncmp(line, username, strlen(username)) && - line[strlen(username)]==':') { /* found entry */ - char *p, *q; - - p=line+strlen(username)+1; - if ((q=strchr(p, ':'))) { - *q=0; - if (q-p+1>20) - break; - strcpy(pw, p); - static_spwd.sp_pwdp=pw; - } - break; - } - } - fclose(f); - if (static_spwd.sp_pwdp) - return &static_spwd; - return 0; -} -#endif - - -#ifdef OSF1_ENH_SEC -/**************************************************************************** -an enhanced crypt for OSF1 -****************************************************************************/ -static char *osf1_bigcrypt(char *password,char *salt1) -{ - static char result[AUTH_MAX_PASSWD_LENGTH] = ""; - char *p1; - char *p2=password; - char salt[3]; - int i; - int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS; - if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS) - parts++; - - StrnCpy(salt,salt1,2); - StrnCpy(result,salt1,2); - - for (i=0; i<parts;i++) - { - p1 = crypt(p2,salt); - strcat(result,p1+2); - StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2); - p2 += AUTH_CLEARTEXT_SEG_CHARS; - } - - return(result); -} -#endif - - -/**************************************************************************** -update the enhanced security database. Only relevant for OSF1 at the moment. -****************************************************************************/ -static void update_protected_database( char *user, BOOL result) -{ -#ifdef OSF1_ENH_SEC - struct pr_passwd *mypasswd; - time_t starttime; - - mypasswd = getprpwnam (user); - starttime = time (NULL); - - if (result) - { - mypasswd->ufld.fd_slogin = starttime; - mypasswd->ufld.fd_nlogins = 0; - - putprpwnam(user,mypasswd); - - DEBUG(3,("Update protected database for Account %s after succesful connection\n",user)); - } - else - { - mypasswd->ufld.fd_ulogin = starttime; - mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1; - if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries ) - { - mypasswd->uflg.fg_lock = 0; - DEBUG(3,("Account is disabled -- see Account Administrator.\n")); - } - putprpwnam ( user , mypasswd ); - DEBUG(3,("Update protected database for Account %s after refusing connection\n",user)); - } -#else - DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result))); -#endif -} - - -#ifdef USE_PAM -/******************************************************************* -check on PAM authentication -********************************************************************/ - -/* We first need some helper functions */ -#include <security/pam_appl.h> -/* Static variables used to communicate between the conversation function - * and the server_login function - */ -static char *PAM_username; -static char *PAM_password; - -/* PAM conversation function - * Here we assume (for now, at least) that echo on means login name, and - * echo off means password. - */ -static int PAM_conv (int num_msg, - struct pam_message **msg, - struct pam_response **resp, - void *appdata_ptr) { - int count = 0, replies = 0; - struct pam_response *reply = NULL; - int size = sizeof(struct pam_response); - - #define GET_MEM if (reply) realloc(reply, size); else reply = malloc(size); \ - if (!reply) return PAM_CONV_ERR; \ - size += sizeof(struct pam_response) - #define COPY_STRING(s) (s) ? strdup(s) : NULL - - for (count = 0; count < num_msg; count++) { - switch (msg[count]->msg_style) { - case PAM_PROMPT_ECHO_ON: - GET_MEM; - reply[replies].resp_retcode = PAM_SUCCESS; - reply[replies++].resp = COPY_STRING(PAM_username); - /* PAM frees resp */ - break; - case PAM_PROMPT_ECHO_OFF: - GET_MEM; - reply[replies].resp_retcode = PAM_SUCCESS; - reply[replies++].resp = COPY_STRING(PAM_password); - /* PAM frees resp */ - break; - case PAM_TEXT_INFO: - /* ignore it... */ - break; - case PAM_ERROR_MSG: - default: - /* Must be an error of some sort... */ - free (reply); - return PAM_CONV_ERR; - } - } - if (reply) *resp = reply; - return PAM_SUCCESS; -} -static struct pam_conv PAM_conversation = { - &PAM_conv, - NULL -}; - - -static BOOL pam_auth(char *this_user,char *password) -{ - pam_handle_t *pamh; - int pam_error; - - /* Now use PAM to do authentication. For now, we won't worry about - * session logging, only authentication. Bail out if there are any - * errors. Since this is a limited protocol, and an even more limited - * function within a server speaking this protocol, we can't be as - * verbose as would otherwise make sense. - * Query: should we be using PAM_SILENT to shut PAM up? - */ - #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \ - pam_end(pamh, 0); return False; \ - } - PAM_password = password; - PAM_username = this_user; - pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh); - PAM_BAIL; - pam_error = pam_authenticate(pamh, 0); - PAM_BAIL; - /* It is not clear to me that account management is the right thing - * to do, but it is not clear that it isn't, either. This can be - * removed if no account management should be done. Alternately, - * put a pam_allow.so entry in /etc/pam.conf for account handling. */ - pam_error = pam_acct_mgmt(pamh, 0); - PAM_BAIL; - pam_end(pamh, PAM_SUCCESS); - /* If this point is reached, the user has been authenticated. */ - return(True); -} -#endif - - -#ifdef AFS_AUTH -/******************************************************************* -check on AFS authentication -********************************************************************/ -static BOOL afs_auth(char *this_user,char *password) -{ - long password_expires = 0; - char *reason; - - /* For versions of AFS prior to 3.3, this routine has few arguments, */ - /* but since I can't find the old documentation... :-) */ - setpag(); - if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG, - this_user, - (char *) 0, /* instance */ - (char *) 0, /* cell */ - password, - 0, /* lifetime, default */ - &password_expires, /*days 'til it expires */ - 0, /* spare 2 */ - &reason) == 0) - return(True); - return(False); -} -#endif - - -#ifdef DFS_AUTH - -sec_login_handle_t my_dce_sec_context; -int dcelogin_atmost_once = 0; - -/******************************************************************* -check on a DCE/DFS authentication -********************************************************************/ -static BOOL dfs_auth(char *this_user,char *password) -{ - error_status_t err; - int err2; - int prterr; - boolean32 password_reset; - sec_passwd_rec_t my_dce_password; - sec_login_auth_src_t auth_src = sec_login_auth_src_network; - unsigned char dce_errstr[dce_c_error_string_len]; - - /* - * We only go for a DCE login context if the given password - * matches that stored in the local password file.. - * Assumes local passwd file is kept in sync w/ DCE RGY! - */ - - if (!strcmp((char *)crypt(password,this_salt),this_crypted) || - dcelogin_atmost_once) - return(False); - - if (sec_login_setup_identity( - (unsigned char *)this_user, - sec_login_no_flags, - &my_dce_sec_context, - &err) == 0) - { - dce_error_inq_text(err, dce_errstr, &err2); - DEBUG(0,("DCE Setup Identity for %s failed: %s\n", - this_user,dce_errstr)); - return(False); - } - - my_dce_password.version_number = sec_passwd_c_version_none; - my_dce_password.pepper = NULL; - my_dce_password.key.key_type = sec_passwd_plain; - my_dce_password.key.tagged_union.plain = (idl_char *)password; - - if (sec_login_valid_and_cert_ident(my_dce_sec_context, - &my_dce_password, - &password_reset, - &auth_src, - &err) == 0 ) - { - dce_error_inq_text(err, dce_errstr, &err2); - DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n", - this_user,dce_errstr)); - - return(False); - } - - sec_login_set_context(my_dce_sec_context, &err); - if (err != error_status_ok ) - { - dce_error_inq_text(err, dce_errstr, &err2); - DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n", - this_user,dce_errstr)); - sec_login_purge_context(my_dce_sec_context, &err); - return(False); - } - else - { - DEBUG(0,("DCE login succeeded for principal %s on pid %d\n", - this_user, getpid())); - } - - dcelogin_atmost_once = 1; - return (True); -} - -void dfs_unlogin(void) -{ - error_status_t err; - int err2; - unsigned char dce_errstr[dce_c_error_string_len]; - - sec_login_purge_context(my_dce_sec_context, &err); - if (err != error_status_ok ) - { - dce_error_inq_text(err, dce_errstr, &err2); - DEBUG(0,("DCE purge login context failed for server instance %d: %s\n", - getpid(), dce_errstr)); - } -} - -#endif - -#ifdef KRB5_AUTH -/******************************************************************* -check on Kerberos authentication -********************************************************************/ -static BOOL krb5_auth(char *this_user,char *password) -{ - krb5_data tgtname = { - 0, - KRB5_TGS_NAME_SIZE, - KRB5_TGS_NAME - }; - krb5_context kcontext; - krb5_principal kprinc; - krb5_principal server; - krb5_creds kcreds; - int options = 0; - krb5_address **addrs = (krb5_address **)0; - krb5_preauthtype *preauth = NULL; - krb5_keytab keytab = NULL; - krb5_timestamp now; - krb5_ccache ccache = NULL; - int retval; - char *name; - - if ( retval=krb5_init_context(&kcontext)) - { - return(False); - } - - if ( retval = krb5_timeofday(kcontext, &now) ) - { - return(False); - } - - if ( retval = krb5_cc_default(kcontext, &ccache) ) - { - return(False); - } - - if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) ) - { - return(False); - } - - memset((char *)&kcreds, 0, sizeof(kcreds)); - - kcreds.client = kprinc; - - if ((retval = krb5_build_principal_ext(kcontext, &server, - krb5_princ_realm(kcontext, kprinc)->length, - krb5_princ_realm(kcontext, kprinc)->data, - tgtname.length, - tgtname.data, - krb5_princ_realm(kcontext, kprinc)->length, - krb5_princ_realm(kcontext, kprinc)->data, - 0))) - { - return(False); - } - - kcreds.server = server; - - retval = krb5_get_in_tkt_with_password(kcontext, - options, - addrs, - NULL, - preauth, - password, - 0, - &kcreds, - 0); - - if ( retval ) - { - return(False); - } - - return(True); -} -#endif /* KRB5_AUTH */ - -#ifdef LINUX_BIGCRYPT -/**************************************************************************** -an enhanced crypt for Linux to handle password longer than 8 characters -****************************************************************************/ -static int linux_bigcrypt(char *password,char *salt1, char *crypted) -{ -#define LINUX_PASSWORD_SEG_CHARS 8 - char salt[3]; - int i; - - StrnCpy(salt,salt1,2); - crypted +=2; - - for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) { - char * p = crypt(password,salt) + 2; - if(strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0) - return(0); - password += LINUX_PASSWORD_SEG_CHARS; - crypted += strlen(p); - } - - return(1); -} -#endif - - -/**************************************************************************** -apply a function to upper/lower case combinations -of a string and return true if one of them returns true. -try all combinations with N uppercase letters. -offset is the first char to try and change (start with 0) -it assumes the string starts lowercased -****************************************************************************/ -static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(),int N) -{ - int len = strlen(s); - int i; - -#ifdef PASSWORD_LENGTH - len = MIN(len,PASSWORD_LENGTH); -#endif - - if (N <= 0 || offset >= len) - return(fn(s)); - - for (i=offset;i<(len-(N-1));i++) - { - char c = s[i]; - if (!islower(c)) continue; - s[i] = toupper(c); - if (string_combinations2(s,i+1,fn,N-1)) - return(True); - s[i] = c; - } - return(False); -} - -/**************************************************************************** -apply a function to upper/lower case combinations -of a string and return true if one of them returns true. -try all combinations with up to N uppercase letters. -offset is the first char to try and change (start with 0) -it assumes the string starts lowercased -****************************************************************************/ -static BOOL string_combinations(char *s,BOOL (*fn)(),int N) -{ - int n; - for (n=1;n<=N;n++) - if (string_combinations2(s,0,fn,n)) return(True); - return(False); -} - - - -/**************************************************************************** -core of password checking routine -****************************************************************************/ -BOOL password_check(char *password) -{ - -#ifdef USE_PAM -/* This falls through if the password check fails - - if NO_CRYPT is defined this causes an error msg - saying Warning - no crypt available - - if NO_CRYPT is NOT defined this is a potential security hole - as it may authenticate via the crypt call when PAM - settings say it should fail. - if (pam_auth(this_user,password)) return(True); -Hence we make a direct return to avoid a second chance!!! -*/ - return (pam_auth(this_user,password)); -#endif - -#ifdef AFS_AUTH - if (afs_auth(this_user,password)) return(True); -#endif - -#ifdef DFS_AUTH - if (dfs_auth(this_user,password)) return(True); -#endif - -#ifdef KRB5_AUTH - if (krb5_auth(this_user,password)) return(True); -#endif - -#ifdef PWDAUTH - if (pwdauth(this_user,password) == 0) - return(True); -#endif - -#ifdef OSF1_ENH_SEC - return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0); -#endif - -#ifdef ULTRIX_AUTH - return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0); -#endif - -#ifdef LINUX_BIGCRYPT - return(linux_bigcrypt(password,this_salt,this_crypted)); -#endif - -#ifdef NO_CRYPT - DEBUG(1,("Warning - no crypt available\n")); - return(False); -#else - return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0); -#endif -} - -/**************************************************************************** -core of smb password checking routine. -****************************************************************************/ -BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8) -{ - /* Finish the encryption of part_passwd. */ - unsigned char p21[21]; - unsigned char p24[24]; - - if(part_passwd == NULL) - DEBUG(10,("No password set - allowing access\n")); - /* No password set - always true ! */ - if(part_passwd == NULL) - return 1; - - memset(p21,'\0',21); - memcpy(p21,part_passwd,16); - E_P24(p21, c8, p24); -#if DEBUG_PASSWORD - { - int i; - DEBUG(100,("Part password (P16) was |")); - for(i = 0; i < 16; i++) - DEBUG(100,("%X ", (unsigned char)part_passwd[i])); - DEBUG(100,("|\n")); - DEBUG(100,("Password from client was |")); - for(i = 0; i < 24; i++) - DEBUG(100,("%X ", (unsigned char)password[i])); - DEBUG(100,("|\n")); - DEBUG(100,("Given challenge was |")); - for(i = 0; i < 8; i++) - DEBUG(100,("%X ", (unsigned char)c8[i])); - DEBUG(100,("|\n")); - DEBUG(100,("Value from encryption was |")); - for(i = 0; i < 24; i++) - DEBUG(100,("%X ", (unsigned char)p24[i])); - DEBUG(100,("|\n")); - } -#endif - return (memcmp(p24, password, 24) == 0); -} - -/**************************************************************************** -check if a username/password is OK -****************************************************************************/ -BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd) -{ - pstring pass2; - int level = lp_passwordlevel(); - struct passwd *pass; - char challenge[8]; - struct smb_passwd *smb_pass; - BOOL challenge_done = False; - - if (password) password[pwlen] = 0; - - if (pwlen == 24) - challenge_done = last_challenge(challenge); - -#if DEBUG_PASSWORD - if (challenge_done) - { - int i; - DEBUG(100,("checking user=[%s] pass=[",user)); - for( i = 0; i < 24; i++) - DEBUG(100,("%0x ", (unsigned char)password[i])); - DEBUG(100,("]\n")); - } else { - DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password)); - } -#endif - - if (!password) - return(False); - - if (((!*password) || (!pwlen)) && !lp_null_passwords()) - return(False); - - if (pwd && !user) - { - pass = (struct passwd *) pwd; - user = pass->pw_name; - } - else - pass = Get_Pwnam(user,True); - - DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done)); - - if((pwlen == 24) && challenge_done) - { - DEBUG(4,("Checking SMB password for user %s (l=24)\n",user)); - - if (!pass) - { - DEBUG(3,("Couldn't find user %s\n",user)); - return(False); - } - - smb_pass = get_smbpwnam(user); - if(!smb_pass) - { - DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user)); - return(False); - } - - /* Ensure the uid's match */ - if(smb_pass->smb_userid != pass->pw_uid) - { - DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n")); - return(False); - } - - if(Protocol >= PROTOCOL_NT1) - { - /* We have the NT MD4 hash challenge available - see if we can - use it (ie. does it exist in the smbpasswd file). - */ - if(smb_pass->smb_nt_passwd != NULL) - { - DEBUG(4,("Checking NT MD4 password\n")); - if(smb_password_check(password, - smb_pass->smb_nt_passwd, - (unsigned char *)challenge)) - { - update_protected_database(user,True); - return(True); - } - DEBUG(4,("NT MD4 password check failed\n")); - } - } - - /* Try against the lanman password */ - - if (smb_password_check(password, - smb_pass->smb_passwd, - (unsigned char *)challenge)) { - update_protected_database(user,True); - return(True); - } - - DEBUG(3,("Error smb_password_check failed\n")); - } - - DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen)); - - if (!pass) - { - DEBUG(3,("Couldn't find user %s\n",user)); - return(False); - } - -#ifdef SHADOW_PWD - { - struct spwd *spass; - - /* many shadow systems require you to be root to get the password, - in most cases this should already be the case when this - function is called, except perhaps for IPC password changing - requests */ - - spass = getspnam(pass->pw_name); - if (spass && spass->sp_pwdp) - pass->pw_passwd = spass->sp_pwdp; - } -#elif defined(IA_UINFO) - { - /* Need to get password with SVR4.2's ia_ functions instead of - get{sp,pw}ent functions. Required by UnixWare 2.x, tested on - version 2.1. (tangent@cyberport.com) */ - uinfo_t uinfo; - if (ia_openinfo(pass->pw_name, &uinfo) != -1) - ia_get_logpwd(uinfo, &(pass->pw_passwd)); - } -#endif - -#ifdef SecureWare - { - struct pr_passwd *pr_pw = getprpwnam(pass->pw_name); - if (pr_pw && pr_pw->ufld.fd_encrypt) - pass->pw_passwd = pr_pw->ufld.fd_encrypt; - } -#endif - -#ifdef HPUX_10_TRUSTED - { - struct pr_passwd *pr_pw = getprpwnam(pass->pw_name); - if (pr_pw && pr_pw->ufld.fd_encrypt) - pass->pw_passwd = pr_pw->ufld.fd_encrypt; - } -#endif - -#ifdef OSF1_ENH_SEC - { - struct pr_passwd *mypasswd; - DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user)); - mypasswd = getprpwnam (user); - if ( mypasswd ) - { - strcpy(pass->pw_name,mypasswd->ufld.fd_name); - strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt); - } - else - { - DEBUG(5,("No entry for user %s in protected database !\n",user)); - return(False); - } - } -#endif - -#ifdef ULTRIX_AUTH - { - AUTHORIZATION *ap = getauthuid( pass->pw_uid ); - if (ap) - { - strcpy( pass->pw_passwd, ap->a_password ); - endauthent(); - } - } -#endif - - /* extract relevant info */ - strcpy(this_user,pass->pw_name); - strcpy(this_salt,pass->pw_passwd); - strcpy(this_crypted,pass->pw_passwd); - - if (!*this_crypted) { - if (!lp_null_passwords()) { - DEBUG(2,("Disallowing access to %s due to null password\n",this_user)); - return(False); - } -#ifndef PWDAUTH - if (!*password) { - DEBUG(3,("Allowing access to %s with null password\n",this_user)); - return(True); - } -#endif - } - - /* try it as it came to us */ - if (password_check(password)) - { - update_protected_database(user,True); - return(True); - } - - /* if the password was given to us with mixed case then we don't - need to proceed as we know it hasn't been case modified by the - client */ - if (strhasupper(password) && strhaslower(password)) - return(False); - - /* make a copy of it */ - StrnCpy(pass2,password,sizeof(pstring)-1); - - /* try all lowercase */ - strlower(password); - if (password_check(password)) - { - update_protected_database(user,True); - return(True); - } - - /* give up? */ - if(level < 1) - { - update_protected_database(user,False); - - /* restore it */ - strcpy(password,pass2); - - return(False); - } - - /* last chance - all combinations of up to level chars upper! */ - strlower(password); - - if (string_combinations(password,password_check,level)) - { - update_protected_database(user,True); - return(True); - } - - update_protected_database(user,False); - - /* restore it */ - strcpy(password,pass2); - - return(False); -} - - - -/**************************************************************************** -check if a username is valid -****************************************************************************/ -BOOL user_ok(char *user,int snum) -{ - pstring valid, invalid; - BOOL ret; - - StrnCpy(valid, lp_valid_users(snum), sizeof(pstring)); - StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring)); - - string_sub(valid,"%S",lp_servicename(snum)); - string_sub(invalid,"%S",lp_servicename(snum)); - - ret = !user_in_list(user,invalid); - - if (ret && valid && *valid) - ret = user_in_list(user,valid); - - if (ret && lp_onlyuser(snum)) { - char *user_list = lp_username(snum); - string_sub(user_list,"%S",lp_servicename(snum)); - ret = user_in_list(user,user_list); - } - - return(ret); -} - - - - -/**************************************************************************** -validate a group username entry. Return the username or NULL -****************************************************************************/ -static char *validate_group(char *group,char *password,int pwlen,int snum) -{ -#ifdef NETGROUP - { - char *host, *user, *domain; - setnetgrent(group); - while (getnetgrent(&host, &user, &domain)) { - if (user) { - if (user_ok(user, snum) && - password_ok(user,password,pwlen,NULL)) { - endnetgrent(); - return(user); - } - } - } - endnetgrent(); - } -#endif - -#if HAVE_GETGRNAM - { - struct group *gptr = (struct group *)getgrnam(group); - char **member; - if (gptr) - { - member = gptr->gr_mem; - while (member && *member) - { - static fstring name; - strcpy(name,*member); - if (user_ok(name,snum) && - password_ok(name,password,pwlen,NULL)) - return(&name[0]); - member++; - } -#ifdef GROUP_CHECK_PWENT - { - struct passwd *pwd; - static fstring tm; - - setpwent (); - while (pwd = getpwent ()) { - if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) { - /* This Entry have PASSWORD and same GID then check pwd */ - if (password_ok(NULL, password, pwlen, pwd)) { - strcpy(tm, pwd->pw_name); - endpwent (); - return tm; - } - } - } - endpwent (); - } -#endif /* GROUP_CHECK_PWENT */ - } - } -#endif - return(NULL); -} - - - -/**************************************************************************** -check for authority to login to a service with a given username/password -****************************************************************************/ -BOOL authorise_login(int snum,char *user,char *password, int pwlen, - BOOL *guest,BOOL *force,uint16 vuid) -{ - BOOL ok = False; - - *guest = False; - -#if DEBUG_PASSWORD - DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password)); -#endif - - /* there are several possibilities: - 1) login as the given user with given password - 2) login as a previously registered username with the given password - 3) login as a session list username with the given password - 4) login as a previously validated user/password pair - 5) login as the "user =" user with given password - 6) login as the "user =" user with no password (guest connection) - 7) login as guest user with no password - - if the service is guest_only then steps 1 to 5 are skipped - */ - - if (GUEST_ONLY(snum)) *force = True; - - if (!(GUEST_ONLY(snum) && GUEST_OK(snum))) - { - - user_struct *vuser = get_valid_user_struct(vuid); - - /* check the given username and password */ - if (!ok && (*user) && user_ok(user,snum)) { - ok = password_ok(user,password, pwlen, NULL); - if (ok) DEBUG(3,("ACCEPTED: given username password ok\n")); - } - - /* check for a previously registered guest username */ - if (!ok && (vuser != 0) && vuser->guest) { - if (user_ok(vuser->name,snum) && - password_ok(vuser->name, password, pwlen, NULL)) { - strcpy(user, vuser->name); - vuser->guest = False; - DEBUG(3,("ACCEPTED: given password with registered user %s\n", user)); - ok = True; - } - } - - - /* now check the list of session users */ - if (!ok) - { - char *auser; - char *user_list = strdup(session_users); - if (!user_list) return(False); - - for (auser=strtok(user_list,LIST_SEP); - !ok && auser; - auser = strtok(NULL,LIST_SEP)) - { - fstring user2; - strcpy(user2,auser); - if (!user_ok(user2,snum)) continue; - - if (password_ok(user2,password, pwlen, NULL)) { - ok = True; - strcpy(user,user2); - DEBUG(3,("ACCEPTED: session list username and given password ok\n")); - } - } - free(user_list); - } - - /* check for a previously validated username/password pair */ - if (!ok && !lp_revalidate(snum) && - (vuser != 0) && !vuser->guest && - user_ok(vuser->name,snum)) { - strcpy(user,vuser->name); - *guest = False; - DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n")); - ok = True; - } - - /* check for a rhosts entry */ - if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) { - ok = True; - DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n")); - } - - /* check the user= fields and the given password */ - if (!ok && lp_username(snum)) { - char *auser; - pstring user_list; - StrnCpy(user_list,lp_username(snum),sizeof(pstring)); - - string_sub(user_list,"%S",lp_servicename(snum)); - - for (auser=strtok(user_list,LIST_SEP); - auser && !ok; - auser = strtok(NULL,LIST_SEP)) - { - if (*auser == '@') - { - auser = validate_group(auser+1,password,pwlen,snum); - if (auser) - { - ok = True; - strcpy(user,auser); - DEBUG(3,("ACCEPTED: group username and given password ok\n")); - } - } - else - { - fstring user2; - strcpy(user2,auser); - if (user_ok(user2,snum) && - password_ok(user2,password,pwlen,NULL)) - { - ok = True; - strcpy(user,user2); - DEBUG(3,("ACCEPTED: user list username and given password ok\n")); - } - } - } - } - } /* not guest only */ - - /* check for a normal guest connection */ - if (!ok && GUEST_OK(snum)) - { - fstring guestname; - StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1); - if (Get_Pwnam(guestname,True)) - { - strcpy(user,guestname); - ok = True; - DEBUG(3,("ACCEPTED: guest account and guest ok\n")); - } - else - DEBUG(0,("Invalid guest account %s??\n",guestname)); - *guest = True; - *force = True; - } - - if (ok && !user_ok(user,snum)) - { - DEBUG(0,("rejected invalid user %s\n",user)); - ok = False; - } - - return(ok); -} - - -/**************************************************************************** -read the a hosts.equiv or .rhosts file and check if it -allows this user from this machine -****************************************************************************/ -static BOOL check_user_equiv(char *user, char *remote, char *equiv_file) -{ - pstring buf; - int plus_allowed = 1; - char *file_host; - char *file_user; - FILE *fp = fopen(equiv_file, "r"); - DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file)); - if (! fp) return False; - while(fgets(buf, sizeof(buf), fp)) - { - trim_string(buf," "," "); - - if (buf[0] != '#' && buf[0] != '\n') - { - BOOL is_group = False; - int plus = 1; - char *bp = buf; - if (strcmp(buf, "NO_PLUS\n") == 0) - { - DEBUG(6, ("check_user_equiv NO_PLUS\n")); - plus_allowed = 0; - } - else { - if (buf[0] == '+') - { - bp++; - if (*bp == '\n' && plus_allowed) - { - /* a bare plus means everbody allowed */ - DEBUG(6, ("check_user_equiv everybody allowed\n")); - fclose(fp); - return True; - } - } - else if (buf[0] == '-') - { - bp++; - plus = 0; - } - if (*bp == '@') - { - is_group = True; - bp++; - } - file_host = strtok(bp, " \t\n"); - file_user = strtok(NULL, " \t\n"); - DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)", - file_user ? file_user : "(null)" )); - if (file_host && *file_host) - { - BOOL host_ok = False; - -#ifdef NETGROUP - if (is_group) - { - static char *mydomain = NULL; - if (!mydomain) - yp_get_default_domain(&mydomain); - if (mydomain && innetgr(file_host,remote,user,mydomain)) - host_ok = True; - } -#else - if (is_group) - { - DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n")); - continue; - } -#endif - - /* is it this host */ - /* the fact that remote has come from a call of gethostbyaddr - * means that it may have the fully qualified domain name - * so we could look up the file version to get it into - * a canonical form, but I would rather just type it - * in full in the equiv file - */ - if (!host_ok && !is_group && strequal(remote, file_host)) - host_ok = True; - - if (!host_ok) - continue; - - /* is it this user */ - if (file_user == 0 || strequal(user, file_user)) - { - fclose(fp); - DEBUG(5, ("check_user_equiv matched %s%s %s\n", - (plus ? "+" : "-"), file_host, - (file_user ? file_user : ""))); - return (plus ? True : False); - } - } - } - } - } - fclose(fp); - return False; -} - - -/**************************************************************************** -check for a possible hosts equiv or rhosts entry for the user -****************************************************************************/ -BOOL check_hosts_equiv(char *user) -{ - char *fname = NULL; - pstring rhostsfile; - struct passwd *pass = Get_Pwnam(user,True); - - if (!pass) - return(False); - - fname = lp_hosts_equiv(); - - /* note: don't allow hosts.equiv on root */ - if (fname && *fname && (pass->pw_uid != 0)) - { - if (check_user_equiv(user,client_name(),fname)) - return(True); - } - - if (lp_use_rhosts()) - { - char *home = get_home_dir(user); - if (home) - { - sprintf(rhostsfile, "%s/.rhosts", home); - if (check_user_equiv(user,client_name(),rhostsfile)) - return(True); - } - } - - return(False); -} - - -int password_client = -1; -static fstring pserver; -static char *secserver_inbuf = NULL; - -/**************************************************************************** -attempted support for server level security -****************************************************************************/ -BOOL server_cryptkey(char *buf) -{ - pstring outbuf; - fstring pass_protocol; - extern fstring remote_machine; - char *p; - int len; - fstring desthost; - struct in_addr dest_ip; - int port = SMB_PORT; - BOOL ret; - - if(secserver_inbuf == NULL) { - secserver_inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); - if(secserver_inbuf == NULL) { - DEBUG(0,("server_cryptkey: malloc fail for input buffer.\n")); - return False; - } - } - - if (password_client >= 0) - close(password_client); - password_client = -1; - - if (Protocol < PROTOCOL_NT1) { - strcpy(pass_protocol,"LM1.2X002"); - } else { - strcpy(pass_protocol,"NT LM 0.12"); - } - - bzero(secserver_inbuf,BUFFER_SIZE + SAFETY_MARGIN); - bzero(outbuf,sizeof(outbuf)); - - for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) { - strcpy(desthost,p); - standard_sub_basic(desthost); - strupper(desthost); - - dest_ip = *interpret_addr2(desthost); - if (zero_ip(dest_ip)) { - DEBUG(1,("Can't resolve address for %s\n",p)); - continue; - } - - if (ismyip(dest_ip)) { - DEBUG(1,("Password server loop - disabling password server %s\n",p)); - continue; - } - - password_client = open_socket_out(SOCK_STREAM, &dest_ip, port, SHORT_CONNECT_TIMEOUT); - if (password_client >= 0) { - DEBUG(3,("connected to password server %s\n",p)); - StrnCpy(pserver,p,sizeof(pserver)-1); - break; - } - } - - if (password_client < 0) { - DEBUG(1,("password server not available\n")); - return(False); - } - - - /* send a session request (RFC 8002) */ - - /* put in the destination name */ - len = 4; - p = outbuf+len; - name_mangle(desthost,p,' '); - len += name_len(p); - p = outbuf+len; - - /* and my name */ - /* Fix from Frank Varnavas <varnavas@ny.ubs.com>. - We cannot use the same name as the client to - the NT password server, as NT will drop client - connections if the same client name connects - twice. Instead, synthesize a name from our pid. - and the remote machine name. - */ - { - char buf2[32]; /* create name as PIDname */ - sprintf(buf2,"%d", getpid()); - strncpy(&buf2[strlen(buf2)], remote_machine, 31 - strlen(buf2)); - buf2[31] = '\0'; - DEBUG(1,("negprot w/password server as %s\n",buf2)); - name_mangle(buf2,p,' '); - len += name_len(p); - } - - _smb_setlen(outbuf,len); - CVAL(outbuf,0) = 0x81; - - send_smb(password_client,outbuf); - - - if (!receive_smb(password_client,secserver_inbuf,5000) || - CVAL(secserver_inbuf,0) != 0x82) { - DEBUG(1,("%s rejected the session\n",pserver)); - close(password_client); password_client = -1; - return(False); - } - - DEBUG(3,("got session\n")); - - bzero(outbuf,smb_size); - - /* setup the protocol string */ - set_message(outbuf,0,strlen(pass_protocol)+2,True); - p = smb_buf(outbuf); - *p++ = 2; - strcpy(p,pass_protocol); - - CVAL(outbuf,smb_com) = SMBnegprot; - CVAL(outbuf,smb_flg) = 0x8; - SSVAL(outbuf,smb_flg2,0x1); - - send_smb(password_client,outbuf); - ret = receive_smb(password_client,secserver_inbuf,5000); - - if (!ret || CVAL(secserver_inbuf,smb_rcls) || SVAL(secserver_inbuf,smb_vwv0)) { - DEBUG(1,("%s rejected the protocol\n",pserver)); - close(password_client); password_client= -1; - return(False); - } - - if (!(CVAL(secserver_inbuf,smb_vwv1) & 1)) { - DEBUG(1,("%s isn't in user level security mode\n",pserver)); - close(password_client); password_client= -1; - return(False); - } - - memcpy(buf,secserver_inbuf,smb_len(secserver_inbuf)+4); - - DEBUG(3,("password server OK\n")); - - return(True); -} - -/**************************************************************************** -attempted support for server level security -****************************************************************************/ -BOOL server_validate(char *buf) -{ - pstring outbuf; - BOOL ret; - - if(secserver_inbuf == NULL) { - secserver_inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); - if(secserver_inbuf == NULL) { - DEBUG(0,("server_validate: malloc fail for input buffer.\n")); - return False; - } - } - - if (password_client < 0) { - DEBUG(1,("%s not connected\n",pserver)); - return(False); - } - - bzero(secserver_inbuf,BUFFER_SIZE + SAFETY_MARGIN); - memcpy(outbuf,buf,sizeof(outbuf)); - - /* send a session setup command */ - CVAL(outbuf,smb_flg) = 0x8; - SSVAL(outbuf,smb_flg2,0x1); - CVAL(outbuf,smb_vwv0) = 0xFF; - - set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False); - - SCVAL(secserver_inbuf,smb_rcls,1); - - send_smb(password_client,outbuf); - ret = receive_smb(password_client,secserver_inbuf,5000); - - if (!ret || CVAL(secserver_inbuf,smb_rcls) != 0) { - DEBUG(1,("password server %s rejected the password\n",pserver)); - return(False); - } - - /* if logged in as guest then reject */ - if ((SVAL(secserver_inbuf,smb_vwv2) & 1) != 0) { - DEBUG(1,("password server %s gave us guest only\n",pserver)); - return(False); - } - - DEBUG(3,("password server %s accepted the password\n",pserver)); - -#if !KEEP_PASSWORD_SERVER_OPEN - close(password_client); password_client= -1; -#endif - - return(True); -} - - diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c deleted file mode 100644 index 6937412e29f..00000000000 --- a/source/smbd/pipes.c +++ /dev/null @@ -1,1196 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - Pipe SMB reply routines - Copyright (C) Andrew Tridgell 1992-1997, - Copyright (C) Luke Kenneth Casson Leighton 1996-1997. - Copyright (C) Paul Ashton 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* - This file handles reply_ calls on named pipes that the server - makes to handle specific protocols -*/ - - -#include "includes.h" -#include "trans2.h" -#include "nterr.h" - -#define PIPE "\\PIPE\\" -#define PIPELEN strlen(PIPE) - -#define REALLOC(ptr,size) Realloc(ptr,MAX((size),4*1024)) - -/* look in server.c for some explanation of these variables */ -extern int Protocol; -extern int DEBUGLEVEL; -extern int chain_fnum; -extern char magic_char; -extern connection_struct Connections[]; -extern files_struct Files[]; -extern BOOL case_sensitive; -extern pstring sesssetup_user; -extern int Client; -extern fstring myworkgroup; - -/* this macro should always be used to extract an fnum (smb_fid) from -a packet to ensure chaining works correctly */ -#define GETFNUM(buf,where) (chain_fnum!= -1?chain_fnum:SVAL(buf,where)) - -char * known_pipes [] = -{ - "lsarpc", -#if NTDOMAIN - "NETLOGON", -#endif - NULL -}; - -/**************************************************************************** - reply to an open and X on a named pipe - - In fact what we do is to open a regular file with the same name in - /tmp. This can then be closed as normal. Reading and writing won't - make much sense, but will do *something*. The real reason for this - support is to be able to do transactions on them (well, on lsarpc - for domain login purposes...). - - This code is basically stolen from reply_open_and_X with some - wrinkles to handle pipes. -****************************************************************************/ -int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize) -{ - pstring fname; - int cnum = SVAL(inbuf,smb_tid); - int fnum = -1; - int smb_mode = SVAL(inbuf,smb_vwv3); - int smb_attr = SVAL(inbuf,smb_vwv5); -#if 0 - int open_flags = SVAL(inbuf,smb_vwv2); - int smb_sattr = SVAL(inbuf,smb_vwv4); - uint32 smb_time = make_unix_date3(inbuf+smb_vwv6); -#endif - int smb_ofun = SVAL(inbuf,smb_vwv8); - int unixmode; - int size=0,fmode=0,mtime=0,rmode=0; - struct stat sbuf; - int smb_action = 0; - int i; - BOOL bad_path = False; - - /* XXXX we need to handle passed times, sattr and flags */ - pstrcpy(fname,smb_buf(inbuf)); - - /* If the name doesn't start \PIPE\ then this is directed */ - /* at a mailslot or something we really, really don't understand, */ - /* not just something we really don't understand. */ - if ( strncmp(fname,PIPE,PIPELEN) != 0 ) - return(ERROR(ERRSRV,ERRaccess)); - - DEBUG(4,("Opening pipe %s.\n", fname)); - - /* Strip \PIPE\ off the name. */ - pstrcpy(fname,smb_buf(inbuf) + PIPELEN); - - /* See if it is one we want to handle. */ - for( i = 0; known_pipes[i] ; i++ ) - if( strcmp(fname,known_pipes[i]) == 0 ) - break; - - if ( known_pipes[i] == NULL ) - return(ERROR(ERRSRV,ERRaccess)); - - /* Known pipes arrive with DIR attribs. Remove it so a regular file */ - /* can be opened and add it in after the open. */ - DEBUG(3,("Known pipe %s opening.\n",fname)); - smb_attr &= ~aDIR; - Connections[cnum].read_only = 0; - smb_ofun |= 0x10; /* Add Create it not exists flag */ - - unix_convert(fname,cnum,0,&bad_path); - - fnum = find_free_file(); - if (fnum < 0) - return(ERROR(ERRSRV,ERRnofids)); - - if (!check_name(fname,cnum)) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - unixmode = unix_mode(cnum,smb_attr); - - open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode, - 0, &rmode,&smb_action); - - if (!Files[fnum].open) - { - /* Change the error code if bad_path was set. */ - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) { - close_file(fnum); - return(ERROR(ERRDOS,ERRnoaccess)); - } - - size = sbuf.st_size; - fmode = dos_mode(cnum,fname,&sbuf); - mtime = sbuf.st_mtime; - if (fmode & aDIR) { - close_file(fnum); - return(ERROR(ERRDOS,ERRnoaccess)); - } - - /* Prepare the reply */ - set_message(outbuf,15,0,True); - - /* Put things back the way they were. */ - Connections[cnum].read_only = 1; - - /* Mark the opened file as an existing named pipe in message mode. */ - SSVAL(outbuf,smb_vwv9,2); - SSVAL(outbuf,smb_vwv10,0xc700); - if (rmode == 2) - { - DEBUG(4,("Resetting open result to open from create.\n")); - rmode = 1; - } - - SSVAL(outbuf,smb_vwv2,fnum); - SSVAL(outbuf,smb_vwv3,fmode); - put_dos_date3(outbuf,smb_vwv4,mtime); - SIVAL(outbuf,smb_vwv6,size); - SSVAL(outbuf,smb_vwv8,rmode); - SSVAL(outbuf,smb_vwv11,smb_action); - - chain_fnum = fnum; - - DEBUG(4,("Opened pipe %s with handle %d, saved name %s.\n", - fname, fnum, Files[fnum].name)); - - return chain_reply(inbuf,outbuf,length,bufsize); -} - - -/**************************************************************************** - api_LsarpcSNPHS - - SetNamedPipeHandleState on \PIPE\lsarpc. We can't really do much here, - so just blithely return True. This is really only for NT domain stuff, - we we're only handling that - don't assume Samba now does complete - named pipe handling. -****************************************************************************/ -BOOL api_LsarpcSNPHS(int cnum,int uid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - uint16 id; - - id = param[0] + (param[1] << 8); - DEBUG(4,("lsarpc SetNamedPipeHandleState to code %x\n",id)); - return(True); -} - - -/**************************************************************************** - api_LsarpcTNP - - TransactNamedPipe on \PIPE\lsarpc. -****************************************************************************/ -static void LsarpcTNP1(char *data,char **rdata, int *rdata_len) -{ - uint32 dword1, dword2; - char pname[] = "\\PIPE\\lsass"; - - /* All kinds of mysterious numbers here */ - *rdata_len = 68; - *rdata = REALLOC(*rdata,*rdata_len); - - dword1 = IVAL(data,0xC); - dword2 = IVAL(data,0x10); - - SIVAL(*rdata,0,0xc0005); - SIVAL(*rdata,4,0x10); - SIVAL(*rdata,8,0x44); - SIVAL(*rdata,0xC,dword1); - - SIVAL(*rdata,0x10,dword2); - SIVAL(*rdata,0x14,0x15); - SSVAL(*rdata,0x18,sizeof(pname)); - strcpy(*rdata + 0x1a,pname); - SIVAL(*rdata,0x28,1); - memcpy(*rdata + 0x30, data + 0x34, 0x14); -} - -static void LsarpcTNP2(char *data,char **rdata, int *rdata_len) -{ - uint32 dword1; - - /* All kinds of mysterious numbers here */ - *rdata_len = 48; - *rdata = REALLOC(*rdata,*rdata_len); - - dword1 = IVAL(data,0xC); - - SIVAL(*rdata,0,0x03020005); - SIVAL(*rdata,4,0x10); - SIVAL(*rdata,8,0x30); - SIVAL(*rdata,0xC,dword1); - SIVAL(*rdata,0x10,0x18); - SIVAL(*rdata,0x1c,0x44332211); - SIVAL(*rdata,0x20,0x88776655); - SIVAL(*rdata,0x24,0xCCBBAA99); - SIVAL(*rdata,0x28,0x11FFEEDD); -} - -static void LsarpcTNP3(char *data,char **rdata, int *rdata_len) -{ - uint32 dword1; - uint16 word1; - char * workgroup = myworkgroup; - int wglen = strlen(workgroup); - int i; - - /* All kinds of mysterious numbers here */ - *rdata_len = 90 + 2 * wglen; - *rdata = REALLOC(*rdata,*rdata_len); - - dword1 = IVAL(data,0xC); - word1 = SVAL(data,0x2C); - - SIVAL(*rdata,0,0x03020005); - SIVAL(*rdata,4,0x10); - SIVAL(*rdata,8,0x60); - SIVAL(*rdata,0xC,dword1); - SIVAL(*rdata,0x10,0x48); - SSVAL(*rdata,0x18,0x5988); /* This changes */ - SSVAL(*rdata,0x1A,0x15); - SSVAL(*rdata,0x1C,word1); - SSVAL(*rdata,0x20,6); - SSVAL(*rdata,0x22,8); - SSVAL(*rdata,0x24,0x8E8); /* So does this */ - SSVAL(*rdata,0x26,0x15); - SSVAL(*rdata,0x28,0x4D48); /* And this */ - SSVAL(*rdata,0x2A,0x15); - SIVAL(*rdata,0x2C,4); - SIVAL(*rdata,0x34,wglen); - for ( i = 0 ; i < wglen ; i++ ) - (*rdata)[0x38 + i * 2] = workgroup[i]; - - /* Now fill in the rest */ - i = 0x38 + wglen * 2; - SSVAL(*rdata,i,0x648); - SIVAL(*rdata,i+2,4); - SIVAL(*rdata,i+6,0x401); - SSVAL(*rdata,i+0xC,0x500); - SIVAL(*rdata,i+0xE,0x15); - SIVAL(*rdata,i+0x12,0x2372FE1); - SIVAL(*rdata,i+0x16,0x7E831BEF); - SIVAL(*rdata,i+0x1A,0x4B454B2); -} - -static void LsarpcTNP4(char *data,char **rdata, int *rdata_len) -{ - uint32 dword1; - - /* All kinds of mysterious numbers here */ - *rdata_len = 48; - *rdata = REALLOC(*rdata,*rdata_len); - - dword1 = IVAL(data,0xC); - - SIVAL(*rdata,0,0x03020005); - SIVAL(*rdata,4,0x10); - SIVAL(*rdata,8,0x30); - SIVAL(*rdata,0xC,dword1); - SIVAL(*rdata,0x10,0x18); -} - - -BOOL api_LsarpcTNP(int cnum,int uid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - uint32 id,id2; - - id = IVAL(data,0); - - DEBUG(4,("lsarpc TransactNamedPipe id %lx\n",id)); - switch (id) - { - case 0xb0005: - LsarpcTNP1(data,rdata,rdata_len); - break; - - case 0x03000005: - id2 = IVAL(data,8); - DEBUG(4,("\t- Suboperation %lx\n",id2)); - switch (id2 & 0xF) - { - case 8: - LsarpcTNP2(data,rdata,rdata_len); - break; - - case 0xC: - LsarpcTNP4(data,rdata,rdata_len); - break; - - case 0xE: - LsarpcTNP3(data,rdata,rdata_len); - break; - } - break; - } - return(True); -} - - -#ifdef NTDOMAIN -/* - PAXX: Someone fix above. - The above API is indexing RPC calls based on RPC flags and - fragment length. I've decided to do it based on operation number :-) -*/ - -/* this function is due to be replaced */ -static void initrpcreply(char *inbuf, char *q) -{ - uint32 callid; - - SCVAL(q, 0, 5); q++; /* RPC version 5 */ - SCVAL(q, 0, 0); q++; /* minor version 0 */ - SCVAL(q, 0, 2); q++; /* RPC response packet */ - SCVAL(q, 0, 3); q++; /* first frag + last frag */ - RSIVAL(q, 0, 0x10000000); q += 4; /* packed data representation */ - RSSVAL(q, 0, 0); q += 2; /* fragment length, fill in later */ - SSVAL(q, 0, 0); q += 2; /* authentication length */ - callid = RIVAL(inbuf, 12); - RSIVAL(q, 0, callid); q += 4; /* call identifier - match incoming RPC */ - SIVAL(q, 0, 0x18); q += 4; /* allocation hint (no idea) */ - SSVAL(q, 0, 0); q += 2; /* presentation context identifier */ - SCVAL(q, 0, 0); q++; /* cancel count */ - SCVAL(q, 0, 0); q++; /* reserved */ -} - -/* this function is due to be replaced */ -static void endrpcreply(char *inbuf, char *q, int datalen, int rtnval, int *rlen) -{ - SSVAL(q, 8, datalen + 4); - SIVAL(q,0x10,datalen+4-0x18); /* allocation hint */ - SIVAL(q, datalen, rtnval); - *rlen = datalen + 4; - { int fd; fd = open("/tmp/rpc", O_RDWR); write(fd, q, datalen + 4); } -} - -/* RID username mapping function. just for fun, it maps to the unix uid */ -static uint32 name_to_rid(char *user_name) -{ - struct passwd *pw = Get_Pwnam(user_name, False); - if (!pw) - { - DEBUG(1,("Username %s is invalid on this system\n", user_name)); - return (uint32)(-1); - } - - return (uint32)(pw->pw_uid); -} - - -/* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */ -char *dom_sid_to_string(DOM_SID *sid) -{ - static pstring sidstr; - char subauth[16]; - int i; - uint32 ia = (sid->id_auth[0]) + - (sid->id_auth[1] << 8 ) + - (sid->id_auth[2] << 16) + - (sid->id_auth[3] << 24); - - sprintf(sidstr, "S-%d-%d", sid->sid_no, ia); - - for (i = 0; i < sid->num_auths; i++) - { - sprintf(subauth, "-%d", sid->sub_auths[i]); - strcat(sidstr, subauth); - } - - DEBUG(5,("dom_sid_to_string returning %s\n", sidstr)); - return sidstr; -} - -/* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */ -/* identauth >= 2^32 can be detected because it will be specified in hex */ -static void make_dom_sid(DOM_SID *sid, char *domsid) -{ - int identauth; - char *p; - - DEBUG(4,("netlogon domain SID: %s\n", domsid)); - - /* assume, but should check, that domsid starts "S-" */ - p = strtok(domsid+2,"-"); - sid->sid_no = atoi(p); - - /* identauth in decimal should be < 2^32 */ - /* identauth in hex should be >= 2^32 */ - identauth = atoi(strtok(0,"-")); - - DEBUG(4,("netlogon rev %d\n", sid->sid_no)); - DEBUG(4,("netlogon %s ia %d\n", p, identauth)); - - sid->id_auth[0] = 0; - sid->id_auth[1] = 0; - sid->id_auth[2] = (identauth & 0xff000000) >> 24; - sid->id_auth[3] = (identauth & 0x00ff0000) >> 16; - sid->id_auth[4] = (identauth & 0x0000ff00) >> 8; - sid->id_auth[5] = (identauth & 0x000000ff); - - sid->num_auths = 0; - - while ((p = strtok(0, "-")) != NULL) - { - sid->sub_auths[sid->num_auths++] = atoi(p); - } -} - -static void create_rpc_reply(RPC_HDR *hdr, uint32 call_id, int data_len) -{ - if (hdr == NULL) return; - - hdr->major = 5; /* RPC version 5 */ - hdr->minor = 0; /* minor version 0 */ - hdr->pkt_type = 2; /* RPC response packet */ - hdr->frag = 3; /* first frag + last frag */ - hdr->pack_type = 1; /* packed data representation */ - hdr->frag_len = data_len; /* fragment length, fill in later */ - hdr->auth_len = 0; /* authentication length */ - hdr->call_id = call_id; /* call identifier - match incoming RPC */ - hdr->alloc_hint = data_len - 0x18; /* allocation hint (no idea) */ - hdr->context_id = 0; /* presentation context identifier */ - hdr->cancel_count = 0; /* cancel count */ - hdr->reserved = 0; /* reserved */ -} - -static void make_rpc_reply(char *inbuf, char *q, int data_len) -{ - uint32 callid = RIVAL(inbuf, 12); - RPC_HDR hdr; - - create_rpc_reply(&hdr, callid, data_len); - smb_io_rpc_hdr(False, &hdr, q, q, 4); -} - -static int lsa_reply_open_policy(char *q, char *base) -{ - char *start = q; - LSA_R_OPEN_POL r_o; - - /* set up the LSA QUERY INFO response */ - bzero(&(r_o.pol.data), POL_HND_SIZE); - r_o.status = 0x0; - - /* store the response in the SMB stream */ - q = lsa_io_r_open_pol(False, &r_o, q, base, 4); - - /* return length of SMB data stored */ - return q - start; -} - -static void make_uni_hdr(UNIHDR *hdr, int max_len, int len, uint16 terminate) -{ - hdr->uni_max_len = max_len; - hdr->uni_str_len = len; - hdr->undoc = terminate; -} - -static void make_uni_hdr2(UNIHDR2 *hdr, int max_len, int len, uint16 terminate) -{ - make_uni_hdr(&(hdr->unihdr), max_len, len, terminate); - hdr->undoc_buffer = len > 0 ? 1 : 0; -} - -static void make_unistr(UNISTR *str, char *buf) -{ - /* store the string (null-terminated copy) */ - PutUniCode((char *)(str->buffer), buf); -} - -static void make_unistr2(UNISTR2 *str, char *buf, int len, char terminate) -{ - /* set up string lengths. add one if string is not null-terminated */ - str->uni_max_len = len + (terminate != 0 ? 1 : 0); - str->undoc = 0; - str->uni_str_len = len; - - /* store the string (null-terminated copy) */ - PutUniCode((char *)str->buffer, buf); - - /* overwrite the last character: some strings are terminated with 4 not 0 */ - str->buffer[len] = (uint16)terminate; -} - -static void make_dom_rid2(DOM_RID2 *rid2, uint32 rid) -{ - rid2->type = 0x5; - rid2->undoc = 0x5; - rid2->rid = rid; - rid2->rid_idx = 0; -} - -static void make_dom_sid2(DOM_SID2 *sid2, char *sid_str) -{ - int len_sid_str = strlen(sid_str); - - sid2->type = 0x5; - sid2->undoc = 0; - make_uni_hdr2(&(sid2->hdr), len_sid_str, len_sid_str, 0); - make_unistr (&(sid2->str), sid_str); -} - -static void make_dom_query(DOM_QUERY *d_q, char *dom_name, char *dom_sid) -{ - int domlen = strlen(dom_name); - - d_q->uni_dom_max_len = domlen * 2; - d_q->padding = 0; - d_q->uni_dom_str_len = domlen * 2; - - d_q->buffer_dom_name = 0; /* domain buffer pointer */ - d_q->buffer_dom_sid = 0; /* domain sid pointer */ - - /* NOT null-terminated: 4-terminated instead! */ - make_unistr2(&(d_q->uni_domain_name), dom_name, domlen, 4); - - make_dom_sid(&(d_q->dom_sid), dom_sid); -} - -static int lsa_reply_query_info(LSA_Q_QUERY_INFO *q_q, char *q, char *base, - char *dom_name, char *dom_sid) -{ - char *start = q; - LSA_R_QUERY_INFO r_q; - - /* set up the LSA QUERY INFO response */ - - r_q.undoc_buffer = 1; /* not null */ - r_q.info_class = q_q->info_class; - - make_dom_query(&r_q.dom.id5, dom_name, dom_sid); - - r_q.status = 0x0; - - /* store the response in the SMB stream */ - q = lsa_io_r_query(False, &r_q, q, base, 4); - - /* return length of SMB data stored */ - return q - start; -} - -/* pretty much hard-coded choice of "other" sids, unfortunately... */ -static void make_dom_ref(DOM_R_REF *ref, - char *dom_name, char *dom_sid, - char *other_sid1, char *other_sid2, char *other_sid3) -{ - int len_dom_name = strlen(dom_name); - int len_other_sid1 = strlen(other_sid1); - int len_other_sid2 = strlen(other_sid2); - int len_other_sid3 = strlen(other_sid3); - - ref->undoc_buffer = 1; - ref->num_ref_doms_1 = 4; - ref->buffer_dom_name = 1; - ref->max_entries = 32; - ref->num_ref_doms_2 = 4; - - make_uni_hdr2(&(ref->hdr_dom_name ), len_dom_name , len_dom_name , 0); - make_uni_hdr2(&(ref->hdr_ref_dom[0]), len_other_sid1, len_other_sid1, 0); - make_uni_hdr2(&(ref->hdr_ref_dom[1]), len_other_sid2, len_other_sid2, 0); - make_uni_hdr2(&(ref->hdr_ref_dom[2]), len_other_sid3, len_other_sid3, 0); - - if (dom_name != NULL) - { - make_unistr(&(ref->uni_dom_name), dom_name); - } - - make_dom_sid(&(ref->ref_dom[0]), dom_sid ); - make_dom_sid(&(ref->ref_dom[1]), other_sid1); - make_dom_sid(&(ref->ref_dom[2]), other_sid2); - make_dom_sid(&(ref->ref_dom[3]), other_sid3); -} - -static void make_reply_lookup_rids(LSA_R_LOOKUP_RIDS *r_l, - int num_entries, uint32 dom_rids[MAX_LOOKUP_SIDS], - char *dom_name, char *dom_sid, - char *other_sid1, char *other_sid2, char *other_sid3) -{ - int i; - - make_dom_ref(&(r_l->dom_ref), dom_name, dom_sid, - other_sid1, other_sid2, other_sid3); - - r_l->num_entries = num_entries; - r_l->undoc_buffer = 1; - r_l->num_entries2 = num_entries; - - for (i = 0; i < num_entries; i++) - { - make_dom_rid2(&(r_l->dom_rid[i]), dom_rids[i]); - } - - r_l->num_entries3 = num_entries; -} - -static void make_reply_lookup_sids(LSA_R_LOOKUP_SIDS *r_l, - int num_entries, fstring dom_sids[MAX_LOOKUP_SIDS], - char *dom_name, char *dom_sid, - char *other_sid1, char *other_sid2, char *other_sid3) -{ - int i; - - make_dom_ref(&(r_l->dom_ref), dom_name, dom_sid, - other_sid1, other_sid2, other_sid3); - - r_l->num_entries = num_entries; - r_l->undoc_buffer = 1; - r_l->num_entries2 = num_entries; - - for (i = 0; i < num_entries; i++) - { - make_dom_sid2(&(r_l->dom_sid[i]), dom_sids[i]); - } - - r_l->num_entries3 = num_entries; -} - -static int lsa_reply_lookup_sids(char *q, char *base, - int num_entries, fstring dom_sids[MAX_LOOKUP_SIDS], - char *dom_name, char *dom_sid, - char *other_sid1, char *other_sid2, char *other_sid3) -{ - char *start = q; - LSA_R_LOOKUP_SIDS r_l; - - /* set up the LSA Lookup SIDs response */ - make_reply_lookup_sids(&r_l, num_entries, dom_sids, - dom_name, dom_sid, other_sid1, other_sid2, other_sid3); - r_l.status = 0x0; - - /* store the response in the SMB stream */ - q = lsa_io_r_lookup_sids(False, &r_l, q, base, 4); - - /* return length of SMB data stored */ - return q - start; -} - -static int lsa_reply_lookup_rids(char *q, char *base, - int num_entries, uint32 dom_rids[MAX_LOOKUP_SIDS], - char *dom_name, char *dom_sid, - char *other_sid1, char *other_sid2, char *other_sid3) -{ - char *start = q; - LSA_R_LOOKUP_RIDS r_l; - - /* set up the LSA Lookup RIDs response */ - make_reply_lookup_rids(&r_l, num_entries, dom_rids, - dom_name, dom_sid, other_sid1, other_sid2, other_sid3); - r_l.status = 0x0; - - /* store the response in the SMB stream */ - q = lsa_io_r_lookup_rids(False, &r_l, q, base, 4); - - /* return length of SMB data stored */ - return q - start; -} - -static void make_lsa_r_req_chal(LSA_R_REQ_CHAL *r_c, char chal[8], int status) -{ - memcpy(r_c->srv_chal.data, chal, sizeof(r_c->srv_chal.data)); - r_c->status = status; -} - -#if 0 - char chal[8]; - /* PAXX: set these to random values */ - for (int i = 0; i < 8; i+++) - { - chal[i] = 0xA5; - } -#endif - -static int lsa_reply_req_chal(LSA_Q_REQ_CHAL *q_c, char *q, char *base, - char chal[8]) -{ - char *start = q; - LSA_R_REQ_CHAL r_c; - - /* set up the LSA REQUEST CHALLENGE response */ - - make_lsa_r_req_chal(&r_c, chal, 0); - - /* store the response in the SMB stream */ - q = lsa_io_r_req_chal(False, &r_c, q, base, 4); - - /* return length of SMB data stored */ - return q - start; -} - -static void make_lsa_chal(DOM_CHAL *cred, char resp_cred[8]) -{ - memcpy(cred->data, resp_cred, sizeof(cred->data)); -} - -static void make_lsa_r_auth_2(LSA_R_AUTH_2 *r_a, - char resp_cred[8], NEG_FLAGS *flgs, int status) -{ - make_lsa_chal(&(r_a->srv_chal), resp_cred); - memcpy(&(r_a->srv_flgs), flgs, sizeof(r_a->srv_flgs)); - r_a->status = status; -} - -static int lsa_reply_auth_2(LSA_Q_AUTH_2 *q_a, char *q, char *base, - char resp_cred[8], int status) -{ - char *start = q; - LSA_R_AUTH_2 r_a; - - /* set up the LSA AUTH 2 response */ - - make_lsa_r_auth_2(&r_a, resp_cred, &(q_a->clnt_flgs), status); - - /* store the response in the SMB stream */ - q = lsa_io_r_auth_2(False, &r_a, q, base, 4); - - /* return length of SMB data stored */ - return q - start; -} - -static void make_lsa_dom_chal(DOM_CRED *cred, char srv_chal[8], UTIME srv_time) -{ - make_lsa_chal(&(cred->challenge), srv_chal); - cred->timestamp = srv_time; -} - - -static void make_lsa_r_srv_pwset(LSA_R_SRV_PWSET *r_a, - char srv_chal[8], UTIME srv_time, int status) -{ - make_lsa_dom_chal(&(r_a->srv_cred), srv_chal, srv_time); - r_a->status = status; -} - -static int lsa_reply_srv_pwset(LSA_Q_SRV_PWSET *q_s, char *q, char *base, - char srv_cred[8], UTIME srv_time, - int status) -{ - char *start = q; - LSA_R_SRV_PWSET r_s; - - /* set up the LSA Server Password Set response */ - make_lsa_r_srv_pwset(&r_s, srv_cred, srv_time, status); - - /* store the response in the SMB stream */ - q = lsa_io_r_srv_pwset(False, &r_s, q, base, 4); - - /* return length of SMB data stored */ - return q - start; -} - -static void make_lsa_user_info(LSA_USER_INFO *usr, - - NTTIME *logon_time, - NTTIME *logoff_time, - NTTIME *kickoff_time, - NTTIME *pass_last_set_time, - NTTIME *pass_can_change_time, - NTTIME *pass_must_change_time, - - char *user_name, - char *full_name, - char *logon_script, - char *profile_path, - char *home_dir, - char *dir_drive, - - uint16 logon_count, - uint16 bad_pw_count, - - uint32 user_id, - uint32 group_id, - uint32 num_groups, - DOM_GID *gids, - uint32 user_flgs, - - char sess_key[16], - - char *logon_srv, - char *logon_dom, - - char *dom_sid, - char *other_sids) /* space-delimited set of SIDs */ -{ - /* only cope with one "other" sid, right now. */ - /* need to count the number of space-delimited sids */ - int i; - int num_other_sids = other_sids != NULL ? 1 : 0; - - int len_user_name = strlen(user_name ); - int len_full_name = strlen(full_name ); - int len_logon_script = strlen(logon_script); - int len_profile_path = strlen(profile_path); - int len_home_dir = strlen(home_dir ); - int len_dir_drive = strlen(dir_drive ); - - int len_logon_srv = strlen(logon_srv); - int len_logon_dom = strlen(logon_dom); - - usr->undoc_buffer = 1; /* yes, we're bothering to put USER_INFO data here */ - - usr->logon_time = *logon_time; - usr->logoff_time = *logoff_time; - usr->kickoff_time = *kickoff_time; - usr->pass_last_set_time = *pass_last_set_time; - usr->pass_can_change_time = *pass_can_change_time; - usr->pass_must_change_time = *pass_must_change_time; - - make_uni_hdr(&(usr->hdr_user_name ), len_user_name , len_user_name , 4); - make_uni_hdr(&(usr->hdr_full_name ), len_full_name , len_full_name , 4); - make_uni_hdr(&(usr->hdr_logon_script), len_logon_script, len_logon_script, 4); - make_uni_hdr(&(usr->hdr_profile_path), len_profile_path, len_profile_path, 4); - make_uni_hdr(&(usr->hdr_home_dir ), len_home_dir , len_home_dir , 4); - make_uni_hdr(&(usr->hdr_dir_drive ), len_dir_drive , len_dir_drive , 4); - - usr->logon_count = logon_count; - usr->bad_pw_count = bad_pw_count; - - usr->user_id = user_id; - usr->group_id = group_id; - usr->num_groups = num_groups; - usr->buffer_groups = num_groups ? 1 : 0; /* yes, we're bothering to put group info in */ - usr->user_flgs = user_flgs; - - if (sess_key != NULL) - { - memcpy(usr->sess_key, sess_key, sizeof(usr->sess_key)); - } - else - { - bzero(usr->sess_key, sizeof(usr->sess_key)); - } - - make_uni_hdr(&(usr->hdr_logon_srv), len_logon_srv, len_logon_srv, 4); - make_uni_hdr(&(usr->hdr_logon_dom), len_logon_dom, len_logon_dom, 4); - - usr->buffer_dom_id = dom_sid ? 1 : 0; /* yes, we're bothering to put a domain SID in */ - - bzero(usr->padding, sizeof(usr->padding)); - - usr->num_other_sids = num_other_sids; - usr->buffer_other_sids = num_other_sids != 0 ? 1 : 0; - - make_unistr2(&(usr->uni_user_name ), user_name , len_user_name , 0); - make_unistr2(&(usr->uni_full_name ), full_name , len_full_name , 0); - make_unistr2(&(usr->uni_logon_script), logon_script, len_logon_script, 0); - make_unistr2(&(usr->uni_profile_path), profile_path, len_profile_path, 0); - make_unistr2(&(usr->uni_home_dir ), home_dir , len_home_dir , 0); - make_unistr2(&(usr->uni_dir_drive ), dir_drive , len_dir_drive , 0); - - usr->num_groups2 = num_groups; - for (i = 0; i < num_groups; i++) - { - usr->gids[i] = gids[i]; - } - - make_unistr2(&(usr->uni_logon_srv), logon_srv, len_logon_srv, 0); - make_unistr2(&(usr->uni_logon_dom), logon_dom, len_logon_dom, 0); - - make_dom_sid(&(usr->dom_sid), dom_sid); - make_dom_sid(&(usr->other_sids[0]), other_sids); -} - - -static int lsa_reply_sam_logon(LSA_Q_SAM_LOGON *q_s, char *q, char *base, - char srv_cred[8], UTIME srv_time, - LSA_USER_INFO *user_info) -{ - char *start = q; - LSA_R_SAM_LOGON r_s; - - /* XXXX maybe we want to say 'no', reject the client's credentials */ - r_s.buffer_creds = 1; /* yes, we have valid server credentials */ - make_lsa_dom_chal(&(r_s.srv_creds), srv_cred, srv_time); - - /* store the user information, if there is any. */ - r_s.user = user_info; - r_s.buffer_user = user_info != NULL ? 1 : 0; - r_s.status = user_info != NULL ? 0 : (0xC000000|NT_STATUS_NO_SUCH_USER); - - /* store the response in the SMB stream */ - q = lsa_io_r_sam_logon(False, &r_s, q, base, 4); - - /* return length of SMB data stored */ - return q - start; -} - - -static int lsa_reply_sam_logoff(LSA_Q_SAM_LOGOFF *q_s, char *q, char *base, - char srv_cred[8], UTIME srv_time, - uint32 status) -{ - char *start = q; - LSA_R_SAM_LOGOFF r_s; - - /* XXXX maybe we want to say 'no', reject the client's credentials */ - r_s.buffer_creds = 1; /* yes, we have valid server credentials */ - make_lsa_dom_chal(&(r_s.srv_creds), srv_cred, srv_time); - - r_s.status = status; - - /* store the response in the SMB stream */ - q = lsa_io_r_sam_logoff(False, &r_s, q, base, 4); - - /* return length of SMB data stored */ - return q - start; -} - - -static void api_lsa_open_policy( char *param, char *data, - char **rdata, int *rdata_len ) -{ - int reply_len; - - /* we might actually want to decode the query, but it's not necessary */ - /* lsa_io_q_open_policy(...); */ - - /* return a 20 byte policy handle */ - reply_len = lsa_reply_open_policy(*rdata + 0x18, *rdata + 0x18); - - /* construct header, now that we know the reply length */ - make_rpc_reply(data, *rdata, reply_len); - *rdata_len = reply_len + 0x18; -} - -static void api_lsa_query_info( char *param, char *data, - char **rdata, int *rdata_len ) -{ - int reply_len; - - LSA_Q_QUERY_INFO q_i; - pstring dom_name; - pstring dom_sid; - - /* grab the info class and policy handle */ - lsa_io_q_query(True, &q_i, data + 0x18, data + 0x18, 4); - - pstrcpy(dom_name, lp_workgroup()); - pstrcpy(dom_sid , lp_domainsid()); - - /* construct reply. return status is always 0x0 */ - reply_len = lsa_reply_query_info(&q_i, *rdata + 0x18, *rdata + 0x18, - dom_name, dom_sid); - - /* construct header, now that we know the reply length */ - make_rpc_reply(data, *rdata, reply_len); - *rdata_len = reply_len + 0x18; -} - -static void api_lsa_lookup_sids( char *param, char *data, - char **rdata, int *rdata_len ) -{ - int reply_len; - - int i; - LSA_Q_LOOKUP_SIDS q_l; - pstring dom_name; - pstring dom_sid; - fstring dom_sids[MAX_LOOKUP_SIDS]; - - /* grab the info class and policy handle */ - lsa_io_q_lookup_sids(True, &q_l, data + 0x18, data + 0x18, 4); - - pstrcpy(dom_name, lp_workgroup()); - pstrcpy(dom_sid , lp_domainsid()); - - /* convert received SIDs to strings, so we can do them. */ - for (i = 0; i < q_l.num_entries; i++) - { - fstrcpy(dom_sids[i], dom_sid_to_string(&(q_l.dom_sids[i]))); - } - - /* construct reply. return status is always 0x0 */ - reply_len = lsa_reply_lookup_sids(*rdata + 0x18, *rdata + 0x18, - q_l.num_entries, dom_sids, /* text-converted SIDs */ - dom_name, dom_sid, /* domain name, domain SID */ - "S-1-1", "S-1-3", "S-1-5"); /* the three other SIDs */ - - /* construct header, now that we know the reply length */ - make_rpc_reply(data, *rdata, reply_len); - *rdata_len = reply_len + 0x18; -} - -static void api_lsa_lookup_names( char *param, char *data, - char **rdata, int *rdata_len ) -{ - int reply_len; - - int i; - LSA_Q_LOOKUP_RIDS q_l; - pstring dom_name; - pstring dom_sid; - uint32 dom_rids[MAX_LOOKUP_SIDS]; - - /* grab the info class and policy handle */ - lsa_io_q_lookup_rids(True, &q_l, data + 0x18, data + 0x18, 4); - - pstrcpy(dom_name, lp_workgroup()); - pstrcpy(dom_sid , lp_domainsid()); - - /* convert received RIDs to strings, so we can do them. */ - for (i = 0; i < q_l.num_entries; i++) - { - char *user_name = unistr2(q_l.lookup_name[i].str.buffer); - dom_rids[i] = name_to_rid(user_name); - } - - /* construct reply. return status is always 0x0 */ - reply_len = lsa_reply_lookup_rids(*rdata + 0x18, *rdata + 0x18, - q_l.num_entries, dom_rids, /* text-converted SIDs */ - dom_name, dom_sid, /* domain name, domain SID */ - "S-1-1", "S-1-3", "S-1-5"); /* the three other SIDs */ - - /* construct header, now that we know the reply length */ - make_rpc_reply(data, *rdata, reply_len); - *rdata_len = reply_len + 0x18; -} - -BOOL api_ntlsarpcTNP(int cnum,int uid, char *param,char *data, - int mdrcnt,int mprcnt, - char **rdata,char **rparam, - int *rdata_len,int *rparam_len) -{ - uint16 opnum = SVAL(data,22); - - int pkttype = CVAL(data, 2); - if (pkttype == 0x0b) /* RPC BIND */ - { - DEBUG(4,("netlogon rpc bind %x\n",pkttype)); - LsarpcTNP1(data,rdata,rdata_len); - return True; - } - - DEBUG(4,("ntlsa TransactNamedPipe op %x\n",opnum)); - switch (opnum) - { - case LSA_OPENPOLICY: - { - DEBUG(3,("LSA_OPENPOLICY\n")); - api_lsa_open_policy(param, data, rdata, rdata_len); - break; - } - - case LSA_QUERYINFOPOLICY: - { - DEBUG(3,("LSA_QUERYINFOPOLICY\n")); - - api_lsa_query_info(param, data, rdata, rdata_len); - break; - } - - case LSA_ENUMTRUSTDOM: - { - char *q = *rdata + 0x18; - - DEBUG(3,("LSA_ENUMTRUSTDOM\n")); - - initrpcreply(data, *rdata); - - SIVAL(q, 0, 0); /* enumeration context */ - SIVAL(q, 0, 4); /* entries read */ - SIVAL(q, 0, 8); /* trust information */ - - endrpcreply(data, *rdata, q-*rdata, 0x8000001a, rdata_len); - - break; - } - - case LSA_CLOSE: - { - char *q = *rdata + 0x18; - - DEBUG(3,("LSA_CLOSE\n")); - - initrpcreply(data, *rdata); - - SIVAL(q, 0, 0); - SIVAL(q, 0, 4); - SIVAL(q, 0, 8); - SIVAL(q, 0, 12); - SIVAL(q, 0, 16); - - endrpcreply(data, *rdata, q-*rdata, 0, rdata_len); - - break; - } - - case LSA_OPENSECRET: - { - char *q = *rdata + 0x18; - DEBUG(3,("LSA_OPENSECRET\n")); - - initrpcreply(data, *rdata); - - SIVAL(q, 0, 0); - SIVAL(q, 0, 4); - SIVAL(q, 0, 8); - SIVAL(q, 0, 12); - SIVAL(q, 0, 16); - - endrpcreply(data, *rdata, q-*rdata, 0xc000034, rdata_len); - - break; - } - - case LSA_LOOKUPSIDS: - { - DEBUG(3,("LSA_OPENSECRET\n")); - api_lsa_lookup_sids(param, data, rdata, rdata_len); - break; - } - - case LSA_LOOKUPNAMES: - { - DEBUG(3,("LSA_LOOKUPNAMES\n")); - api_lsa_lookup_names(param, data, rdata, rdata_len); - break; - } - - default: - { - DEBUG(4, ("NTLSARPC, unknown code: %lx\n", opnum)); - break; - } - } - return True; -} - -#endif /* NTDOMAIN */ diff --git a/source/smbd/predict.c b/source/smbd/predict.c deleted file mode 100644 index 7d6b2498f5a..00000000000 --- a/source/smbd/predict.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - file read prediction routines - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -extern int DEBUGLEVEL; - - -/* variables used by the read prediction module */ -static int rp_fd = -1; -static int rp_offset = 0; -static int rp_length = 0; -static int rp_alloced = 0; -static int rp_predict_fd = -1; -static int rp_predict_offset = 0; -static int rp_predict_length = 0; -static int rp_timeout = 5; -static time_t rp_time = 0; -static char *rp_buffer = NULL; -static BOOL predict_skip=False; -time_t smb_last_time=(time_t)0; - -/**************************************************************************** -handle read prediction on a file -****************************************************************************/ -int read_predict(int fd,int offset,char *buf,char **ptr,int num) -{ - int ret = 0; - int possible = rp_length - (offset - rp_offset); - - possible = MIN(possible,num); - - /* give data if possible */ - if (fd == rp_fd && - offset >= rp_offset && - possible>0 && - smb_last_time-rp_time < rp_timeout) - { - ret = possible; - if (buf) - memcpy(buf,rp_buffer + (offset-rp_offset),possible); - else - *ptr = rp_buffer + (offset-rp_offset); - DEBUG(5,("read-prediction gave %d bytes of %d\n",ret,num)); - } - - if (ret == num) { - predict_skip = True; - } else { - struct stat rp_stat; - - /* Find the end of the file - ensure we don't - read predict beyond it. */ - if(fstat(fd,&rp_stat) < 0) - { - DEBUG(0,("read-prediction failed on fstat. Error was %s\n", strerror(errno))); - predict_skip = True; - } - else - { - predict_skip = False; - - /* prepare the next prediction */ - rp_predict_fd = fd; - /* Make sure we don't seek beyond the end of the file. */ - rp_predict_offset = MIN((offset + num),rp_stat.st_size); - rp_predict_length = num; - } - } - - if (ret < 0) ret = 0; - - return(ret); -} - -/**************************************************************************** -pre-read some data -****************************************************************************/ -void do_read_prediction() -{ - static int readsize = 0; - - if (predict_skip) return; - - if (rp_predict_fd == -1) - return; - - rp_fd = rp_predict_fd; - rp_offset = rp_predict_offset; - rp_length = 0; - - rp_predict_fd = -1; - - if (readsize == 0) { - readsize = lp_readsize(); - readsize = MAX(readsize,1024); - } - - rp_predict_length = MIN(rp_predict_length,2*readsize); - rp_predict_length = MAX(rp_predict_length,1024); - rp_offset = (rp_offset/1024)*1024; - rp_predict_length = (rp_predict_length/1024)*1024; - - if (rp_predict_length > rp_alloced) - { - rp_buffer = Realloc(rp_buffer,rp_predict_length); - rp_alloced = rp_predict_length; - if (!rp_buffer) - { - DEBUG(0,("can't allocate read-prediction buffer\n")); - rp_predict_fd = -1; - rp_fd = -1; - rp_alloced = 0; - return; - } - } - - if (lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) { - rp_fd = -1; - rp_predict_fd = -1; - return; - } - - rp_length = read(rp_fd,rp_buffer,rp_predict_length); - rp_time = time(NULL); - if (rp_length < 0) - rp_length = 0; -} - -/**************************************************************************** -invalidate read-prediction on a fd -****************************************************************************/ -void invalidate_read_prediction(int fd) -{ - if (rp_fd == fd) - rp_fd = -1; - if (rp_predict_fd == fd) - rp_predict_fd = -1; -} - diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c deleted file mode 100644 index 8810bcd909d..00000000000 --- a/source/smbd/quotas.c +++ /dev/null @@ -1,657 +0,0 @@ -#ifdef QUOTAS -/* - Unix SMB/Netbios implementation. - Version 1.9. - support for quotas - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -/* - * This is one of the most system dependent parts of Samba, and its - * done a litle differently. Each system has its own way of doing - * things :-( - */ - -#include "includes.h" - -extern int DEBUGLEVEL; - -#ifdef LINUX - -#include <sys/types.h> -#include <asm/types.h> -#include <sys/quota.h> - -#include <mntent.h> -#include <linux/unistd.h> - -_syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr); - -/**************************************************************************** -try to get the disk space from disk quotas (LINUX version) -****************************************************************************/ - -BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize) -{ - uid_t euser_id; - int r; - struct dqblk D; - struct stat S; - FILE *fp; - struct mntent *mnt; - int devno; - int found; - - /* 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))) { - if ( stat(mnt->mnt_dir,&S) == -1 ) - continue ; - if (S.st_dev == devno) { - found = True ; - break ; - } - } - endmntent(fp) ; - - if (!found) { - return(False); - } - - euser_id=geteuid(); - seteuid(0); - r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D); - seteuid(euser_id); - - /* 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_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) || - (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) || - (D.dqb_isoftlimit && D.dqb_curinodes>=D.dqb_isoftlimit) || - (D.dqb_ihardlimit && D.dqb_curinodes>=D.dqb_ihardlimit) - ) - { - *dfree = 0; - *dsize = D.dqb_curblocks; - } - else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0) - { - return(False); - } - else { - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - *dsize = D.dqb_bsoftlimit; - } - return (True); -} - -#elif defined(CRAY) - -#include <sys/quota.h> -#include <mntent.h> - -/**************************************************************************** -try to get the disk space from disk quotas (CRAY VERSION) -****************************************************************************/ -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) ; - -} - - -#elif defined(SUNOS5) || defined(SUNOS4) - -#include <fcntl.h> -#if defined(SUNOS5) -#include <sys/fs/ufs_quota.h> -#include <sys/mnttab.h> -#else /* defined(SUNOS4) */ -#include <ufs/quota.h> -#include <mntent.h> -#endif - -/**************************************************************************** -try to get the disk space from disk quotas (solaris 2 version) -****************************************************************************/ -/* Quota code by Peter Urbanec (amiga@cse.unsw.edu.au) */ -BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize) -{ - uid_t user_id, euser_id; - int ret; - struct dqblk D; -#if defined(SUNOS5) - struct quotctl command; - int file; - struct mnttab mnt; - static char name[MNT_LINE_MAX] ; -#else - struct mntent *mnt; - static char name[MNTMAXSTR] ; -#endif - FILE *fd; - struct stat sbuf; - dev_t devno ; - static dev_t devno_cached = 0 ; - int found ; - - if ( stat(path,&sbuf) == -1 ) - return(False) ; - - devno = sbuf.st_dev ; - DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%o\n", path,devno)); - if ( devno != devno_cached ) { - devno_cached = devno ; -#if defined(SUNOS5) - if ((fd = fopen(MNTTAB, "r")) == NULL) - return(False) ; - - found = False ; - while (getmntent(fd, &mnt) == 0) { - if ( stat(mnt.mnt_mountp,&sbuf) == -1 ) - continue ; - DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n", - mnt.mnt_mountp,sbuf.st_dev)); - if (sbuf.st_dev == devno) { - found = True ; - break ; - } - } - - strcpy(name,mnt.mnt_mountp) ; - strcat(name,"/quotas") ; - fclose(fd) ; -#else - if ((fd = setmntent(MOUNTED, "r")) == NULL) - return(False) ; - - found = False ; - while ((mnt = getmntent(fd)) != NULL) { - if ( stat(mnt->mnt_dir,&sbuf) == -1 ) - continue ; - DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n", - mnt->mnt_dir,sbuf.st_dev)); - if (sbuf.st_dev == devno) { - found = True ; - break ; - } - } - - strcpy(name,mnt->mnt_fsname) ; - endmntent(fd) ; -#endif - - if ( ! found ) - return(False) ; - } - - euser_id = geteuid(); - user_id = getuid(); - - setuid(0); /* Solaris seems to want to give info only to super-user */ - seteuid(0); - -#if defined(SUNOS5) - DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name)); - if((file=open(name, O_RDONLY))<0) { - setuid(user_id); /* Restore the original UID status */ - seteuid(euser_id); - return(False); - } - command.op = Q_GETQUOTA; - command.uid = euser_id; - command.addr = (caddr_t) &D; - ret = ioctl(file, Q_QUOTACTL, &command); - close(file); -#else - DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name)); - ret = quotactl(Q_GETQUOTA, name, euser_id, &D); -#endif - - setuid(user_id); /* Restore the original uid status. */ - seteuid(euser_id); - - if (ret < 0) { - DEBUG(2,("disk_quotas ioctl (Solaris) failed\n")); - return(False); - } - - - /* Use softlimit to determine disk space. A user exceeding the quota is told - * that there's no space left. Writes might actually work for a bit if the - * hardlimit is set higher than softlimit. Effectively the disk becomes - * made of rubber latex and begins to expand to accommodate the user :-) - */ - - if (D.dqb_bsoftlimit==0) - return(False); - *bsize = 512; - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - *dsize = D.dqb_bsoftlimit; - if(*dfree < 0) - { - *dfree = 0; - *dsize = D.dqb_curblocks; - } - -DEBUG(5,("disk_quotas for path \"%s\" returning bsize %d, dfree %d, dsize %d\n", - path,*bsize,*dfree,*dsize)); - - return(True); -} - - -#elif defined(OSF1) -#include <ufs/quota.h> - -/**************************************************************************** -try to get the disk space from disk quotas - OFS1 version -****************************************************************************/ -BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize) -{ - uid_t user_id, euser_id; - int r, save_errno; - struct dqblk D; - struct stat S; - - euser_id = geteuid(); - user_id = getuid(); - - setreuid(euser_id, -1); - r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D); - if (r) - save_errno = errno; - - if (setreuid(user_id, -1) == -1) - DEBUG(5,("Unable to reset uid to %d\n", user_id)); - - *bsize = DEV_BSIZE; - - if (r) - { - if (save_errno == EDQUOT) // disk quota exceeded - { - *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_bsoftlimit==0) - return(False); - - if ((D.dqb_curblocks>D.dqb_bsoftlimit)) { - *dfree = 0; - *dsize = D.dqb_curblocks; - } else { - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - *dsize = D.dqb_bsoftlimit; - } - return (True); -} - -#elif defined (SGI6) -/**************************************************************************** -try to get the disk space from disk quotas (IRIX 6.2 version) -****************************************************************************/ - -#include <sys/quota.h> -#include <mntent.h> - -BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize) -{ - uid_t euser_id; - int r; - struct dqblk D; - struct fs_disk_quota F; - struct stat S; - FILE *fp; - struct mntent *mnt; - int devno; - int found; - - /* 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))) { - if ( stat(mnt->mnt_dir,&S) == -1 ) - continue ; - if (S.st_dev == devno) { - found = True ; - break ; - } - } - endmntent(fp) ; - - if (!found) { - return(False); - } - - euser_id=geteuid(); - seteuid(0); - - /* Use softlimit to determine disk space, except when it has been exceeded */ - - *bsize = 512; - - if ( 0 == strcmp ( mnt->mnt_type, "efs" )) - { - r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D); - - if (r==-1) - return(False); - - /* Use softlimit to determine disk space, except when it has been exceeded */ - if ( - (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) || - (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) || - (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) || - (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit) - ) - { - *dfree = 0; - *dsize = D.dqb_curblocks; - } - else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0) - { - return(False); - } - else - { - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - *dsize = D.dqb_bsoftlimit; - } - - } - else if ( 0 == strcmp ( mnt->mnt_type, "xfs" )) - { - r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F); - - if (r==-1) - return(False); - - /* Use softlimit to determine disk space, except when it has been exceeded */ - if ( - (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) || - (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) || - (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) || - (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit) - ) - { - /* - * Fixme!: these are __uint64_t, this may truncate values - */ - *dfree = 0; - *dsize = (int) F.d_bcount; - } - else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0) - { - return(False); - } - else - { - *dfree = (int)(F.d_blk_softlimit - F.d_bcount); - *dsize = (int)F.d_blk_softlimit; - } - - } - else - return(False); - - return (True); - -} - -#else - -#ifdef __FreeBSD__ -#include <ufs/ufs/quota.h> -#include <machine/param.h> -#elif AIX -/* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */ -#include <jfs/quota.h> -/* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */ -#define dqb_curfiles dqb_curinodes -#define dqb_fhardlimit dqb_ihardlimit -#define dqb_fsoftlimit dqb_isoftlimit -#else /* !__FreeBSD__ && !AIX */ -#include <sys/quota.h> -#include <devnm.h> -#endif - -/**************************************************************************** -try to get the disk space from disk quotas - default version -****************************************************************************/ -BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize) -{ - uid_t euser_id; - int r; - struct dqblk D; -#if !defined(__FreeBSD__) && !defined(AIX) - char dev_disk[256]; - 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); -#endif - - euser_id = geteuid(); - -#ifdef USE_SETRES - { - uid_t user_id; - - /* for HPUX, real uid must be same as euid to execute quotactl for euid */ - user_id = getuid(); - setresuid(euser_id,-1,-1); - r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D); - if (setresuid(user_id,-1,-1)) - DEBUG(5,("Unable to reset uid to %d\n", user_id)); - } -#else /* USE_SETRES */ -#if defined(__FreeBSD__) - { - /* FreeBSD patches from Marty Moll <martym@arbor.edu> */ - uid_t user_id; - gid_t egrp_id; - - /* Need to be root to get quotas in FreeBSD */ - user_id = getuid(); - egrp_id = getegid(); - setuid(0); - seteuid(0); - r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D); - - /* As FreeBSD has group quotas, if getting the user - quota fails, try getting the group instead. */ - if (r) - r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D); - setuid(user_id); - seteuid(euser_id); - } -#elif defined(AIX) - /* AIX has both USER and GROUP quotas: - Get the USER quota (ohnielse@fysik.dtu.dk) */ - r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D); -#else /* !__FreeBSD__ && !AIX */ - r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D); -#endif /* !__FreeBSD__ && !AIX */ -#endif /* USE_SETRES */ - - /* Use softlimit to determine disk space, except when it has been exceeded */ -#if defined(__FreeBSD__) - *bsize = DEV_BSIZE; -#else /* !__FreeBSD__ */ - *bsize = 1024; -#endif /*!__FreeBSD__ */ - - if (r) - { - if (errno == EDQUOT) - { - *dfree =0; - *dsize =D.dqb_curblocks; - return (True); - } - else return(False); - } - if (D.dqb_bsoftlimit==0) - return(False); - /* Use softlimit to determine disk space, except when it has been exceeded */ - if ((D.dqb_curblocks>D.dqb_bsoftlimit) -#if !defined(__FreeBSD__) -||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0)) -#endif - ) { - *dfree = 0; - *dsize = D.dqb_curblocks; - } - else { - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - *dsize = D.dqb_bsoftlimit; - } - return (True); -} - -#endif - -#else -/* this keeps fussy compilers happy */ - void quotas_dummy(void) {} -#endif /* QUOTAS */ - diff --git a/source/smbd/reply.c b/source/smbd/reply.c deleted file mode 100644 index baccb762911..00000000000 --- a/source/smbd/reply.c +++ /dev/null @@ -1,3821 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - Main SMB reply routines - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* - This file handles most of the reply_ calls that the server - makes to handle specific protocols -*/ - - -#include "includes.h" -#include "trans2.h" - -/* look in server.c for some explanation of these variables */ -extern int Protocol; -extern int DEBUGLEVEL; -extern int max_send; -extern int max_recv; -extern int chain_fnum; -extern char magic_char; -extern connection_struct Connections[]; -extern files_struct Files[]; -extern BOOL case_sensitive; -extern BOOL case_preserve; -extern BOOL short_case_preserve; -extern pstring sesssetup_user; -extern fstring myworkgroup; -extern int Client; -extern int global_oplock_break; - -/* this macro should always be used to extract an fnum (smb_fid) from -a packet to ensure chaining works correctly */ -#define GETFNUM(buf,where) (chain_fnum!= -1?chain_fnum:SVAL(buf,where)) - - -/**************************************************************************** -report a possible attack via the password buffer overflow bug -****************************************************************************/ -static void overflow_attack(int len) -{ - DEBUG(0,("ERROR: Invalid password length %d\n", len)); - DEBUG(0,("your machine may be under attack by a user exploiting an old bug\n")); - DEBUG(0,("Attack was from IP=%s\n", client_addr())); - exit_server("possible attack"); -} - - -/**************************************************************************** - reply to an special message -****************************************************************************/ -int reply_special(char *inbuf,char *outbuf) -{ - int outsize = 4; - int msg_type = CVAL(inbuf,0); - int msg_flags = CVAL(inbuf,1); - pstring name1,name2; - extern fstring remote_machine; - extern fstring local_machine; - char *p; - - *name1 = *name2 = 0; - - smb_setlen(outbuf,0); - - switch (msg_type) { - case 0x81: /* session request */ - CVAL(outbuf,0) = 0x82; - CVAL(outbuf,3) = 0; - if (name_len(inbuf+4) > 50 || name_len(inbuf+4 + name_len(inbuf + 4)) > 50) { - DEBUG(0,("Invalid name length in session request\n")); - return(0); - } - name_extract(inbuf,4,name1); - name_extract(inbuf,4 + name_len(inbuf + 4),name2); - DEBUG(2,("netbios connect: name1=%s name2=%s\n", - name1,name2)); - - fstrcpy(remote_machine,name2); - trim_string(remote_machine," "," "); - p = strchr(remote_machine,' '); - strlower(remote_machine); - if (p) *p = 0; - - fstrcpy(local_machine,name1); - trim_string(local_machine," "," "); - p = strchr(local_machine,' '); - strlower(local_machine); - if (p) *p = 0; - - add_session_user(remote_machine); - - reload_services(True); - reopen_logs(); - - break; - - case 0x89: /* session keepalive request - (some old clients produce this?) */ - CVAL(outbuf,0) = 0x85; - CVAL(outbuf,3) = 0; - break; - - case 0x82: /* positive session response */ - case 0x83: /* negative session response */ - case 0x84: /* retarget session response */ - DEBUG(0,("Unexpected session response\n")); - break; - - case 0x85: /* session keepalive */ - default: - return(0); - } - - DEBUG(5,("%s init msg_type=0x%x msg_flags=0x%x\n", - timestring(),msg_type,msg_flags)); - - return(outsize); -} - - -/******************************************************************* -work out what error to give to a failed connection -********************************************************************/ -static int connection_error(char *inbuf,char *outbuf,int connection_num) -{ - switch (connection_num) - { - case -8: - return(ERROR(ERRSRV,ERRnoresource)); - case -7: - return(ERROR(ERRSRV,ERRbaduid)); - case -6: - return(ERROR(ERRSRV,ERRinvdevice)); - case -5: - return(ERROR(ERRSRV,ERRinvnetname)); - case -4: - return(ERROR(ERRSRV,ERRaccess)); - case -3: - return(ERROR(ERRDOS,ERRnoipc)); - case -2: - return(ERROR(ERRSRV,ERRinvnetname)); - } - return(ERROR(ERRSRV,ERRbadpw)); -} - - - -/**************************************************************************** - parse a share descriptor string -****************************************************************************/ -static void parse_connect(char *p,char *service,char *user, - char *password,int *pwlen,char *dev) -{ - char *p2; - - DEBUG(4,("parsing connect string %s\n",p)); - - p2 = strrchr(p,'\\'); - if (p2 == NULL) - fstrcpy(service,p); - else - fstrcpy(service,p2+1); - - p += strlen(p) + 2; - - fstrcpy(password,p); - *pwlen = strlen(password); - - p += strlen(p) + 2; - - fstrcpy(dev,p); - - *user = 0; - p = strchr(service,'%'); - if (p != NULL) - { - *p = 0; - fstrcpy(user,p+1); - } -} - - - - -/**************************************************************************** - reply to a tcon -****************************************************************************/ -int reply_tcon(char *inbuf,char *outbuf) -{ - pstring service; - pstring user; - pstring password; - pstring dev; - int connection_num; - int outsize = 0; - uint16 vuid = SVAL(inbuf,smb_uid); - int pwlen=0; - - *service = *user = *password = *dev = 0; - - parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev); - - connection_num = make_connection(service,user,password,pwlen,dev,vuid); - - if (connection_num < 0) - return(connection_error(inbuf,outbuf,connection_num)); - - outsize = set_message(outbuf,2,0,True); - SSVAL(outbuf,smb_vwv0,max_recv); - SSVAL(outbuf,smb_vwv1,connection_num); - SSVAL(outbuf,smb_tid,connection_num); - - DEBUG(3,("%s tcon service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num)); - - return(outsize); -} - - -/**************************************************************************** - reply to a tcon and X -****************************************************************************/ -int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize) -{ - pstring service; - pstring user; - pstring password; - pstring devicename; - int connection_num; - uint16 vuid = SVAL(inbuf,smb_uid); - int passlen = SVAL(inbuf,smb_vwv3); - BOOL doencrypt = SMBENCRYPT(); - - *service = *user = *password = *devicename = 0; - - /* we might have to close an old one */ - if ((SVAL(inbuf,smb_vwv2) & 0x1) != 0) - close_cnum(SVAL(inbuf,smb_tid),vuid); - - if (passlen > MAX_PASS_LEN) { - overflow_attack(passlen); - } - - { - char *path; - char *p; - memcpy(password,smb_buf(inbuf),passlen); - password[passlen]=0; - path = smb_buf(inbuf) + passlen; - - if (!doencrypt || passlen != 24) { - if (strequal(password," ")) - *password = 0; - passlen = strlen(password); - } - - fstrcpy(service,path+2); - p = strchr(service,'\\'); - if (!p) - return(ERROR(ERRSRV,ERRinvnetname)); - *p = 0; - fstrcpy(service,p+1); - p = strchr(service,'%'); - if (p) - { - *p++ = 0; - fstrcpy(user,p); - } - StrnCpy(devicename,path + strlen(path) + 1,6); - DEBUG(4,("Got device type %s\n",devicename)); - } - - connection_num = make_connection(service,user,password,passlen,devicename,vuid); - - if (connection_num < 0) - return(connection_error(inbuf,outbuf,connection_num)); - - if (Protocol < PROTOCOL_NT1) - { - set_message(outbuf,2,strlen(devicename)+1,True); - strcpy(smb_buf(outbuf),devicename); - } - else - { - char *fsname = "SAMBA"; - char *p; - - set_message(outbuf,3,3,True); - - p = smb_buf(outbuf); - strcpy(p,devicename); p = skip_string(p,1); /* device name */ - strcpy(p,fsname); p = skip_string(p,1); /* filesystem type e.g NTFS */ - - set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False); - - SSVAL(outbuf, smb_vwv2, 0x0); /* optional support */ - } - - DEBUG(3,("%s tconX service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num)); - - /* set the incoming and outgoing tid to the just created one */ - SSVAL(inbuf,smb_tid,connection_num); - SSVAL(outbuf,smb_tid,connection_num); - - return chain_reply(inbuf,outbuf,length,bufsize); -} - - -/**************************************************************************** - reply to an unknown type -****************************************************************************/ -int reply_unknown(char *inbuf,char *outbuf) -{ - int cnum; - int type; - cnum = SVAL(inbuf,smb_tid); - type = CVAL(inbuf,smb_com); - - DEBUG(0,("%s unknown command type (%s): cnum=%d type=%d (0x%X)\n", - timestring(), - smb_fn_name(type), - cnum,type,type)); - - return(ERROR(ERRSRV,ERRunknownsmb)); -} - - -/**************************************************************************** - reply to an ioctl -****************************************************************************/ -int reply_ioctl(char *inbuf,char *outbuf) -{ - DEBUG(3,("ignoring ioctl\n")); -#if 0 - /* we just say it succeeds and hope its all OK. - some day it would be nice to interpret them individually */ - return set_message(outbuf,1,0,True); -#else - return(ERROR(ERRSRV,ERRnosupport)); -#endif -} - - -/**************************************************************************** -reply to a session setup command -****************************************************************************/ -int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize) -{ - uint16 sess_vuid; - int gid; - int uid; - int smb_bufsize; - int smb_mpxmax; - int smb_vc_num; - uint32 smb_sesskey; - int smb_apasslen = 0; - pstring smb_apasswd; - int smb_ntpasslen = 0; - pstring smb_ntpasswd; - BOOL valid_nt_password = False; - pstring user; - BOOL guest=False; - BOOL computer_id=False; - static BOOL done_sesssetup = False; - BOOL doencrypt = SMBENCRYPT(); - - *smb_apasswd = 0; - - smb_bufsize = SVAL(inbuf,smb_vwv2); - smb_mpxmax = SVAL(inbuf,smb_vwv3); - smb_vc_num = SVAL(inbuf,smb_vwv4); - smb_sesskey = IVAL(inbuf,smb_vwv5); - - if (Protocol < PROTOCOL_NT1) { - smb_apasslen = SVAL(inbuf,smb_vwv7); - if (smb_apasslen > MAX_PASS_LEN) - { - overflow_attack(smb_apasslen); - } - - memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen); - pstrcpy(user,smb_buf(inbuf)+smb_apasslen); - - if (lp_security() != SEC_SERVER && !doencrypt) { - smb_apasslen = strlen(smb_apasswd); - } - } else { - uint16 passlen1 = SVAL(inbuf,smb_vwv7); - uint16 passlen2 = SVAL(inbuf,smb_vwv8); - uint32 client_caps = IVAL(inbuf,smb_vwv11); - enum remote_arch_types ra_type = get_remote_arch(); - - char *p = smb_buf(inbuf); - - /* client_caps is used as final determination if client is NT or Win95. - This is needed to return the correct error codes in some - circumstances. - */ - - if(ra_type == RA_WINNT || ra_type == RA_WIN95) - { - if(client_caps & (CAP_NT_SMBS | CAP_STATUS32)) - set_remote_arch( RA_WINNT); - else - set_remote_arch( RA_WIN95); - } - - if (passlen1 != 24 && passlen2 != 24) - doencrypt = False; - - if (passlen1 > MAX_PASS_LEN) { - overflow_attack(passlen1); - } - - passlen1 = MIN(passlen1, MAX_PASS_LEN); - passlen2 = MIN(passlen2, MAX_PASS_LEN); - - if(doencrypt) { - /* Save the lanman2 password and the NT md4 password. */ - smb_apasslen = passlen1; - memcpy(smb_apasswd,p,smb_apasslen); - smb_ntpasslen = passlen2; - memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen); - } else { - /* both Win95 and WinNT stuff up the password lengths for - non-encrypting systems. Uggh. - - if passlen1==24 its a win95 system, and its setting the - password length incorrectly. Luckily it still works with the - default code because Win95 will null terminate the password - anyway - - if passlen1>0 and passlen2>0 then maybe its a NT box and its - setting passlen2 to some random value which really stuffs - things up. we need to fix that one. */ - if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && - passlen2 != 1) { - passlen2 = 0; - } - /* we use the first password that they gave */ - smb_apasslen = passlen1; - StrnCpy(smb_apasswd,p,smb_apasslen); - - /* trim the password */ - smb_apasslen = strlen(smb_apasswd); - - /* wfwg sometimes uses a space instead of a null */ - if (strequal(smb_apasswd," ")) { - smb_apasslen = 0; - *smb_apasswd = 0; - } - } - - p += passlen1 + passlen2; - fstrcpy(user,p); p = skip_string(p,1); - DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n", - p,skip_string(p,1),skip_string(p,2))); - } - - - DEBUG(3,("sesssetupX:name=[%s]\n",user)); - - /* If name ends in $ then I think it's asking about whether a */ - /* computer with that name (minus the $) has access. For now */ - /* say yes to everything ending in $. */ - if (user[strlen(user) - 1] == '$') { - computer_id = True; - user[strlen(user) - 1] = '\0'; - } - - - /* If no username is sent use the guest account */ - if (!*user) - { - strcpy(user,lp_guestaccount(-1)); - /* If no user and no password then set guest flag. */ - if( *smb_apasswd == 0) - guest = True; - } - - strlower(user); - - strcpy(sesssetup_user,user); - - reload_services(True); - - add_session_user(user); - - /* Check if the given username was the guest user with no password. - We need to do this check after add_session_user() as that - call can potentially change the username (via map_user). - */ - - if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0)) - guest = True; - - if (!guest && !(lp_security() == SEC_SERVER && server_validate(inbuf)) && - !check_hosts_equiv(user)) - { - - /* now check if it's a valid username/password */ - /* If an NT password was supplied try and validate with that - first. This is superior as the passwords are mixed case - 128 length unicode */ - if(smb_ntpasslen) - { - if(!password_ok(user,smb_ntpasswd,smb_ntpasslen,NULL)) - DEBUG(0,("NT Password did not match ! Defaulting to Lanman\n")); - else - valid_nt_password = True; - } - if (!valid_nt_password && !password_ok(user,smb_apasswd,smb_apasslen,NULL)) - { - if (!computer_id && lp_security() >= SEC_USER) { -#if (GUEST_SESSSETUP == 0) - return(ERROR(ERRSRV,ERRbadpw)); -#endif -#if (GUEST_SESSSETUP == 1) - if (Get_Pwnam(user,True)) - return(ERROR(ERRSRV,ERRbadpw)); -#endif - } - if (*smb_apasswd || !Get_Pwnam(user,True)) - strcpy(user,lp_guestaccount(-1)); - DEBUG(3,("Registered username %s for guest access\n",user)); - guest = True; - } - } - - if (!Get_Pwnam(user,True)) { - DEBUG(3,("No such user %s - using guest account\n",user)); - strcpy(user,lp_guestaccount(-1)); - guest = True; - } - - if (!strequal(user,lp_guestaccount(-1)) && - lp_servicenumber(user) < 0) - { - int homes = lp_servicenumber(HOMES_NAME); - char *home = get_home_dir(user); - if (homes >= 0 && home) - lp_add_home(user,homes,home); - } - - - /* it's ok - setup a reply */ - if (Protocol < PROTOCOL_NT1) { - set_message(outbuf,3,0,True); - } else { - char *p; - set_message(outbuf,3,3,True); - p = smb_buf(outbuf); - strcpy(p,"Unix"); p = skip_string(p,1); - strcpy(p,"Samba "); strcat(p,VERSION); p = skip_string(p,1); - strcpy(p,myworkgroup); p = skip_string(p,1); - set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False); - /* perhaps grab OS version here?? */ - } - - /* Set the correct uid in the outgoing and incoming packets - We will use this on future requests to determine which - user we should become. - */ - { - struct passwd *pw = Get_Pwnam(user,False); - if (!pw) { - DEBUG(1,("Username %s is invalid on this system\n",user)); - return(ERROR(ERRSRV,ERRbadpw)); - } - gid = pw->pw_gid; - uid = pw->pw_uid; - } - - if (guest && !computer_id) - SSVAL(outbuf,smb_vwv2,1); - - /* register the name and uid as being validated, so further connections - to a uid can get through without a password, on the same VC */ - sess_vuid = register_vuid(uid,gid,user,guest); - - SSVAL(outbuf,smb_uid,sess_vuid); - SSVAL(inbuf,smb_uid,sess_vuid); - - if (!done_sesssetup) - max_send = MIN(max_send,smb_bufsize); - - DEBUG(6,("Client requested max send size of %d\n", max_send)); - - done_sesssetup = True; - - return chain_reply(inbuf,outbuf,length,bufsize); -} - - -/**************************************************************************** - reply to a chkpth -****************************************************************************/ -int reply_chkpth(char *inbuf,char *outbuf) -{ - int outsize = 0; - int cnum,mode; - pstring name; - BOOL ok = False; - BOOL bad_path = False; - - cnum = SVAL(inbuf,smb_tid); - - pstrcpy(name,smb_buf(inbuf) + 1); - unix_convert(name,cnum,0,&bad_path); - - mode = SVAL(inbuf,smb_vwv0); - - if (check_name(name,cnum)) - ok = directory_exist(name,NULL); - - if (!ok) - { - /* We special case this - as when a Windows machine - is parsing a path is steps through the components - one at a time - if a component fails it expects - ERRbadpath, not ERRbadfile. - */ - if(errno == ENOENT) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - -#if 0 - /* Ugly - NT specific hack - maybe not needed ? (JRA) */ - if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && - (get_remote_arch() == RA_WINNT)) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbaddirectory; - } -#endif - - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - - outsize = set_message(outbuf,0,0,True); - - DEBUG(3,("%s chkpth %s cnum=%d mode=%d\n",timestring(),name,cnum,mode)); - - return(outsize); -} - - -/**************************************************************************** - reply to a getatr -****************************************************************************/ -int reply_getatr(char *inbuf,char *outbuf) -{ - pstring fname; - int cnum; - int outsize = 0; - struct stat sbuf; - BOOL ok = False; - int mode=0; - uint32 size=0; - time_t mtime=0; - BOOL bad_path = False; - - cnum = SVAL(inbuf,smb_tid); - - pstrcpy(fname,smb_buf(inbuf) + 1); - unix_convert(fname,cnum,0,&bad_path); - - /* dos smetimes asks for a stat of "" - it returns a "hidden directory" - under WfWg - weird! */ - if (! (*fname)) - { - mode = aHIDDEN | aDIR; - if (!CAN_WRITE(cnum)) mode |= aRONLY; - size = 0; - mtime = 0; - ok = True; - } - else - if (check_name(fname,cnum)) - { - if (sys_stat(fname,&sbuf) == 0) - { - mode = dos_mode(cnum,fname,&sbuf); - size = sbuf.st_size; - mtime = sbuf.st_mtime; - if (mode & aDIR) - size = 0; - ok = True; - } - else - DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno))); - } - - if (!ok) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - - return(UNIXERROR(ERRDOS,ERRbadfile)); - } - - outsize = set_message(outbuf,10,0,True); - - SSVAL(outbuf,smb_vwv0,mode); - put_dos_date3(outbuf,smb_vwv1,mtime); - SIVAL(outbuf,smb_vwv3,size); - - if (Protocol >= PROTOCOL_NT1) { - char *p = strrchr(fname,'/'); - uint16 flg2 = SVAL(outbuf,smb_flg2); - if (!p) p = fname; - if (!is_8_3(fname, True)) - SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */ - } - - DEBUG(3,("%s getatr name=%s mode=%d size=%d\n",timestring(),fname,mode,size)); - - return(outsize); -} - - -/**************************************************************************** - reply to a setatr -****************************************************************************/ -int reply_setatr(char *inbuf,char *outbuf) -{ - pstring fname; - int cnum; - int outsize = 0; - BOOL ok=False; - int mode; - time_t mtime; - BOOL bad_path = False; - - cnum = SVAL(inbuf,smb_tid); - - pstrcpy(fname,smb_buf(inbuf) + 1); - unix_convert(fname,cnum,0,&bad_path); - - mode = SVAL(inbuf,smb_vwv0); - mtime = make_unix_date3(inbuf+smb_vwv1); - - if (directory_exist(fname,NULL)) - mode |= aDIR; - if (check_name(fname,cnum)) - ok = (dos_chmod(cnum,fname,mode,NULL) == 0); - if (ok) - ok = set_filetime(fname,mtime); - - if (!ok) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - outsize = set_message(outbuf,0,0,True); - - DEBUG(3,("%s setatr name=%s mode=%d\n",timestring(),fname,mode)); - - return(outsize); -} - - -/**************************************************************************** - reply to a dskattr -****************************************************************************/ -int reply_dskattr(char *inbuf,char *outbuf) -{ - int cnum; - int outsize = 0; - int dfree,dsize,bsize; - - cnum = SVAL(inbuf,smb_tid); - - sys_disk_free(".",&bsize,&dfree,&dsize); - - outsize = set_message(outbuf,5,0,True); - - SSVAL(outbuf,smb_vwv0,dsize); - SSVAL(outbuf,smb_vwv1,bsize/512); - SSVAL(outbuf,smb_vwv2,512); - SSVAL(outbuf,smb_vwv3,dfree); - - DEBUG(3,("%s dskattr cnum=%d dfree=%d\n",timestring(),cnum,dfree)); - - return(outsize); -} - - -/**************************************************************************** - reply to a search - Can be called from SMBsearch, SMBffirst or SMBfunique. -****************************************************************************/ -int reply_search(char *inbuf,char *outbuf) -{ - pstring mask; - pstring directory; - pstring fname; - int size,mode; - time_t date; - int dirtype; - int cnum; - int outsize = 0; - int numentries = 0; - BOOL finished = False; - int maxentries; - int i; - char *p; - BOOL ok = False; - int status_len; - char *path; - char status[21]; - int dptr_num= -1; - BOOL check_descend = False; - BOOL expect_close = False; - BOOL can_open = True; - BOOL bad_path = False; - - *mask = *directory = *fname = 0; - - /* If we were called as SMBffirst then we must expect close. */ - if(CVAL(inbuf,smb_com) == SMBffirst) - expect_close = True; - - cnum = SVAL(inbuf,smb_tid); - - outsize = set_message(outbuf,1,3,True); - maxentries = SVAL(inbuf,smb_vwv0); - dirtype = SVAL(inbuf,smb_vwv1); - path = smb_buf(inbuf) + 1; - status_len = SVAL(smb_buf(inbuf),3 + strlen(path)); - - - /* dirtype &= ~aDIR; */ - - DEBUG(5,("path=%s status_len=%d\n",path,status_len)); - - - if (status_len == 0) - { - pstring dir2; - - pstrcpy(directory,smb_buf(inbuf)+1); - pstrcpy(dir2,smb_buf(inbuf)+1); - unix_convert(directory,cnum,0,&bad_path); - unix_format(dir2); - - if (!check_name(directory,cnum)) - can_open = False; - - p = strrchr(dir2,'/'); - if (p == NULL) - { - strcpy(mask,dir2); - *dir2 = 0; - } - else - { - *p = 0; - pstrcpy(mask,p+1); - } - - p = strrchr(directory,'/'); - if (!p) - *directory = 0; - else - *p = 0; - - if (strlen(directory) == 0) - strcpy(directory,"./"); - bzero(status,21); - CVAL(status,0) = dirtype; - } - else - { - memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21); - memcpy(mask,status+1,11); - mask[11] = 0; - dirtype = CVAL(status,0) & 0x1F; - Connections[cnum].dirptr = dptr_fetch(status+12,&dptr_num); - if (!Connections[cnum].dirptr) - goto SearchEmpty; - string_set(&Connections[cnum].dirpath,dptr_path(dptr_num)); - if (!case_sensitive) - strnorm(mask); - } - - /* turn strings of spaces into a . */ - { - trim_string(mask,NULL," "); - if ((p = strrchr(mask,' '))) - { - fstring ext; - fstrcpy(ext,p+1); - *p = 0; - trim_string(mask,NULL," "); - strcat(mask,"."); - strcat(mask,ext); - } - } - - { - for (p=mask; *p; p++) - { - if (*p != '?' && *p != '*' && !isdoschar(*p)) - { - DEBUG(5,("Invalid char [%c] in search mask?\n",*p)); - *p = '?'; - } - } - } - - if (!strchr(mask,'.') && strlen(mask)>8) - { - fstring tmp; - fstrcpy(tmp,&mask[8]); - mask[8] = '.'; - mask[9] = 0; - strcat(mask,tmp); - } - - DEBUG(5,("mask=%s directory=%s\n",mask,directory)); - - if (can_open) - { - p = smb_buf(outbuf) + 3; - - ok = True; - - if (status_len == 0) - { - dptr_num = dptr_create(cnum,directory,expect_close,SVAL(inbuf,smb_pid)); - if (dptr_num < 0) - { - if(dptr_num == -2) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return (UNIXERROR(ERRDOS,ERRnofids)); - } - return(ERROR(ERRDOS,ERRnofids)); - } - } - - DEBUG(4,("dptr_num is %d\n",dptr_num)); - - if (ok) - { - if ((dirtype&0x1F) == aVOLID) - { - memcpy(p,status,21); - make_dir_struct(p,"???????????",volume_label(SNUM(cnum)),0,aVOLID,0); - dptr_fill(p+12,dptr_num); - if (dptr_zero(p+12) && (status_len==0)) - numentries = 1; - else - numentries = 0; - p += DIR_STRUCT_SIZE; - } - else - { - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)))); - if (in_list(Connections[cnum].dirpath, - lp_dontdescend(SNUM(cnum)),True)) - check_descend = True; - - for (i=numentries;(i<maxentries) && !finished;i++) - { - finished = - !get_dir_entry(cnum,mask,dirtype,fname,&size,&mode,&date,check_descend); - if (!finished) - { - memcpy(p,status,21); - make_dir_struct(p,mask,fname,size,mode,date); - dptr_fill(p+12,dptr_num); - numentries++; - } - p += DIR_STRUCT_SIZE; - } - } - } - } - - - SearchEmpty: - - if (numentries == 0 || !ok) - { - CVAL(outbuf,smb_rcls) = ERRDOS; - SSVAL(outbuf,smb_err,ERRnofiles); - } - - /* If we were called as SMBffirst with smb_search_id == NULL - and no entries were found then return error and close dirptr - (X/Open spec) */ - - if(ok && expect_close && numentries == 0 && status_len == 0) - { - CVAL(outbuf,smb_rcls) = ERRDOS; - SSVAL(outbuf,smb_err,ERRnofiles); - /* Also close the dptr - we know it's gone */ - dptr_close(dptr_num); - } - - /* If we were called as SMBfunique, then we can close the dirptr now ! */ - if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique) - dptr_close(dptr_num); - - SSVAL(outbuf,smb_vwv0,numentries); - SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE); - CVAL(smb_buf(outbuf),0) = 5; - SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE); - - if (Protocol >= PROTOCOL_NT1) { - uint16 flg2 = SVAL(outbuf,smb_flg2); - SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */ - } - - outsize += DIR_STRUCT_SIZE*numentries; - smb_setlen(outbuf,outsize - 4); - - if ((! *directory) && dptr_path(dptr_num)) - sprintf(directory,"(%s)",dptr_path(dptr_num)); - - DEBUG(4,("%s %s mask=%s path=%s cnum=%d dtype=%d nument=%d of %d\n", - timestring(), - smb_fn_name(CVAL(inbuf,smb_com)), - mask,directory,cnum,dirtype,numentries,maxentries)); - - return(outsize); -} - - -/**************************************************************************** - reply to a fclose (stop directory search) -****************************************************************************/ -int reply_fclose(char *inbuf,char *outbuf) -{ - int cnum; - int outsize = 0; - int status_len; - char *path; - char status[21]; - int dptr_num= -1; - - cnum = SVAL(inbuf,smb_tid); - - outsize = set_message(outbuf,1,0,True); - path = smb_buf(inbuf) + 1; - status_len = SVAL(smb_buf(inbuf),3 + strlen(path)); - - - if (status_len == 0) - return(ERROR(ERRSRV,ERRsrverror)); - - memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21); - - if(dptr_fetch(status+12,&dptr_num)) { - /* Close the dptr - we know it's gone */ - dptr_close(dptr_num); - } - - SSVAL(outbuf,smb_vwv0,0); - - DEBUG(3,("%s search close cnum=%d\n",timestring(),cnum)); - - return(outsize); -} - - -/**************************************************************************** - reply to an open -****************************************************************************/ -int reply_open(char *inbuf,char *outbuf) -{ - pstring fname; - int cnum; - int fnum = -1; - int outsize = 0; - int fmode=0; - int share_mode; - int size = 0; - time_t mtime=0; - int unixmode; - int rmode=0; - struct stat sbuf; - BOOL bad_path = False; - files_struct *fsp; - int oplock_request = CORE_OPLOCK_REQUEST(inbuf); - - cnum = SVAL(inbuf,smb_tid); - - share_mode = SVAL(inbuf,smb_vwv0); - - pstrcpy(fname,smb_buf(inbuf)+1); - unix_convert(fname,cnum,0,&bad_path); - - fnum = find_free_file(); - if (fnum < 0) - return(ERROR(ERRSRV,ERRnofids)); - - if (!check_name(fname,cnum)) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - unixmode = unix_mode(cnum,aARCH); - - open_file_shared(fnum,cnum,fname,share_mode,3,unixmode, - oplock_request,&rmode,NULL); - - fsp = &Files[fnum]; - - if (!fsp->open) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) { - close_file(fnum); - return(ERROR(ERRDOS,ERRnoaccess)); - } - - size = sbuf.st_size; - fmode = dos_mode(cnum,fname,&sbuf); - mtime = sbuf.st_mtime; - - if (fmode & aDIR) { - DEBUG(3,("attempt to open a directory %s\n",fname)); - close_file(fnum); - return(ERROR(ERRDOS,ERRnoaccess)); - } - - outsize = set_message(outbuf,7,0,True); - SSVAL(outbuf,smb_vwv0,fnum); - SSVAL(outbuf,smb_vwv1,fmode); - put_dos_date3(outbuf,smb_vwv2,mtime); - SIVAL(outbuf,smb_vwv4,size); - SSVAL(outbuf,smb_vwv6,rmode); - - if (oplock_request && lp_fake_oplocks(SNUM(cnum))) { - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; - } - - if(fsp->granted_oplock) - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; - return(outsize); -} - - -/**************************************************************************** - reply to an open and X -****************************************************************************/ -int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize) -{ - pstring fname; - int cnum = SVAL(inbuf,smb_tid); - int fnum = -1; - int smb_mode = SVAL(inbuf,smb_vwv3); - int smb_attr = SVAL(inbuf,smb_vwv5); - BOOL oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf); -#if 0 - int open_flags = SVAL(inbuf,smb_vwv2); - int smb_sattr = SVAL(inbuf,smb_vwv4); - uint32 smb_time = make_unix_date3(inbuf+smb_vwv6); -#endif - int smb_ofun = SVAL(inbuf,smb_vwv8); - int unixmode; - int size=0,fmode=0,mtime=0,rmode=0; - struct stat sbuf; - int smb_action = 0; - BOOL bad_path = False; - files_struct *fsp; - - /* If it's an IPC, pass off the pipe handler. */ - if (IS_IPC(cnum)) - return reply_open_pipe_and_X(inbuf,outbuf,length,bufsize); - - /* XXXX we need to handle passed times, sattr and flags */ - - pstrcpy(fname,smb_buf(inbuf)); - unix_convert(fname,cnum,0,&bad_path); - - fnum = find_free_file(); - if (fnum < 0) - return(ERROR(ERRSRV,ERRnofids)); - - if (!check_name(fname,cnum)) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - unixmode = unix_mode(cnum,smb_attr | aARCH); - - open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode, - oplock_request, &rmode,&smb_action); - - fsp = &Files[fnum]; - - if (!fsp->open) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) { - close_file(fnum); - return(ERROR(ERRDOS,ERRnoaccess)); - } - - size = sbuf.st_size; - fmode = dos_mode(cnum,fname,&sbuf); - mtime = sbuf.st_mtime; - if (fmode & aDIR) { - close_file(fnum); - return(ERROR(ERRDOS,ERRnoaccess)); - } - - if (oplock_request && lp_fake_oplocks(SNUM(cnum))) { - smb_action |= EXTENDED_OPLOCK_GRANTED; - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; - } - - if(fsp->granted_oplock) { - smb_action |= EXTENDED_OPLOCK_GRANTED; - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; - } - - set_message(outbuf,15,0,True); - SSVAL(outbuf,smb_vwv2,fnum); - SSVAL(outbuf,smb_vwv3,fmode); - put_dos_date3(outbuf,smb_vwv4,mtime); - SIVAL(outbuf,smb_vwv6,size); - SSVAL(outbuf,smb_vwv8,rmode); - SSVAL(outbuf,smb_vwv11,smb_action); - - chain_fnum = fnum; - - return chain_reply(inbuf,outbuf,length,bufsize); -} - - -/**************************************************************************** - reply to a SMBulogoffX -****************************************************************************/ -int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize) -{ - uint16 vuid = SVAL(inbuf,smb_uid); - user_struct *vuser = get_valid_user_struct(vuid); - - if(vuser == 0) { - DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid)); - } - - /* in user level security we are supposed to close any files - open by this user */ - if ((vuser != 0) && (lp_security() != SEC_SHARE)) { - int i; - for (i=0;i<MAX_OPEN_FILES;i++) - if (Files[i].uid == vuser->uid && Files[i].open) { - close_file(i); - } - } - - invalidate_vuid(vuid); - - set_message(outbuf,2,0,True); - - DEBUG(3,("%s ulogoffX vuid=%d\n",timestring(),vuid)); - - return chain_reply(inbuf,outbuf,length,bufsize); -} - - -/**************************************************************************** - reply to a mknew or a create -****************************************************************************/ -int reply_mknew(char *inbuf,char *outbuf) -{ - pstring fname; - int cnum,com; - int fnum = -1; - int outsize = 0; - int createmode; - mode_t unixmode; - int ofun = 0; - BOOL bad_path = False; - files_struct *fsp; - int oplock_request = CORE_OPLOCK_REQUEST(inbuf); - - com = SVAL(inbuf,smb_com); - cnum = SVAL(inbuf,smb_tid); - - createmode = SVAL(inbuf,smb_vwv0); - pstrcpy(fname,smb_buf(inbuf)+1); - unix_convert(fname,cnum,0,&bad_path); - - if (createmode & aVOLID) - { - DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname)); - } - - unixmode = unix_mode(cnum,createmode); - - fnum = find_free_file(); - if (fnum < 0) - return(ERROR(ERRSRV,ERRnofids)); - - if (!check_name(fname,cnum)) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - if(com == SMBmknew) - { - /* We should fail if file exists. */ - ofun = 0x10; - } - else - { - /* SMBcreate - Create if file doesn't exist, truncate if it does. */ - ofun = 0x12; - } - - /* Open file in dos compatibility share mode. */ - open_file_shared(fnum,cnum,fname,(DENY_FCB<<4)|0xF, ofun, unixmode, - oplock_request, NULL, NULL); - - fsp = &Files[fnum]; - - if (!fsp->open) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - outsize = set_message(outbuf,1,0,True); - SSVAL(outbuf,smb_vwv0,fnum); - - if (oplock_request && lp_fake_oplocks(SNUM(cnum))) { - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; - } - - if(fsp->granted_oplock) - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; - - DEBUG(2,("new file %s\n",fname)); - DEBUG(3,("%s mknew %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname,Files[fnum].fd_ptr->fd,fnum,cnum,createmode,unixmode)); - - return(outsize); -} - - -/**************************************************************************** - reply to a create temporary file -****************************************************************************/ -int reply_ctemp(char *inbuf,char *outbuf) -{ - pstring fname; - pstring fname2; - int cnum; - int fnum = -1; - int outsize = 0; - int createmode; - mode_t unixmode; - BOOL bad_path = False; - files_struct *fsp; - int oplock_request = CORE_OPLOCK_REQUEST(inbuf); - - cnum = SVAL(inbuf,smb_tid); - createmode = SVAL(inbuf,smb_vwv0); - pstrcpy(fname,smb_buf(inbuf)+1); - strcat(fname,"/TMXXXXXX"); - unix_convert(fname,cnum,0,&bad_path); - - unixmode = unix_mode(cnum,createmode); - - fnum = find_free_file(); - if (fnum < 0) - return(ERROR(ERRSRV,ERRnofids)); - - if (!check_name(fname,cnum)) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - strcpy(fname2,(char *)mktemp(fname)); - - /* Open file in dos compatibility share mode. */ - /* We should fail if file exists. */ - open_file_shared(fnum,cnum,fname2,(DENY_FCB<<4)|0xF, 0x10, unixmode, - oplock_request, NULL, NULL); - - fsp = &Files[fnum]; - - if (!fsp->open) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - outsize = set_message(outbuf,1,2 + strlen(fname2),True); - SSVAL(outbuf,smb_vwv0,fnum); - CVAL(smb_buf(outbuf),0) = 4; - strcpy(smb_buf(outbuf) + 1,fname2); - - if (oplock_request && lp_fake_oplocks(SNUM(cnum))) { - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; - } - - if(fsp->granted_oplock) - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; - - DEBUG(2,("created temp file %s\n",fname2)); - DEBUG(3,("%s ctemp %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname2,Files[fnum].fd_ptr->fd,fnum,cnum,createmode,unixmode)); - - return(outsize); -} - - -/******************************************************************* -check if a user is allowed to delete a file -********************************************************************/ -static BOOL can_delete(char *fname,int cnum,int dirtype) -{ - struct stat sbuf; - int fmode; - - if (!CAN_WRITE(cnum)) return(False); - - if (sys_lstat(fname,&sbuf) != 0) return(False); - fmode = dos_mode(cnum,fname,&sbuf); - if (fmode & aDIR) return(False); - if (!lp_delete_readonly(SNUM(cnum))) { - if (fmode & aRONLY) return(False); - } - if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) - return(False); - if (!check_file_sharing(cnum,fname)) return(False); - return(True); -} - -/**************************************************************************** - reply to a unlink -****************************************************************************/ -int reply_unlink(char *inbuf,char *outbuf) -{ - int outsize = 0; - pstring name; - int cnum; - int dirtype; - pstring directory; - pstring mask; - char *p; - int count=0; - int error = ERRnoaccess; - BOOL has_wild; - BOOL exists=False; - BOOL bad_path = False; - - *directory = *mask = 0; - - cnum = SVAL(inbuf,smb_tid); - dirtype = SVAL(inbuf,smb_vwv0); - - pstrcpy(name,smb_buf(inbuf) + 1); - - DEBUG(3,("reply_unlink : %s\n",name)); - - unix_convert(name,cnum,0,&bad_path); - - p = strrchr(name,'/'); - if (!p) { - strcpy(directory,"./"); - strcpy(mask,name); - } else { - *p = 0; - strcpy(directory,name); - strcpy(mask,p+1); - } - - if (is_mangled(mask)) - check_mangled_stack(mask); - - has_wild = strchr(mask,'*') || strchr(mask,'?'); - - if (!has_wild) { - strcat(directory,"/"); - strcat(directory,mask); - if (can_delete(directory,cnum,dirtype) && !sys_unlink(directory)) count++; - if (!count) exists = file_exist(directory,NULL); - } else { - void *dirptr = NULL; - char *dname; - - if (check_name(directory,cnum)) - dirptr = OpenDir(cnum, directory, True); - - /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then - the pattern matches against the long name, otherwise the short name - We don't implement this yet XXXX - */ - - if (dirptr) - { - error = ERRbadfile; - - if (strequal(mask,"????????.???")) - strcpy(mask,"*"); - - while ((dname = ReadDirName(dirptr))) - { - pstring fname; - pstrcpy(fname,dname); - - if(!mask_match(fname, mask, case_sensitive, False)) continue; - - error = ERRnoaccess; - sprintf(fname,"%s/%s",directory,dname); - if (!can_delete(fname,cnum,dirtype)) continue; - if (!sys_unlink(fname)) count++; - DEBUG(3,("reply_unlink : doing unlink on %s\n",fname)); - } - CloseDir(dirptr); - } - } - - if (count == 0) { - if (exists) - return(ERROR(ERRDOS,error)); - else - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,error)); - } - } - - outsize = set_message(outbuf,0,0,True); - - return(outsize); -} - - -/**************************************************************************** - reply to a readbraw (core+ protocol) -****************************************************************************/ -int reply_readbraw(char *inbuf, char *outbuf) -{ - int cnum,maxcount,mincount,fnum; - int nread = 0; - uint32 startpos; - char *header = outbuf; - int ret=0; - int fd; - char *fname; - - /* - * Special check if an oplock break has been issued - * and the readraw request croses on the wire, we must - * return a zero length response here. - */ - - if(global_oplock_break) - { - _smb_setlen(header,0); - transfer_file(0,Client,0,header,4,0); - DEBUG(5,("readbraw - oplock break finished\n")); - return -1; - } - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - startpos = IVAL(inbuf,smb_vwv1); - maxcount = SVAL(inbuf,smb_vwv3); - mincount = SVAL(inbuf,smb_vwv4); - - /* ensure we don't overrun the packet size */ - maxcount = MIN(65535,maxcount); - maxcount = MAX(mincount,maxcount); - - if (!FNUM_OK(fnum,cnum) || !Files[fnum].can_read) - { - DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",fnum)); - _smb_setlen(header,0); - transfer_file(0,Client,0,header,4,0); - return(-1); - } - else - { - fd = Files[fnum].fd_ptr->fd; - fname = Files[fnum].name; - } - - - if (!is_locked(fnum,cnum,maxcount,startpos)) - { - int size = Files[fnum].size; - int sizeneeded = startpos + maxcount; - - if (size < sizeneeded) { - struct stat st; - if (fstat(Files[fnum].fd_ptr->fd,&st) == 0) - size = st.st_size; - if (!Files[fnum].can_write) - Files[fnum].size = size; - } - - nread = MIN(maxcount,(int)(size - startpos)); - } - - if (nread < mincount) - nread = 0; - - DEBUG(3,("%s readbraw fnum=%d cnum=%d start=%d max=%d min=%d nread=%d\n", - timestring(), - fnum,cnum,startpos, - maxcount,mincount,nread)); - -#if UNSAFE_READRAW - { - int predict=0; - _smb_setlen(header,nread); - - if (!Files[fnum].can_write) - predict = read_predict(fd,startpos,header+4,NULL,nread); - - if ((nread-predict) > 0) - seek_file(fnum,startpos + predict); - - ret = transfer_file(fd,Client,nread-predict,header,4+predict, - startpos+predict); - } - - if (ret != nread+4) - DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n", - fname,startpos,nread,ret)); - -#else - ret = read_file(fnum,header+4,startpos,nread); - if (ret < mincount) ret = 0; - - _smb_setlen(header,ret); - transfer_file(0,Client,0,header,4+ret,0); -#endif - - DEBUG(5,("readbraw finished\n")); - return -1; -} - - -/**************************************************************************** - reply to a lockread (core+ protocol) -****************************************************************************/ -int reply_lockread(char *inbuf,char *outbuf) -{ - int cnum,fnum; - int nread = -1; - char *data; - int outsize = 0; - uint32 startpos, numtoread; - int eclass; - uint32 ecode; - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_READ(fnum); - CHECK_ERROR(fnum); - - numtoread = SVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv2); - - outsize = set_message(outbuf,5,3,True); - numtoread = MIN(BUFFER_SIZE-outsize,numtoread); - data = smb_buf(outbuf) + 3; - - if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode)) - return (ERROR(eclass,ecode)); - - nread = read_file(fnum,data,startpos,numtoread); - - if (nread < 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - outsize += nread; - SSVAL(outbuf,smb_vwv0,nread); - SSVAL(outbuf,smb_vwv5,nread+3); - SSVAL(smb_buf(outbuf),1,nread); - - DEBUG(3,("%s lockread fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread)); - - return(outsize); -} - - -/**************************************************************************** - reply to a read -****************************************************************************/ -int reply_read(char *inbuf,char *outbuf) -{ - int cnum,numtoread,fnum; - int nread = 0; - char *data; - uint32 startpos; - int outsize = 0; - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_READ(fnum); - CHECK_ERROR(fnum); - - numtoread = SVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv2); - - outsize = set_message(outbuf,5,3,True); - numtoread = MIN(BUFFER_SIZE-outsize,numtoread); - data = smb_buf(outbuf) + 3; - - if (is_locked(fnum,cnum,numtoread,startpos)) - return(ERROR(ERRDOS,ERRlock)); - - if (numtoread > 0) - nread = read_file(fnum,data,startpos,numtoread); - - if (nread < 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - outsize += nread; - SSVAL(outbuf,smb_vwv0,nread); - SSVAL(outbuf,smb_vwv5,nread+3); - CVAL(smb_buf(outbuf),0) = 1; - SSVAL(smb_buf(outbuf),1,nread); - - DEBUG(3,("%s read fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread)); - - return(outsize); -} - - -/**************************************************************************** - reply to a read and X -****************************************************************************/ -int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize) -{ - int fnum = GETFNUM(inbuf,smb_vwv2); - uint32 smb_offs = IVAL(inbuf,smb_vwv3); - int smb_maxcnt = SVAL(inbuf,smb_vwv5); - int smb_mincnt = SVAL(inbuf,smb_vwv6); - int cnum; - int nread = -1; - char *data; - BOOL ok = False; - - cnum = SVAL(inbuf,smb_tid); - - CHECK_FNUM(fnum,cnum); - CHECK_READ(fnum); - CHECK_ERROR(fnum); - - set_message(outbuf,12,0,True); - data = smb_buf(outbuf); - - if (is_locked(fnum,cnum,smb_maxcnt,smb_offs)) - return(ERROR(ERRDOS,ERRlock)); - nread = read_file(fnum,data,smb_offs,smb_maxcnt); - ok = True; - - if (nread < 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - SSVAL(outbuf,smb_vwv5,nread); - SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf)); - SSVAL(smb_buf(outbuf),-2,nread); - - DEBUG(3,("%s readX fnum=%d cnum=%d min=%d max=%d nread=%d\n", - timestring(),fnum,cnum, - smb_mincnt,smb_maxcnt,nread)); - - chain_fnum = fnum; - - return chain_reply(inbuf,outbuf,length,bufsize); -} - - -/**************************************************************************** - reply to a writebraw (core+ or LANMAN1.0 protocol) -****************************************************************************/ -int reply_writebraw(char *inbuf,char *outbuf) -{ - int nwritten=0; - int total_written=0; - int numtowrite=0; - int cnum,fnum; - int outsize = 0; - long startpos; - char *data=NULL; - BOOL write_through; - int tcount; - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_WRITE(fnum); - CHECK_ERROR(fnum); - - tcount = IVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv3); - write_through = BITSETW(inbuf+smb_vwv7,0); - - /* We have to deal with slightly different formats depending - on whether we are using the core+ or lanman1.0 protocol */ - if(Protocol <= PROTOCOL_COREPLUS) { - numtowrite = SVAL(smb_buf(inbuf),-2); - data = smb_buf(inbuf); - } else { - numtowrite = SVAL(inbuf,smb_vwv10); - data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11); - } - - /* force the error type */ - CVAL(inbuf,smb_com) = SMBwritec; - CVAL(outbuf,smb_com) = SMBwritec; - - if (is_locked(fnum,cnum,tcount,startpos)) - return(ERROR(ERRDOS,ERRlock)); - - if (seek_file(fnum,startpos) != startpos) - DEBUG(0,("couldn't seek to %d in writebraw\n",startpos)); - - if (numtowrite>0) - nwritten = write_file(fnum,data,numtowrite); - - DEBUG(3,("%s writebraw1 fnum=%d cnum=%d start=%d num=%d wrote=%d sync=%d\n", - timestring(),fnum,cnum,startpos,numtowrite,nwritten,write_through)); - - if (nwritten < numtowrite) - return(UNIXERROR(ERRHRD,ERRdiskfull)); - - total_written = nwritten; - - /* Return a message to the redirector to tell it - to send more bytes */ - CVAL(outbuf,smb_com) = SMBwritebraw; - SSVALS(outbuf,smb_vwv0,-1); - outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True); - send_smb(Client,outbuf); - - /* Now read the raw data into the buffer and write it */ - if (read_smb_length(Client,inbuf,SMB_SECONDARY_WAIT) == -1) { - exit_server("secondary writebraw failed"); - } - - /* Even though this is not an smb message, smb_len - returns the generic length of an smb message */ - numtowrite = smb_len(inbuf); - - if (tcount > nwritten+numtowrite) { - DEBUG(3,("Client overestimated the write %d %d %d\n", - tcount,nwritten,numtowrite)); - } - - nwritten = transfer_file(Client,Files[fnum].fd_ptr->fd,numtowrite,NULL,0, - startpos+nwritten); - total_written += nwritten; - - /* Set up outbuf to return the correct return */ - outsize = set_message(outbuf,1,0,True); - CVAL(outbuf,smb_com) = SMBwritec; - SSVAL(outbuf,smb_vwv0,total_written); - - if (nwritten < numtowrite) { - CVAL(outbuf,smb_rcls) = ERRHRD; - SSVAL(outbuf,smb_err,ERRdiskfull); - } - - if (lp_syncalways(SNUM(cnum)) || write_through) - sync_file(fnum); - - DEBUG(3,("%s writebraw2 fnum=%d cnum=%d start=%d num=%d wrote=%d\n", - timestring(),fnum,cnum,startpos,numtowrite,total_written)); - - /* we won't return a status if write through is not selected - this - follows what WfWg does */ - if (!write_through && total_written==tcount) - return(-1); - - return(outsize); -} - - -/**************************************************************************** - reply to a writeunlock (core+) -****************************************************************************/ -int reply_writeunlock(char *inbuf,char *outbuf) -{ - int cnum,fnum; - int nwritten = -1; - int outsize = 0; - char *data; - uint32 numtowrite,startpos; - int eclass; - uint32 ecode; - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_WRITE(fnum); - CHECK_ERROR(fnum); - - numtowrite = SVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv2); - data = smb_buf(inbuf) + 3; - - if (is_locked(fnum,cnum,numtowrite,startpos)) - return(ERROR(ERRDOS,ERRlock)); - - seek_file(fnum,startpos); - - /* The special X/Open SMB protocol handling of - zero length writes is *NOT* done for - this call */ - if(numtowrite == 0) - nwritten = 0; - else - nwritten = write_file(fnum,data,numtowrite); - - if (lp_syncalways(SNUM(cnum))) - sync_file(fnum); - - if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - if(!do_unlock(fnum, cnum, numtowrite, startpos, &eclass, &ecode)) - return(ERROR(eclass,ecode)); - - outsize = set_message(outbuf,1,0,True); - - SSVAL(outbuf,smb_vwv0,nwritten); - - DEBUG(3,("%s writeunlock fnum=%d cnum=%d num=%d wrote=%d\n", - timestring(),fnum,cnum,numtowrite,nwritten)); - - return(outsize); -} - - -/**************************************************************************** - reply to a write -****************************************************************************/ -int reply_write(char *inbuf,char *outbuf,int dum1,int dum2) -{ - int cnum,numtowrite,fnum; - int nwritten = -1; - int outsize = 0; - int startpos; - char *data; - - dum1 = dum2 = 0; - - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_WRITE(fnum); - CHECK_ERROR(fnum); - - numtowrite = SVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv2); - data = smb_buf(inbuf) + 3; - - if (is_locked(fnum,cnum,numtowrite,startpos)) - return(ERROR(ERRDOS,ERRlock)); - - seek_file(fnum,startpos); - - /* X/Open SMB protocol says that if smb_vwv1 is - zero then the file size should be extended or - truncated to the size given in smb_vwv[2-3] */ - if(numtowrite == 0) - nwritten = set_filelen(Files[fnum].fd_ptr->fd, startpos); - else - nwritten = write_file(fnum,data,numtowrite); - - if (lp_syncalways(SNUM(cnum))) - sync_file(fnum); - - if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - outsize = set_message(outbuf,1,0,True); - - SSVAL(outbuf,smb_vwv0,nwritten); - - if (nwritten < numtowrite) { - CVAL(outbuf,smb_rcls) = ERRHRD; - SSVAL(outbuf,smb_err,ERRdiskfull); - } - - DEBUG(3,("%s write fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,numtowrite,nwritten)); - - return(outsize); -} - - -/**************************************************************************** - reply to a write and X -****************************************************************************/ -int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize) -{ - int fnum = GETFNUM(inbuf,smb_vwv2); - uint32 smb_offs = IVAL(inbuf,smb_vwv3); - int smb_dsize = SVAL(inbuf,smb_vwv10); - int smb_doff = SVAL(inbuf,smb_vwv11); - BOOL write_through = BITSETW(inbuf+smb_vwv7,0); - int cnum; - int nwritten = -1; - char *data; - - cnum = SVAL(inbuf,smb_tid); - - CHECK_FNUM(fnum,cnum); - CHECK_WRITE(fnum); - CHECK_ERROR(fnum); - - data = smb_base(inbuf) + smb_doff; - - if (is_locked(fnum,cnum,smb_dsize,smb_offs)) - return(ERROR(ERRDOS,ERRlock)); - - seek_file(fnum,smb_offs); - - /* X/Open SMB protocol says that, unlike SMBwrite - if the length is zero then NO truncation is - done, just a write of zero. To truncate a file, - use SMBwrite. */ - if(smb_dsize == 0) - nwritten = 0; - else - nwritten = write_file(fnum,data,smb_dsize); - - if(((nwritten == 0) && (smb_dsize != 0))||(nwritten < 0)) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - set_message(outbuf,6,0,True); - - SSVAL(outbuf,smb_vwv2,nwritten); - - if (nwritten < smb_dsize) { - CVAL(outbuf,smb_rcls) = ERRHRD; - SSVAL(outbuf,smb_err,ERRdiskfull); - } - - DEBUG(3,("%s writeX fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,smb_dsize,nwritten)); - - chain_fnum = fnum; - - if (lp_syncalways(SNUM(cnum)) || write_through) - sync_file(fnum); - - return chain_reply(inbuf,outbuf,length,bufsize); -} - - -/**************************************************************************** - reply to a lseek -****************************************************************************/ -int reply_lseek(char *inbuf,char *outbuf) -{ - int cnum,fnum; - uint32 startpos; - int32 res= -1; - int mode,umode; - int outsize = 0; - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_ERROR(fnum); - - mode = SVAL(inbuf,smb_vwv1) & 3; - startpos = IVAL(inbuf,smb_vwv2); - - switch (mode & 3) - { - case 0: umode = SEEK_SET; break; - case 1: umode = SEEK_CUR; break; - case 2: umode = SEEK_END; break; - default: - umode = SEEK_SET; break; - } - - res = lseek(Files[fnum].fd_ptr->fd,startpos,umode); - Files[fnum].pos = res; - - outsize = set_message(outbuf,2,0,True); - SIVALS(outbuf,smb_vwv0,res); - - DEBUG(3,("%s lseek fnum=%d cnum=%d ofs=%d mode=%d\n",timestring(),fnum,cnum,startpos,mode)); - - return(outsize); -} - - -/**************************************************************************** - reply to a flush -****************************************************************************/ -int reply_flush(char *inbuf,char *outbuf) -{ - int cnum, fnum; - int outsize = set_message(outbuf,0,0,True); - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - if (fnum != 0xFFFF) { - CHECK_FNUM(fnum,cnum); - CHECK_ERROR(fnum); - } - - if (fnum == 0xFFFF) - { - int i; - for (i=0;i<MAX_OPEN_FILES;i++) - if (OPEN_FNUM(i)) - sync_file(i); - } - else - sync_file(fnum); - - DEBUG(3,("%s flush fnum=%d\n",timestring(),fnum)); - return(outsize); -} - - -/**************************************************************************** - reply to a exit -****************************************************************************/ -int reply_exit(char *inbuf,char *outbuf) -{ - int outsize = set_message(outbuf,0,0,True); - DEBUG(3,("%s exit\n",timestring())); - - return(outsize); -} - - -/**************************************************************************** - reply to a close -****************************************************************************/ -int reply_close(char *inbuf,char *outbuf) -{ - int fnum,cnum; - int outsize = 0; - time_t mtime; - int32 eclass = 0, err = 0; - - outsize = set_message(outbuf,0,0,True); - - cnum = SVAL(inbuf,smb_tid); - - fnum = GETFNUM(inbuf,smb_vwv0); - CHECK_FNUM(fnum,cnum); - - if(HAS_CACHED_ERROR(fnum)) { - eclass = Files[fnum].wbmpx_ptr->wr_errclass; - err = Files[fnum].wbmpx_ptr->wr_error; - } - - mtime = make_unix_date3(inbuf+smb_vwv1); - - /* try and set the date */ - set_filetime(Files[fnum].name,mtime); - - close_file(fnum); - - /* We have a cached error */ - if(eclass || err) - return(ERROR(eclass,err)); - - DEBUG(3,("%s close fd=%d fnum=%d cnum=%d (numopen=%d)\n", - timestring(),Files[fnum].fd_ptr->fd,fnum,cnum, - Connections[cnum].num_files_open)); - - return(outsize); -} - - -/**************************************************************************** - reply to a writeclose (Core+ protocol) -****************************************************************************/ -int reply_writeclose(char *inbuf,char *outbuf) -{ - int cnum,numtowrite,fnum; - int nwritten = -1; - int outsize = 0; - int startpos; - char *data; - time_t mtime; - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_WRITE(fnum); - CHECK_ERROR(fnum); - - numtowrite = SVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv2); - mtime = make_unix_date3(inbuf+smb_vwv4); - data = smb_buf(inbuf) + 1; - - if (is_locked(fnum,cnum,numtowrite,startpos)) - return(ERROR(ERRDOS,ERRlock)); - - seek_file(fnum,startpos); - - nwritten = write_file(fnum,data,numtowrite); - - set_filetime(Files[fnum].name,mtime); - - close_file(fnum); - - DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n", - timestring(),fnum,cnum,numtowrite,nwritten, - Connections[cnum].num_files_open)); - - if (nwritten <= 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - outsize = set_message(outbuf,1,0,True); - - SSVAL(outbuf,smb_vwv0,nwritten); - return(outsize); -} - - -/**************************************************************************** - reply to a lock -****************************************************************************/ -int reply_lock(char *inbuf,char *outbuf) -{ - int fnum,cnum; - int outsize = set_message(outbuf,0,0,True); - uint32 count,offset; - int eclass; - uint32 ecode; - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_ERROR(fnum); - - count = IVAL(inbuf,smb_vwv1); - offset = IVAL(inbuf,smb_vwv3); - - DEBUG(3,("%s lock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum,offset,count)); - - if(!do_lock( fnum, cnum, count, offset, &eclass, &ecode)) - return (ERROR(eclass,ecode)); - - return(outsize); -} - - -/**************************************************************************** - reply to a unlock -****************************************************************************/ -int reply_unlock(char *inbuf,char *outbuf) -{ - int fnum,cnum; - int outsize = set_message(outbuf,0,0,True); - uint32 count,offset; - int eclass; - uint32 ecode; - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_ERROR(fnum); - - count = IVAL(inbuf,smb_vwv1); - offset = IVAL(inbuf,smb_vwv3); - - if(!do_unlock(fnum, cnum, count, offset, &eclass, &ecode)) - return (ERROR(eclass,ecode)); - - DEBUG(3,("%s unlock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum,offset,count)); - - return(outsize); -} - - -/**************************************************************************** - reply to a tdis -****************************************************************************/ -int reply_tdis(char *inbuf,char *outbuf) -{ - int cnum; - int outsize = set_message(outbuf,0,0,True); - uint16 vuid; - - cnum = SVAL(inbuf,smb_tid); - vuid = SVAL(inbuf,smb_uid); - - if (!OPEN_CNUM(cnum)) { - DEBUG(4,("Invalid cnum in tdis (%d)\n",cnum)); - return(ERROR(ERRSRV,ERRinvnid)); - } - - Connections[cnum].used = False; - - close_cnum(cnum,vuid); - - DEBUG(3,("%s tdis cnum=%d\n",timestring(),cnum)); - - return outsize; -} - - - -/**************************************************************************** - reply to a echo -****************************************************************************/ -int reply_echo(char *inbuf,char *outbuf) -{ - int cnum; - int smb_reverb = SVAL(inbuf,smb_vwv0); - int seq_num; - int data_len = smb_buflen(inbuf); - int outsize = set_message(outbuf,1,data_len,True); - - cnum = SVAL(inbuf,smb_tid); - - /* According to the latest CIFS spec we shouldn't - care what the TID is. - */ - -#if 0 - if (cnum != 0xFFFF && !OPEN_CNUM(cnum)) - { - DEBUG(4,("Invalid cnum in echo (%d)\n",cnum)); - return(ERROR(ERRSRV,ERRinvnid)); - } -#endif - - /* copy any incoming data back out */ - if (data_len > 0) - memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len); - - if (smb_reverb > 100) - { - DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb)); - smb_reverb = 100; - } - - for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) - { - SSVAL(outbuf,smb_vwv0,seq_num); - - smb_setlen(outbuf,outsize - 4); - - send_smb(Client,outbuf); - } - - DEBUG(3,("%s echo %d times cnum=%d\n",timestring(),smb_reverb,cnum)); - - return -1; -} - - -/**************************************************************************** - reply to a printopen -****************************************************************************/ -int reply_printopen(char *inbuf,char *outbuf) -{ - pstring fname; - pstring fname2; - int cnum; - int fnum = -1; - int outsize = 0; - - *fname = *fname2 = 0; - - cnum = SVAL(inbuf,smb_tid); - - if (!CAN_PRINT(cnum)) - return(ERROR(ERRDOS,ERRnoaccess)); - - { - pstring s; - char *p; - pstrcpy(s,smb_buf(inbuf)+1); - p = s; - while (*p) - { - if (!(isalnum(*p) || strchr("._-",*p))) - *p = 'X'; - p++; - } - - if (strlen(s) > 10) s[10] = 0; - - sprintf(fname,"%s.XXXXXX",s); - } - - fnum = find_free_file(); - if (fnum < 0) - return(ERROR(ERRSRV,ERRnofids)); - - strcpy(fname2,(char *)mktemp(fname)); - - if (!check_name(fname2,cnum)) - return(ERROR(ERRDOS,ERRnoaccess)); - - /* Open for exclusive use, write only. */ - open_file_shared(fnum,cnum,fname2,(DENY_ALL<<4)|1, 0x12, unix_mode(cnum,0), - 0, NULL, NULL); - - if (!Files[fnum].open) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - /* force it to be a print file */ - Files[fnum].print_file = True; - - outsize = set_message(outbuf,1,0,True); - SSVAL(outbuf,smb_vwv0,fnum); - - DEBUG(3,("%s openprint %s fd=%d fnum=%d cnum=%d\n",timestring(),fname2,Files[fnum].fd_ptr->fd,fnum,cnum)); - - return(outsize); -} - - -/**************************************************************************** - reply to a printclose -****************************************************************************/ -int reply_printclose(char *inbuf,char *outbuf) -{ - int fnum,cnum; - int outsize = set_message(outbuf,0,0,True); - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_ERROR(fnum); - - if (!CAN_PRINT(cnum)) - return(ERROR(ERRDOS,ERRnoaccess)); - - close_file(fnum); - - DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum)); - - return(outsize); -} - - -/**************************************************************************** - reply to a printqueue -****************************************************************************/ -int reply_printqueue(char *inbuf,char *outbuf) -{ - int cnum; - int outsize = set_message(outbuf,2,3,True); - int max_count = SVAL(inbuf,smb_vwv0); - int start_index = SVAL(inbuf,smb_vwv1); - uint16 vuid; - - cnum = SVAL(inbuf,smb_tid); - vuid = SVAL(inbuf,smb_uid); - -/* allow checking the queue for anyone */ -#if 0 - if (!CAN_PRINT(cnum)) - return(ERROR(ERRDOS,ERRnoaccess)); -#endif - - SSVAL(outbuf,smb_vwv0,0); - SSVAL(outbuf,smb_vwv1,0); - CVAL(smb_buf(outbuf),0) = 1; - SSVAL(smb_buf(outbuf),1,0); - - DEBUG(3,("%s printqueue cnum=%d start_index=%d max_count=%d\n", - timestring(),cnum,start_index,max_count)); - - if (!OPEN_CNUM(cnum) || !Connections[cnum].printer) - { - int i; - cnum = -1; - - for (i=0;i<MAX_CONNECTIONS;i++) - if (CAN_PRINT(i) && Connections[i].printer) - cnum = i; - - if (cnum == -1) - for (i=0;i<MAX_CONNECTIONS;i++) - if (OPEN_CNUM(i)) - cnum = i; - - if (!OPEN_CNUM(cnum)) - return(ERROR(ERRSRV,ERRinvnid)); - - DEBUG(5,("connection not open or not a printer, using cnum %d\n",cnum)); - } - - if (!become_user(cnum,vuid)) - return(ERROR(ERRSRV,ERRinvnid)); - - { - print_queue_struct *queue = NULL; - char *p = smb_buf(outbuf) + 3; - int count = get_printqueue(SNUM(cnum),cnum,&queue,NULL); - int num_to_get = ABS(max_count); - int first = (max_count>0?start_index:start_index+max_count+1); - int i; - - if (first >= count) - num_to_get = 0; - else - num_to_get = MIN(num_to_get,count-first); - - - for (i=first;i<first+num_to_get;i++) - { - put_dos_date2(p,0,queue[i].time); - CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3); - SSVAL(p,5,printjob_encode(SNUM(cnum), queue[i].job)); - SIVAL(p,7,queue[i].size); - CVAL(p,11) = 0; - StrnCpy(p+12,queue[i].user,16); - p += 28; - } - - if (count > 0) - { - outsize = set_message(outbuf,2,28*count+3,False); - SSVAL(outbuf,smb_vwv0,count); - SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1)); - CVAL(smb_buf(outbuf),0) = 1; - SSVAL(smb_buf(outbuf),1,28*count); - } - - if (queue) free(queue); - - DEBUG(3,("%d entries returned in queue\n",count)); - } - - return(outsize); -} - - -/**************************************************************************** - reply to a printwrite -****************************************************************************/ -int reply_printwrite(char *inbuf,char *outbuf) -{ - int cnum,numtowrite,fnum; - int outsize = set_message(outbuf,0,0,True); - char *data; - - cnum = SVAL(inbuf,smb_tid); - - if (!CAN_PRINT(cnum)) - return(ERROR(ERRDOS,ERRnoaccess)); - - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_WRITE(fnum); - CHECK_ERROR(fnum); - - numtowrite = SVAL(smb_buf(inbuf),1); - data = smb_buf(inbuf) + 3; - - if (write_file(fnum,data,numtowrite) != numtowrite) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - DEBUG(3,("%s printwrite fnum=%d cnum=%d num=%d\n",timestring(),fnum,cnum,numtowrite)); - - return(outsize); -} - - -/**************************************************************************** - reply to a mkdir -****************************************************************************/ -int reply_mkdir(char *inbuf,char *outbuf) -{ - pstring directory; - int cnum; - int outsize,ret= -1; - BOOL bad_path = False; - - pstrcpy(directory,smb_buf(inbuf) + 1); - cnum = SVAL(inbuf,smb_tid); - unix_convert(directory,cnum,0,&bad_path); - - if (check_name(directory,cnum)) - ret = sys_mkdir(directory,unix_mode(cnum,aDIR)); - - if (ret < 0) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - outsize = set_message(outbuf,0,0,True); - - DEBUG(3,("%s mkdir %s cnum=%d ret=%d\n",timestring(),directory,cnum,ret)); - - return(outsize); -} - -/**************************************************************************** -Static function used by reply_rmdir to delete an entire directory -tree recursively. -****************************************************************************/ -static BOOL recursive_rmdir(char *directory) -{ - char *dname = NULL; - BOOL ret = False; - void *dirptr = OpenDir(-1, directory, False); - - if(dirptr == NULL) - return True; - - while((dname = ReadDirName(dirptr))) - { - pstring fullname; - struct stat st; - - if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) - continue; - - /* Construct the full name. */ - if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) - { - errno = ENOMEM; - ret = True; - break; - } - strcpy(fullname, directory); - strcat(fullname, "/"); - strcat(fullname, dname); - - if(sys_lstat(fullname, &st) != 0) - { - ret = True; - break; - } - - if(st.st_mode & S_IFDIR) - { - if(recursive_rmdir(fullname)!=0) - { - ret = True; - break; - } - if(sys_rmdir(fullname) != 0) - { - ret = True; - break; - } - } - else if(sys_unlink(fullname) != 0) - { - ret = True; - break; - } - } - CloseDir(dirptr); - return ret; -} - -/**************************************************************************** - reply to a rmdir -****************************************************************************/ -int reply_rmdir(char *inbuf,char *outbuf) -{ - pstring directory; - int cnum; - int outsize = 0; - BOOL ok = False; - BOOL bad_path = False; - - cnum = SVAL(inbuf,smb_tid); - pstrcpy(directory,smb_buf(inbuf) + 1); - unix_convert(directory,cnum,0,&bad_path); - - if (check_name(directory,cnum)) - { - - dptr_closepath(directory,SVAL(inbuf,smb_pid)); - ok = (sys_rmdir(directory) == 0); - if(!ok && (errno == ENOTEMPTY) && lp_veto_files(SNUM(cnum))) - { - /* Check to see if the only thing in this directory are - vetoed files/directories. If so then delete them and - retry. If we fail to delete any of them (and we *don't* - do a recursive delete) then fail the rmdir. */ - BOOL all_veto_files = True; - char *dname; - void *dirptr = OpenDir(cnum, directory, False); - - if(dirptr != NULL) - { - int dirpos = TellDir(dirptr); - while ((dname = ReadDirName(dirptr))) - { - if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) - continue; - if(!IS_VETO_PATH(cnum, dname)) - { - all_veto_files = False; - break; - } - } - if(all_veto_files) - { - SeekDir(dirptr,dirpos); - while ((dname = ReadDirName(dirptr))) - { - pstring fullname; - struct stat st; - - if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) - continue; - - /* Construct the full name. */ - if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) - { - errno = ENOMEM; - break; - } - pstrcpy(fullname, directory); - strcat(fullname, "/"); - strcat(fullname, dname); - - if(sys_lstat(fullname, &st) != 0) - break; - if(st.st_mode & S_IFDIR) - { - if(lp_recursive_veto_delete(SNUM(cnum))) - { - if(recursive_rmdir(fullname) != 0) - break; - } - if(sys_rmdir(fullname) != 0) - break; - } - else if(sys_unlink(fullname) != 0) - break; - } - CloseDir(dirptr); - /* Retry the rmdir */ - ok = (sys_rmdir(directory) == 0); - } - else - CloseDir(dirptr); - } - else - errno = ENOTEMPTY; - } - - if (!ok) - DEBUG(3,("couldn't remove directory %s : %s\n", - directory,strerror(errno))); - } - - if (!ok) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - - outsize = set_message(outbuf,0,0,True); - - DEBUG(3,("%s rmdir %s\n",timestring(),directory)); - - return(outsize); -} - - -/******************************************************************* -resolve wildcards in a filename rename -********************************************************************/ -static BOOL resolve_wildcards(char *name1,char *name2) -{ - fstring root1,root2; - fstring ext1,ext2; - char *p,*p2; - - name1 = strrchr(name1,'/'); - name2 = strrchr(name2,'/'); - - if (!name1 || !name2) return(False); - - fstrcpy(root1,name1); - fstrcpy(root2,name2); - p = strrchr(root1,'.'); - if (p) { - *p = 0; - fstrcpy(ext1,p+1); - } else { - fstrcpy(ext1,""); - } - p = strrchr(root2,'.'); - if (p) { - *p = 0; - fstrcpy(ext2,p+1); - } else { - fstrcpy(ext2,""); - } - - p = root1; - p2 = root2; - while (*p2) { - if (*p2 == '?') { - *p2 = *p; - p2++; - } else { - p2++; - } - if (*p) p++; - } - - p = ext1; - p2 = ext2; - while (*p2) { - if (*p2 == '?') { - *p2 = *p; - p2++; - } else { - p2++; - } - if (*p) p++; - } - - strcpy(name2,root2); - if (ext2[0]) { - strcat(name2,"."); - strcat(name2,ext2); - } - - return(True); -} - -/******************************************************************* -check if a user is allowed to rename a file -********************************************************************/ -static BOOL can_rename(char *fname,int cnum) -{ - struct stat sbuf; - - if (!CAN_WRITE(cnum)) return(False); - - if (sys_lstat(fname,&sbuf) != 0) return(False); - if (!check_file_sharing(cnum,fname)) return(False); - - return(True); -} - -/**************************************************************************** - reply to a mv -****************************************************************************/ -int reply_mv(char *inbuf,char *outbuf) -{ - int outsize = 0; - pstring name; - int cnum; - pstring directory; - pstring mask,newname; - pstring newname_last_component; - char *p; - int count=0; - int error = ERRnoaccess; - BOOL has_wild; - BOOL exists=False; - BOOL bad_path1 = False; - BOOL bad_path2 = False; - - *directory = *mask = 0; - - cnum = SVAL(inbuf,smb_tid); - - pstrcpy(name,smb_buf(inbuf) + 1); - pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name)); - - DEBUG(3,("reply_mv : %s -> %s\n",name,newname)); - - unix_convert(name,cnum,0,&bad_path1); - unix_convert(newname,cnum,newname_last_component,&bad_path2); - - /* - * Split the old name into directory and last component - * strings. Note that unix_convert may have stripped off a - * leading ./ from both name and newname if the rename is - * at the root of the share. We need to make sure either both - * name and newname contain a / character or neither of them do - * as this is checked in resolve_wildcards(). - */ - - p = strrchr(name,'/'); - if (!p) { - strcpy(directory,"."); - strcpy(mask,name); - } else { - *p = 0; - strcpy(directory,name); - strcpy(mask,p+1); - *p = '/'; /* Replace needed for exceptional test below. */ - } - - if (is_mangled(mask)) - check_mangled_stack(mask); - - has_wild = strchr(mask,'*') || strchr(mask,'?'); - - if (!has_wild) { - BOOL is_short_name = is_8_3(name, True); - - /* Add a terminating '/' to the directory name. */ - strcat(directory,"/"); - strcat(directory,mask); - - /* Ensure newname contains a '/' also */ - if(strrchr(newname,'/') == 0) { - pstring tmpstr; - - strcpy(tmpstr, "./"); - strcat(tmpstr, newname); - strcpy(newname, tmpstr); - } - - DEBUG(3,("reply_mv : case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", - case_sensitive, case_preserve, short_case_preserve, directory, - newname, newname_last_component, is_short_name)); - - /* - * Check for special case with case preserving and not - * case sensitive, if directory and newname are identical, - * and the old last component differs from the original - * last component only by case, then we should allow - * the rename (user is trying to change the case of the - * filename). - */ - if((case_sensitive == False) && ( ((case_preserve == True) && (is_short_name == False)) || - ((short_case_preserve == True) && (is_short_name == True))) && - strcsequal(directory, newname)) { - pstring newname_modified_last_component; - - /* - * Get the last component of the modified name. - * Note that we guarantee that newname contains a '/' - * character above. - */ - p = strrchr(newname,'/'); - strcpy(newname_modified_last_component,p+1); - - if(strcsequal(newname_modified_last_component, - newname_last_component) == False) { - /* - * Replace the modified last component with - * the original. - */ - strcpy(p+1, newname_last_component); - } - } - - if (resolve_wildcards(directory,newname) && - can_rename(directory,cnum) && - !file_exist(newname,NULL) && - !sys_rename(directory,newname)) count++; - - DEBUG(3,("reply_mv : %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed", - directory,newname)); - - if (!count) exists = file_exist(directory,NULL); - if (!count && exists && file_exist(newname,NULL)) { - exists = True; - error = 183; - } - } else { - void *dirptr = NULL; - char *dname; - pstring destname; - - if (check_name(directory,cnum)) - dirptr = OpenDir(cnum, directory, True); - - if (dirptr) - { - error = ERRbadfile; - - if (strequal(mask,"????????.???")) - strcpy(mask,"*"); - - while ((dname = ReadDirName(dirptr))) - { - pstring fname; - pstrcpy(fname,dname); - - if(!mask_match(fname, mask, case_sensitive, False)) continue; - - error = ERRnoaccess; - sprintf(fname,"%s/%s",directory,dname); - if (!can_rename(fname,cnum)) continue; - pstrcpy(destname,newname); - - if (!resolve_wildcards(fname,destname)) continue; - - if (file_exist(destname,NULL)) { - error = 183; - continue; - } - if (!sys_rename(fname,destname)) count++; - DEBUG(3,("reply_mv : doing rename on %s -> %s\n",fname,destname)); - } - CloseDir(dirptr); - } - } - - if (count == 0) { - if (exists) - return(ERROR(ERRDOS,error)); - else - { - if((errno == ENOENT) && (bad_path1 || bad_path2)) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,error)); - } - } - - outsize = set_message(outbuf,0,0,True); - - return(outsize); -} - -/******************************************************************* - copy a file as part of a reply_copy - ******************************************************************/ -static BOOL copy_file(char *src,char *dest1,int cnum,int ofun, - int count,BOOL target_is_directory) -{ - int Access,action; - struct stat st; - int ret=0; - int fnum1,fnum2; - pstring dest; - - pstrcpy(dest,dest1); - if (target_is_directory) { - char *p = strrchr(src,'/'); - if (p) - p++; - else - p = src; - strcat(dest,"/"); - strcat(dest,p); - } - - if (!file_exist(src,&st)) return(False); - - fnum1 = find_free_file(); - if (fnum1<0) return(False); - open_file_shared(fnum1,cnum,src,(DENY_NONE<<4), - 1,0,0,&Access,&action); - - if (!Files[fnum1].open) return(False); - - if (!target_is_directory && count) - ofun = 1; - - fnum2 = find_free_file(); - if (fnum2<0) { - close_file(fnum1); - return(False); - } - open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1, - ofun,st.st_mode,0,&Access,&action); - - if (!Files[fnum2].open) { - close_file(fnum1); - return(False); - } - - if ((ofun&3) == 1) { - lseek(Files[fnum2].fd_ptr->fd,0,SEEK_END); - } - - if (st.st_size) - ret = transfer_file(Files[fnum1].fd_ptr->fd,Files[fnum2].fd_ptr->fd,st.st_size,NULL,0,0); - - close_file(fnum1); - close_file(fnum2); - - return(ret == st.st_size); -} - - - -/**************************************************************************** - reply to a file copy. - ****************************************************************************/ -int reply_copy(char *inbuf,char *outbuf) -{ - int outsize = 0; - pstring name; - int cnum; - pstring directory; - pstring mask,newname; - char *p; - int count=0; - int error = ERRnoaccess; - BOOL has_wild; - BOOL exists=False; - int tid2 = SVAL(inbuf,smb_vwv0); - int ofun = SVAL(inbuf,smb_vwv1); - int flags = SVAL(inbuf,smb_vwv2); - BOOL target_is_directory=False; - BOOL bad_path1 = False; - BOOL bad_path2 = False; - - *directory = *mask = 0; - - cnum = SVAL(inbuf,smb_tid); - - pstrcpy(name,smb_buf(inbuf)); - pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name)); - - DEBUG(3,("reply_copy : %s -> %s\n",name,newname)); - - if (tid2 != cnum) { - /* can't currently handle inter share copies XXXX */ - DEBUG(3,("Rejecting inter-share copy\n")); - return(ERROR(ERRSRV,ERRinvdevice)); - } - - unix_convert(name,cnum,0,&bad_path1); - unix_convert(newname,cnum,0,&bad_path2); - - target_is_directory = directory_exist(newname,NULL); - - if ((flags&1) && target_is_directory) { - return(ERROR(ERRDOS,ERRbadfile)); - } - - if ((flags&2) && !target_is_directory) { - return(ERROR(ERRDOS,ERRbadpath)); - } - - if ((flags&(1<<5)) && directory_exist(name,NULL)) { - /* wants a tree copy! XXXX */ - DEBUG(3,("Rejecting tree copy\n")); - return(ERROR(ERRSRV,ERRerror)); - } - - p = strrchr(name,'/'); - if (!p) { - strcpy(directory,"./"); - strcpy(mask,name); - } else { - *p = 0; - strcpy(directory,name); - strcpy(mask,p+1); - } - - if (is_mangled(mask)) - check_mangled_stack(mask); - - has_wild = strchr(mask,'*') || strchr(mask,'?'); - - if (!has_wild) { - strcat(directory,"/"); - strcat(directory,mask); - if (resolve_wildcards(directory,newname) && - copy_file(directory,newname,cnum,ofun, - count,target_is_directory)) count++; - if (!count) exists = file_exist(directory,NULL); - } else { - void *dirptr = NULL; - char *dname; - pstring destname; - - if (check_name(directory,cnum)) - dirptr = OpenDir(cnum, directory, True); - - if (dirptr) - { - error = ERRbadfile; - - if (strequal(mask,"????????.???")) - strcpy(mask,"*"); - - while ((dname = ReadDirName(dirptr))) - { - pstring fname; - pstrcpy(fname,dname); - - if(!mask_match(fname, mask, case_sensitive, False)) continue; - - error = ERRnoaccess; - sprintf(fname,"%s/%s",directory,dname); - strcpy(destname,newname); - if (resolve_wildcards(fname,destname) && - copy_file(directory,newname,cnum,ofun, - count,target_is_directory)) count++; - DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname)); - } - CloseDir(dirptr); - } - } - - if (count == 0) { - if (exists) - return(ERROR(ERRDOS,error)); - else - { - if((errno == ENOENT) && (bad_path1 || bad_path2)) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,error)); - } - } - - outsize = set_message(outbuf,1,0,True); - SSVAL(outbuf,smb_vwv0,count); - - return(outsize); -} - - - -/**************************************************************************** - reply to a setdir -****************************************************************************/ -int reply_setdir(char *inbuf,char *outbuf) -{ - int cnum,snum; - int outsize = 0; - BOOL ok = False; - pstring newdir; - - cnum = SVAL(inbuf,smb_tid); - - snum = Connections[cnum].service; - if (!CAN_SETDIR(snum)) - return(ERROR(ERRDOS,ERRnoaccess)); - - pstrcpy(newdir,smb_buf(inbuf) + 1); - strlower(newdir); - - if (strlen(newdir) == 0) - ok = True; - else - { - ok = directory_exist(newdir,NULL); - if (ok) - string_set(&Connections[cnum].connectpath,newdir); - } - - if (!ok) - return(ERROR(ERRDOS,ERRbadpath)); - - outsize = set_message(outbuf,0,0,True); - CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh); - - DEBUG(3,("%s setdir %s cnum=%d\n",timestring(),newdir,cnum)); - - return(outsize); -} - - -/**************************************************************************** - reply to a lockingX request -****************************************************************************/ -int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize) -{ - int fnum = GETFNUM(inbuf,smb_vwv2); - unsigned char locktype = CVAL(inbuf,smb_vwv3); -#if 0 - unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1); -#endif - uint16 num_ulocks = SVAL(inbuf,smb_vwv6); - uint16 num_locks = SVAL(inbuf,smb_vwv7); - uint32 count, offset; - - int cnum; - int i; - char *data; - uint32 ecode=0, dummy2; - int eclass=0, dummy1; - - cnum = SVAL(inbuf,smb_tid); - - CHECK_FNUM(fnum,cnum); - CHECK_ERROR(fnum); - - data = smb_buf(inbuf); - - /* Check if this is an oplock break on a file - we have granted an oplock on. - */ - if((locktype == LOCKING_ANDX_OPLOCK_RELEASE) && - (num_ulocks == 0) && (num_locks == 0) && - (CVAL(inbuf,smb_vwv0) == 0xFF)) - { - share_lock_token token; - files_struct *fsp = &Files[fnum]; - uint32 dev = fsp->fd_ptr->dev; - uint32 inode = fsp->fd_ptr->inode; - - DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n", - fnum)); - /* - * Make sure we have granted an oplock on this file. - */ - if(!fsp->granted_oplock) - { - DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \ -no oplock granted on this file.\n", fnum)); - return ERROR(ERRDOS,ERRlock); - } - - /* Remove the oplock flag from the sharemode. */ - lock_share_entry(fsp->cnum, dev, inode, &token); - if(remove_share_oplock( fnum, token)==False) - { - DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \ -dev = %x, inode = %x\n", fnum, dev, inode)); - unlock_share_entry(fsp->cnum, dev, inode, token); - return -1; - } - unlock_share_entry(fsp->cnum, dev, inode, token); - - /* Clear the granted flag and return. */ - - fsp->granted_oplock = False; - return -1; - } - - /* Data now points at the beginning of the list - of smb_unlkrng structs */ - for(i = 0; i < (int)num_ulocks; i++) { - count = IVAL(data,SMB_LKLEN_OFFSET(i)); - offset = IVAL(data,SMB_LKOFF_OFFSET(i)); - if(!do_unlock(fnum,cnum,count,offset,&eclass, &ecode)) - return ERROR(eclass,ecode); - } - - /* Now do any requested locks */ - data += 10*num_ulocks; - /* Data now points at the beginning of the list - of smb_lkrng structs */ - for(i = 0; i < (int)num_locks; i++) { - count = IVAL(data,SMB_LKLEN_OFFSET(i)); - offset = IVAL(data,SMB_LKOFF_OFFSET(i)); - if(!do_lock(fnum,cnum,count,offset, &eclass, &ecode)) - break; - } - - /* If any of the above locks failed, then we must unlock - all of the previous locks (X/Open spec). */ - if(i != num_locks && num_locks != 0) { - for(; i >= 0; i--) { - count = IVAL(data,SMB_LKLEN_OFFSET(i)); - offset = IVAL(data,SMB_LKOFF_OFFSET(i)); - do_unlock(fnum,cnum,count,offset,&dummy1,&dummy2); - } - return ERROR(eclass,ecode); - } - - set_message(outbuf,2,0,True); - - DEBUG(3,("%s lockingX fnum=%d cnum=%d type=%d num_locks=%d num_ulocks=%d\n", - timestring(),fnum,cnum,(unsigned int)locktype,num_locks,num_ulocks)); - - chain_fnum = fnum; - - return chain_reply(inbuf,outbuf,length,bufsize); -} - - -/**************************************************************************** - reply to a SMBreadbmpx (read block multiplex) request -****************************************************************************/ -int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize) -{ - int cnum,fnum; - int nread = -1; - int total_read; - char *data; - uint32 startpos; - int outsize, mincount, maxcount; - int max_per_packet; - int tcount; - int pad; - - /* this function doesn't seem to work - disable by default */ - if (!lp_readbmpx()) - return(ERROR(ERRSRV,ERRuseSTD)); - - outsize = set_message(outbuf,8,0,True); - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_READ(fnum); - CHECK_ERROR(fnum); - - startpos = IVAL(inbuf,smb_vwv1); - maxcount = SVAL(inbuf,smb_vwv3); - mincount = SVAL(inbuf,smb_vwv4); - - data = smb_buf(outbuf); - pad = ((long)data)%4; - if (pad) pad = 4 - pad; - data += pad; - - max_per_packet = bufsize-(outsize+pad); - tcount = maxcount; - total_read = 0; - - if (is_locked(fnum,cnum,maxcount,startpos)) - return(ERROR(ERRDOS,ERRlock)); - - do - { - int N = MIN(max_per_packet,tcount-total_read); - - nread = read_file(fnum,data,startpos,N); - - if (nread <= 0) nread = 0; - - if (nread < N) - tcount = total_read + nread; - - set_message(outbuf,8,nread,False); - SIVAL(outbuf,smb_vwv0,startpos); - SSVAL(outbuf,smb_vwv2,tcount); - SSVAL(outbuf,smb_vwv6,nread); - SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf)); - - send_smb(Client,outbuf); - - total_read += nread; - startpos += nread; - } - while (total_read < tcount); - - return(-1); -} - - -/**************************************************************************** - reply to a SMBwritebmpx (write block multiplex primary) request -****************************************************************************/ -int reply_writebmpx(char *inbuf,char *outbuf) -{ - int cnum,numtowrite,fnum; - int nwritten = -1; - int outsize = 0; - uint32 startpos; - int tcount, write_through, smb_doff; - char *data; - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_WRITE(fnum); - CHECK_ERROR(fnum); - - tcount = SVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv3); - write_through = BITSETW(inbuf+smb_vwv7,0); - numtowrite = SVAL(inbuf,smb_vwv10); - smb_doff = SVAL(inbuf,smb_vwv11); - - data = smb_base(inbuf) + smb_doff; - - /* If this fails we need to send an SMBwriteC response, - not an SMBwritebmpx - set this up now so we don't forget */ - CVAL(outbuf,smb_com) = SMBwritec; - - if (is_locked(fnum,cnum,tcount,startpos)) - return(ERROR(ERRDOS,ERRlock)); - - seek_file(fnum,startpos); - nwritten = write_file(fnum,data,numtowrite); - - if(lp_syncalways(SNUM(cnum)) || write_through) - sync_file(fnum); - - if(nwritten < numtowrite) - return(UNIXERROR(ERRHRD,ERRdiskfull)); - - /* If the maximum to be written to this file - is greater than what we just wrote then set - up a secondary struct to be attached to this - fd, we will use this to cache error messages etc. */ - if(tcount > nwritten) - { - write_bmpx_struct *wbms; - if(Files[fnum].wbmpx_ptr != NULL) - wbms = Files[fnum].wbmpx_ptr; /* Use an existing struct */ - else - wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct)); - if(!wbms) - { - DEBUG(0,("Out of memory in reply_readmpx\n")); - return(ERROR(ERRSRV,ERRnoresource)); - } - wbms->wr_mode = write_through; - wbms->wr_discard = False; /* No errors yet */ - wbms->wr_total_written = nwritten; - wbms->wr_errclass = 0; - wbms->wr_error = 0; - Files[fnum].wbmpx_ptr = wbms; - } - - /* We are returning successfully, set the message type back to - SMBwritebmpx */ - CVAL(outbuf,smb_com) = SMBwriteBmpx; - - outsize = set_message(outbuf,1,0,True); - - SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */ - - DEBUG(3,("%s writebmpx fnum=%d cnum=%d num=%d wrote=%d\n", - timestring(),fnum,cnum,numtowrite,nwritten)); - - if (write_through && tcount==nwritten) { - /* we need to send both a primary and a secondary response */ - smb_setlen(outbuf,outsize - 4); - send_smb(Client,outbuf); - - /* now the secondary */ - outsize = set_message(outbuf,1,0,True); - CVAL(outbuf,smb_com) = SMBwritec; - SSVAL(outbuf,smb_vwv0,nwritten); - } - - return(outsize); -} - - -/**************************************************************************** - reply to a SMBwritebs (write block multiplex secondary) request -****************************************************************************/ -int reply_writebs(char *inbuf,char *outbuf) -{ - int cnum,numtowrite,fnum; - int nwritten = -1; - int outsize = 0; - int32 startpos; - int tcount, write_through, smb_doff; - char *data; - write_bmpx_struct *wbms; - BOOL send_response = False; - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - CHECK_FNUM(fnum,cnum); - CHECK_WRITE(fnum); - - tcount = SVAL(inbuf,smb_vwv1); - startpos = IVAL(inbuf,smb_vwv2); - numtowrite = SVAL(inbuf,smb_vwv6); - smb_doff = SVAL(inbuf,smb_vwv7); - - data = smb_base(inbuf) + smb_doff; - - /* We need to send an SMBwriteC response, not an SMBwritebs */ - CVAL(outbuf,smb_com) = SMBwritec; - - /* This fd should have an auxiliary struct attached, - check that it does */ - wbms = Files[fnum].wbmpx_ptr; - if(!wbms) return(-1); - - /* If write through is set we can return errors, else we must - cache them */ - write_through = wbms->wr_mode; - - /* Check for an earlier error */ - if(wbms->wr_discard) - return -1; /* Just discard the packet */ - - seek_file(fnum,startpos); - nwritten = write_file(fnum,data,numtowrite); - - if(lp_syncalways(SNUM(cnum)) || write_through) - sync_file(fnum); - - if (nwritten < numtowrite) - { - if(write_through) { - /* We are returning an error - we can delete the aux struct */ - if (wbms) free((char *)wbms); - Files[fnum].wbmpx_ptr = NULL; - return(ERROR(ERRHRD,ERRdiskfull)); - } - return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull)); - } - - /* Increment the total written, if this matches tcount - we can discard the auxiliary struct (hurrah !) and return a writeC */ - wbms->wr_total_written += nwritten; - if(wbms->wr_total_written >= tcount) - { - if (write_through) { - outsize = set_message(outbuf,1,0,True); - SSVAL(outbuf,smb_vwv0,wbms->wr_total_written); - send_response = True; - } - - free((char *)wbms); - Files[fnum].wbmpx_ptr = NULL; - } - - if(send_response) - return(outsize); - - return(-1); -} - - -/**************************************************************************** - reply to a SMBsetattrE -****************************************************************************/ -int reply_setattrE(char *inbuf,char *outbuf) -{ - int cnum,fnum; - struct utimbuf unix_times; - int outsize = 0; - - outsize = set_message(outbuf,0,0,True); - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_ERROR(fnum); - - /* Convert the DOS times into unix times. Ignore create - time as UNIX can't set this. - */ - unix_times.actime = make_unix_date2(inbuf+smb_vwv3); - unix_times.modtime = make_unix_date2(inbuf+smb_vwv5); - - /* - * Patch from Ray Frush <frush@engr.colostate.edu> - * Sometimes times are sent as zero - ignore them. - */ - - if ((unix_times.actime == 0) && (unix_times.modtime == 0)) - { - /* Ignore request */ - DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d ignoring zero request - \ -not setting timestamps of 0\n", - timestring(), fnum,cnum,unix_times.actime,unix_times.modtime)); - return(outsize); - } - else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) - { - /* set modify time = to access time if modify time was 0 */ - unix_times.modtime = unix_times.actime; - } - - /* Set the date on this file */ - if(sys_utime(Files[fnum].name, &unix_times)) - return(ERROR(ERRDOS,ERRnoaccess)); - - DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d actime=%d modtime=%d\n", - timestring(), fnum,cnum,unix_times.actime,unix_times.modtime)); - - return(outsize); -} - - -/**************************************************************************** - reply to a SMBgetattrE -****************************************************************************/ -int reply_getattrE(char *inbuf,char *outbuf) -{ - int cnum,fnum; - struct stat sbuf; - int outsize = 0; - int mode; - - outsize = set_message(outbuf,11,0,True); - - cnum = SVAL(inbuf,smb_tid); - fnum = GETFNUM(inbuf,smb_vwv0); - - CHECK_FNUM(fnum,cnum); - CHECK_ERROR(fnum); - - /* Do an fstat on this file */ - if(fstat(Files[fnum].fd_ptr->fd, &sbuf)) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - - mode = dos_mode(cnum,Files[fnum].name,&sbuf); - - /* Convert the times into dos times. Set create - date to be last modify date as UNIX doesn't save - this */ - put_dos_date2(outbuf,smb_vwv0,sbuf.st_mtime); - put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime); - put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime); - if (mode & aDIR) - { - SIVAL(outbuf,smb_vwv6,0); - SIVAL(outbuf,smb_vwv8,0); - } - else - { - SIVAL(outbuf,smb_vwv6,sbuf.st_size); - SIVAL(outbuf,smb_vwv8,ROUNDUP(sbuf.st_size,1024)); - } - SSVAL(outbuf,smb_vwv10, mode); - - DEBUG(3,("%s reply_getattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum)); - - return(outsize); -} diff --git a/source/smbd/server.c b/source/smbd/server.c deleted file mode 100644 index d387b7375bb..00000000000 --- a/source/smbd/server.c +++ /dev/null @@ -1,5024 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - Main SMB server routines - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "trans2.h" - -pstring servicesf = CONFIGFILE; -extern pstring debugf; -extern pstring sesssetup_user; -extern fstring myworkgroup; - -char *InBuffer = NULL; -char *OutBuffer = NULL; -char *last_inbuf = NULL; - -int am_parent = 1; -int atexit_set = 0; - -/* the last message the was processed */ -int last_message = -1; - -/* a useful macro to debug the last message processed */ -#define LAST_MESSAGE() smb_fn_name(last_message) - -extern pstring scope; -extern int DEBUGLEVEL; -extern int case_default; -extern BOOL case_sensitive; -extern BOOL case_preserve; -extern BOOL use_mangled_map; -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]; - -/* - * 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; - -extern int Protocol; - -/* - * 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; - -/* number of open connections */ -static int num_connections_open = 0; - -/* Oplock ipc UDP socket. */ -int oplock_sock = -1; -uint16 oplock_port = 0; -/* Current number of oplocks we have outstanding. */ -int32 global_oplocks_open = 0; - -BOOL global_oplock_break = False; - -extern fstring remote_machine; - -pstring OriginalDir; - -/* these can be set by some functions to override the error codes */ -int unix_ERR_class=SUCCESS; -int unix_ERR_code=0; - - -extern int extra_time_offset; - -extern pstring myhostname; - -static int find_free_connection(int hash); - -/* for readability... */ -#define IS_DOS_READONLY(test_mode) (((test_mode) & aRONLY) != 0) -#define IS_DOS_DIR(test_mode) (((test_mode) & aDIR) != 0) -#define IS_DOS_ARCHIVE(test_mode) (((test_mode) & aARCH) != 0) -#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 - base permission for files: - everybody gets read bit set - dos readonly is represented in unix by removing everyone's write bit - dos archive is represented in unix by the user's execute bit - dos system is represented in unix by the group's execute bit - dos hidden is represented in unix by the other's execute bit - Then apply create mask, - then add force bits. - base permission for directories: - dos directory is represented in unix by unix's dir bit and the exec bit - Then apply create mask, - then add force bits. -****************************************************************************/ -mode_t unix_mode(int cnum,int dosmode) -{ - mode_t result = (S_IRUSR | S_IRGRP | S_IROTH); - - if ( !IS_DOS_READONLY(dosmode) ) - result |= (S_IWUSR | S_IWGRP | S_IWOTH); - - if (IS_DOS_DIR(dosmode)) { - /* We never make directories read only for the owner as under DOS a user - can always create a file in a read-only directory. */ - result |= (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR); - /* Apply directory mask */ - result &= lp_dir_mode(SNUM(cnum)); - /* Add in force bits */ - result |= lp_force_dir_mode(SNUM(cnum)); - } 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_HIDDEN(cnum) && IS_DOS_HIDDEN(dosmode)) - result |= S_IXOTH; - - /* Apply mode mask */ - result &= lp_create_mode(SNUM(cnum)); - /* Add in force bits */ - result |= lp_force_create_mode(SNUM(cnum)); - } - return(result); -} - - -/**************************************************************************** - change a unix mode to a dos mode -****************************************************************************/ -int dos_mode(int cnum,char *path,struct stat *sbuf) -{ - int result = 0; - extern struct current_user current_user; - - DEBUG(8,("dos_mode: %d %s\n", cnum, path)); - - if (CAN_WRITE(cnum) && !lp_alternate_permissions(SNUM(cnum))) { - if (!((sbuf->st_mode & S_IWOTH) || - Connections[cnum].admin_user || - ((sbuf->st_mode & S_IWUSR) && current_user.uid==sbuf->st_uid) || - ((sbuf->st_mode & S_IWGRP) && - 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; - } - - if (MAP_ARCHIVE(cnum) && ((sbuf->st_mode & S_IXUSR) != 0)) - result |= aARCH; - - if (MAP_SYSTEM(cnum) && ((sbuf->st_mode & S_IXGRP) != 0)) - result |= aSYSTEM; - - if (MAP_HIDDEN(cnum) && ((sbuf->st_mode & S_IXOTH) != 0)) - result |= aHIDDEN; - - if (S_ISDIR(sbuf->st_mode)) - result = aDIR | (result & aRONLY); - -#ifdef S_ISLNK -#if LINKS_READ_ONLY - if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode)) - result |= aRONLY; -#endif -#endif - - /* hide files with a name starting with a . */ - if (lp_hide_dot_files(SNUM(cnum))) - { - char *p = strrchr(path,'/'); - if (p) - p++; - else - p = path; - - if (p[0] == '.' && p[1] != '.' && p[1] != 0) - result |= aHIDDEN; - } - - /* Optimization : Only call is_hidden_path if it's not already - hidden. */ - if (!(result & aHIDDEN) && IS_HIDDEN_PATH(cnum,path)) - { - result |= aHIDDEN; - } - - DEBUG(8,("dos_mode returning ")); - - if (result & aHIDDEN) DEBUG(8, ("h")); - if (result & aRONLY ) DEBUG(8, ("r")); - if (result & aSYSTEM) DEBUG(8, ("s")); - if (result & aDIR ) DEBUG(8, ("d")); - if (result & aARCH ) DEBUG(8, ("a")); - - DEBUG(8,("\n")); - - return(result); -} - - -/******************************************************************* -chmod a file - but preserve some bits -********************************************************************/ -int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st) -{ - struct stat st1; - int mask=0; - int tmp; - int unixmode; - - if (!st) { - st = &st1; - if (sys_stat(fname,st)) return(-1); - } - - if (S_ISDIR(st->st_mode)) dosmode |= aDIR; - - if (dos_mode(cnum,fname,st) == dosmode) return(0); - - unixmode = unix_mode(cnum,dosmode); - - /* preserve the s bits */ - mask |= (S_ISUID | S_ISGID); - - /* preserve the t bit */ -#ifdef S_ISVTX - mask |= S_ISVTX; -#endif - - /* possibly preserve the x bits */ - if (!MAP_ARCHIVE(cnum)) mask |= S_IXUSR; - if (!MAP_SYSTEM(cnum)) mask |= S_IXGRP; - if (!MAP_HIDDEN(cnum)) mask |= S_IXOTH; - - unixmode |= (st->st_mode & mask); - - /* if we previously had any r bits set then leave them alone */ - if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) { - unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH); - unixmode |= tmp; - } - - /* if we previously had any w bits set then leave them alone - if the new mode is not rdonly */ - if (!IS_DOS_READONLY(dosmode) && - (tmp = st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))) { - unixmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH); - unixmode |= tmp; - } - - return(sys_chmod(fname,unixmode)); -} - - -/**************************************************************************** -check if two filenames are equal - -this needs to be careful about whether we are case sensitive -****************************************************************************/ -static BOOL fname_equal(char *name1, char *name2) -{ - int l1 = strlen(name1); - int l2 = strlen(name2); - - /* handle filenames ending in a single dot */ - if (l1-l2 == 1 && name1[l1-1] == '.' && lp_strip_dot()) - { - BOOL ret; - name1[l1-1] = 0; - ret = fname_equal(name1,name2); - name1[l1-1] = '.'; - return(ret); - } - - if (l2-l1 == 1 && name2[l2-1] == '.' && lp_strip_dot()) - { - BOOL ret; - name2[l2-1] = 0; - ret = fname_equal(name1,name2); - name2[l2-1] = '.'; - return(ret); - } - - /* now normal filename handling */ - if (case_sensitive) - return(strcmp(name1,name2) == 0); - - return(strequal(name1,name2)); -} - - -/**************************************************************************** -mangle the 2nd name and check if it is then equal to the first name -****************************************************************************/ -static BOOL mangled_equal(char *name1, char *name2) -{ - pstring tmpname; - - if (is_8_3(name2, True)) - return(False); - - strcpy(tmpname,name2); - mangle_name_83(tmpname); - - return(strequal(name1,tmpname)); -} - - -/**************************************************************************** -scan a directory to find a filename, matching without case sensitivity - -If the name looks like a mangled name then try via the mangling functions -****************************************************************************/ -static BOOL scan_directory(char *path, char *name,int cnum,BOOL docache) -{ - void *cur_dir; - char *dname; - BOOL mangled; - pstring name2; - - mangled = is_mangled(name); - - /* handle null paths */ - if (*path == 0) - path = "."; - - if (docache && (dname = DirCacheCheck(path,name,SNUM(cnum)))) { - strcpy(name, dname); - return(True); - } - - if (mangled) - check_mangled_stack(name); - - /* open the directory */ - if (!(cur_dir = OpenDir(cnum, path, True))) - { - DEBUG(3,("scan dir didn't open dir [%s]\n",path)); - return(False); - } - - /* now scan for matching names */ - while ((dname = ReadDirName(cur_dir))) - { - if (*dname == '.' && - (strequal(dname,".") || strequal(dname,".."))) - continue; - - pstrcpy(name2,dname); - if (!name_map_mangle(name2,False,SNUM(cnum))) continue; - - if ((mangled && mangled_equal(name,name2)) - || fname_equal(name, name2)) /* name2 here was changed to dname - since 1.9.16p2 - not sure of reason (jra) */ - { - /* we've found the file, change it's name and return */ - if (docache) DirCacheAdd(path,name,dname,SNUM(cnum)); - strcpy(name, dname); - CloseDir(cur_dir); - return(True); - } - } - - CloseDir(cur_dir); - return(False); -} - -/**************************************************************************** -This routine is called to convert names from the dos namespace to unix -namespace. It needs to handle any case conversions, mangling, format -changes etc. - -We assume that we have already done a chdir() to the right "root" directory -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. - -The bad_path arg is set to True if the filename walk failed. This is -used to pick the correct error code to return between ENOENT and ENOTDIR -as Windows applications depend on ERRbadpath being returned if a component -of a pathname does not exist. -****************************************************************************/ -BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_path) -{ - struct stat st; - char *start, *end; - pstring dirpath; - int saved_errno; - - *dirpath = 0; - *bad_path = False; - - 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); - - /* 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, True)) - { - 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); - } - - /* stat the name - if it exists then we are all done! */ - if (sys_stat(name,&st) == 0) - return(True); - - saved_errno = errno; - - DEBUG(5,("unix_convert(%s,%d)\n",name,cnum)); - - /* a special case - if we don't have any mangling chars and are case - sensitive then searching won't help */ - if (case_sensitive && !is_mangled(name) && - !lp_strip_dot() && !use_mangled_map && (saved_errno != ENOENT)) - return(False); - - /* now we need to recursively match the name against the real - directory structure */ - - start = name; - while (strncmp(start,"./",2) == 0) - start += 2; - - /* now match each part of the path name separately, trying the names - as is first, then trying to scan the directory for matching names */ - for (;start;start = (end?end+1:(char *)NULL)) - { - /* pinpoint the end of this section of the filename */ - end = strchr(start, '/'); - - /* chop the name at this point */ - 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) - { - /* it exists. it must either be a directory or this must be - the last part of the path for it to be OK */ - if (end && !(st.st_mode & S_IFDIR)) - { - /* an intermediate part of the name isn't a directory */ - DEBUG(5,("Not a dir %s\n",start)); - *end = '/'; - return(False); - } - } - else - { - pstring rest; - - *rest = 0; - - /* remember the rest of the pathname so it can be restored - later */ - if (end) pstrcpy(rest,end+1); - - /* try to find this part of the path in the directory */ - if (strchr(start,'?') || strchr(start,'*') || - !scan_directory(dirpath, start, cnum, end?True:False)) - { - if (end) - { - /* an intermediate part of the name can't be found */ - DEBUG(5,("Intermediate not found %s\n",start)); - *end = '/'; - /* We need to return the fact that the intermediate - name resolution failed. This is used to return an - error of ERRbadpath rather than ERRbadfile. Some - Windows applications depend on the difference between - these two errors. - */ - *bad_path = True; - return(False); - } - - /* just the last part of the name doesn't exist */ - /* we may need to strupper() or strlower() it in case - this conversion is being used for file creation - purposes */ - /* if the filename is of mixed case then don't normalise it */ - if (!case_preserve && - (!strhasupper(start) || !strhaslower(start))) - strnorm(start); - - /* check on the mangled stack to see if we can recover the - base of the filename */ - if (is_mangled(start)) - check_mangled_stack(start); - - DEBUG(5,("New file %s\n",start)); - return(True); - } - - /* restore the rest of the string */ - if (end) - { - strcpy(start+strlen(start)+1,rest); - end = start + strlen(start); - } - } - - /* add to the dirpath that we have resolved so far */ - if (*dirpath) strcat(dirpath,"/"); - strcat(dirpath,start); - - /* restore the / that we wiped out earlier */ - if (end) *end = '/'; - } - - /* the name has been resolved */ - DEBUG(5,("conversion finished %s\n",name)); - return(True); -} - - -/**************************************************************************** -normalise for DOS usage -****************************************************************************/ -static void disk_norm(int *bsize,int *dfree,int *dsize) -{ - /* check if the disk is beyond the max disk size */ - int maxdisksize = lp_maxdisksize(); - if (maxdisksize) { - /* convert to blocks - and don't overflow */ - maxdisksize = ((maxdisksize*1024)/(*bsize))*1024; - if (*dsize > maxdisksize) *dsize = maxdisksize; - if (*dfree > maxdisksize) *dfree = maxdisksize-1; /* the -1 should stop - applications getting - div by 0 errors */ - } - - while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) - { - *dfree /= 2; - *dsize /= 2; - *bsize *= 2; - if (*bsize > WORDMAX ) - { - *bsize = WORDMAX; - if (*dsize > WORDMAX) - *dsize = WORDMAX; - if (*dfree > WORDMAX) - *dfree = WORDMAX; - break; - } - } -} - -/**************************************************************************** - return number of 1K blocks available on a path and total number -****************************************************************************/ -int disk_free(char *path,int *bsize,int *dfree,int *dsize) -{ - char *df_command = lp_dfree_command(); - int dfree_retval; -#ifdef QUOTAS - int dfreeq_retval; - int dfreeq = 0; - int bsizeq = *bsize; - int dsizeq = *dsize; -#endif - -#ifndef NO_STATFS -#ifdef USE_STATVFS - struct statvfs fs; -#else -#ifdef ULTRIX - struct fs_data fs; -#else - struct statfs fs; -#endif -#endif -#endif - - /* possibly use system() to get the result */ - if (df_command && *df_command) - { - int ret; - pstring syscmd; - pstring outfile; - - sprintf(outfile,"%s/dfree.smb.%d",tmpdir(),(int)getpid()); - sprintf(syscmd,"%s %s",df_command,path); - standard_sub_basic(syscmd); - - ret = smbrun(syscmd,outfile,False); - DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret)); - - { - FILE *f = fopen(outfile,"r"); - *dsize = 0; - *dfree = 0; - *bsize = 1024; - if (f) - { - fscanf(f,"%d %d %d",dsize,dfree,bsize); - fclose(f); - } - else - DEBUG(0,("Can't open %s\n",outfile)); - } - - unlink(outfile); - disk_norm(bsize,dfree,dsize); - dfree_retval = ((*bsize)/1024)*(*dfree); -#ifdef QUOTAS - /* Ensure we return the min value between the users quota and - what's free on the disk. Thanks to Albrecht Gebhardt - <albrecht.gebhardt@uni-klu.ac.at> for this fix. - */ - if (disk_quotas(path, &bsizeq, &dfreeq, &dsizeq)) - { - disk_norm(&bsizeq, &dfreeq, &dsizeq); - dfreeq_retval = ((bsizeq)/1024)*(dfreeq); - dfree_retval = ( dfree_retval < dfreeq_retval ) ? - dfree_retval : dfreeq_retval ; - /* maybe dfree and dfreeq are calculated using different bsizes - so convert dfree from bsize into bsizeq */ - /* avoid overflows due to multiplication, so do not: - *dfree = ((*dfree) * (*bsize)) / (bsizeq); - bsize and bsizeq are powers of 2 so its better to - to divide them getting a multiplication or division factor - for dfree. Rene Nieuwenhuizen (07-10-1997) */ - if (*bsize >= bsizeq) - *dfree = *dfree * (*bsize / bsizeq); - else - *dfree = *dfree / (bsizeq / *bsize); - *dfree = ( *dfree < dfreeq ) ? *dfree : dfreeq ; - *bsize = bsizeq; - *dsize = dsizeq; - } -#endif - return(dfree_retval); - } - -#ifdef NO_STATFS - DEBUG(1,("Warning - no statfs function\n")); - return(1); -#else -#ifdef STATFS4 - if (statfs(path,&fs,sizeof(fs),0) != 0) -#else -#ifdef USE_STATVFS - if (statvfs(path, &fs)) -#else -#ifdef STATFS3 - if (statfs(path,&fs,sizeof(fs)) == -1) -#else - if (statfs(path,&fs) == -1) -#endif /* STATFS3 */ -#endif /* USE_STATVFS */ -#endif /* STATFS4 */ - { - DEBUG(3,("dfree call failed code errno=%d\n",errno)); - *bsize = 1024; - *dfree = 1; - *dsize = 1; - return(((*bsize)/1024)*(*dfree)); - } - -#ifdef ULTRIX - *bsize = 1024; - *dfree = fs.fd_req.bfree; - *dsize = fs.fd_req.btot; -#else -#ifdef USE_STATVFS - *bsize = fs.f_frsize; -#else -#ifdef USE_F_FSIZE - /* eg: osf1 has f_fsize = fundamental filesystem block size, - f_bsize = optimal transfer block size (MX: 94-04-19) */ - *bsize = fs.f_fsize; -#else - *bsize = fs.f_bsize; -#endif /* STATFS3 */ -#endif /* USE_STATVFS */ - -#ifdef STATFS4 - *dfree = fs.f_bfree; -#else - *dfree = fs.f_bavail; -#endif /* STATFS4 */ - *dsize = fs.f_blocks; -#endif /* ULTRIX */ - -#if defined(SCO) || defined(ISC) || defined(MIPS) - *bsize = 512; -#endif - -/* handle rediculous bsize values - some OSes are broken */ -if ((*bsize) < 512 || (*bsize)>0xFFFF) *bsize = 1024; - - disk_norm(bsize,dfree,dsize); - - if (*bsize < 256) - *bsize = 512; - if ((*dsize)<1) - { - DEBUG(0,("dfree seems to be broken on your system\n")); - *dsize = 20*1024*1024/(*bsize); - *dfree = MAX(1,*dfree); - } - dfree_retval = ((*bsize)/1024)*(*dfree); -#ifdef QUOTAS - /* Ensure we return the min value between the users quota and - what's free on the disk. Thanks to Albrecht Gebhardt - <albrecht.gebhardt@uni-klu.ac.at> for this fix. - */ - if (disk_quotas(path, &bsizeq, &dfreeq, &dsizeq)) - { - disk_norm(&bsizeq, &dfreeq, &dsizeq); - dfreeq_retval = ((bsizeq)/1024)*(dfreeq); - dfree_retval = ( dfree_retval < dfreeq_retval ) ? - dfree_retval : dfreeq_retval ; - /* maybe dfree and dfreeq are calculated using different bsizes - so convert dfree from bsize into bsizeq */ - /* avoid overflows due to multiplication, so do not: - *dfree = ((*dfree) * (*bsize)) / (bsizeq); - bsize and bsizeq are powers of 2 so its better to - to divide them getting a multiplication or division factor - for dfree. Rene Nieuwenhuizen (07-10-1997) */ - if (*bsize >= bsizeq) - *dfree = *dfree * (*bsize / bsizeq); - else - *dfree = *dfree / (bsizeq / *bsize); - *dfree = ( *dfree < dfreeq ) ? *dfree : dfreeq ; - *bsize = bsizeq; - *dsize = dsizeq; - } -#endif - return(dfree_retval); -#endif -} - - -/**************************************************************************** -wrap it to get filenames right -****************************************************************************/ -int sys_disk_free(char *path,int *bsize,int *dfree,int *dsize) -{ - return(disk_free(dos_to_unix(path,False),bsize,dfree,dsize)); -} - - - -/**************************************************************************** -check a filename - possibly caling reducename - -This is called by every routine before it allows an operation on a filename. -It does any final confirmation necessary to ensure that the filename is -a valid one for the user to access. -****************************************************************************/ -BOOL check_name(char *name,int cnum) -{ - BOOL ret; - - errno = 0; - - if( IS_VETO_PATH(cnum, name)) - { - DEBUG(5,("file path name %s vetoed\n",name)); - return(0); - } - - ret = reduce_name(name,Connections[cnum].connectpath,lp_widelinks(SNUM(cnum))); - - /* Check if we are allowing users to follow symlinks */ - /* Patch from David Clerc <David.Clerc@cui.unige.ch> - University of Geneva */ - -#ifdef S_ISLNK - if (!lp_symlinks(SNUM(cnum))) - { - struct stat statbuf; - if ( (sys_lstat(name,&statbuf) != -1) && - (S_ISLNK(statbuf.st_mode)) ) - { - DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name)); - ret=0; - } - } -#endif - - if (!ret) - DEBUG(5,("check_name on %s failed\n",name)); - - return(ret); -} - -/**************************************************************************** -check a filename - possibly caling reducename -****************************************************************************/ -static void check_for_pipe(char *fname) -{ - /* special case of pipe opens */ - char s[10]; - StrnCpy(s,fname,9); - strlower(s); - if (strstr(s,"pipe/")) - { - DEBUG(3,("Rejecting named pipe open for %s\n",fname)); - unix_ERR_class = ERRSRV; - unix_ERR_code = ERRaccess; - } -} - -/**************************************************************************** -fd support routines - attempt to do a sys_open -****************************************************************************/ -static 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 *. -****************************************************************************/ -static 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. -****************************************************************************/ -static 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. -****************************************************************************/ -static 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. -****************************************************************************/ -static 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 -****************************************************************************/ -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_struct *fsp = &Files[fnum]; - - fsp->open = False; - fsp->fd_ptr = 0; - fsp->granted_oplock = False; - errno = EPERM; - - pstrcpy(fname,fname1); - - /* check permissions */ - if ((flags != O_RDONLY) && !CAN_WRITE(cnum) && !Connections[cnum].printer) - { - DEBUG(3,("Permission denied opening %s\n",fname)); - check_for_pipe(fname); - return; - } - - /* this handles a bug in Win95 - it doesn't say to create the file when it - should */ - if (Connections[cnum].printer) - flags |= O_CREAT; - -/* - if (flags == O_WRONLY) - DEBUG(3,("Bug in client? Set O_WRONLY without O_CREAT\n")); -*/ - -#if UTIME_WORKAROUND - /* XXXX - is this OK?? */ - /* this works around a utime bug but can cause other problems */ - if ((flags & (O_WRONLY|O_RDWR)) && (flags & O_CREAT) && !(flags & O_APPEND)) - sys_unlink(fname); -#endif - - /* - * Ensure we have a valid struct stat so we can search the - * open fd table. - */ - if(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; - } - - /* - * 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 ((fd_ptr->fd >=0) && - Connections[cnum].printer && lp_minprintspace(SNUM(cnum))) { - pstring dname; - int dum1,dum2,dum3; - char *p; - pstrcpy(dname,fname); - p = strrchr(dname,'/'); - if (p) *p = 0; - if (sys_disk_free(dname,&dum1,&dum2,&dum3) < - lp_minprintspace(SNUM(cnum))) { - fd_attempt_close(fd_ptr); - fsp->fd_ptr = 0; - if(fd_ptr->ref_count == 0) - sys_unlink(fname); - errno = ENOSPC; - return; - } - } - - 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 (fd_ptr->fd >= 0) - { - 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; - - fsp->fd_ptr = fd_ptr; - Connections[cnum].num_files_open++; - fsp->mode = sbuf->st_mode; - GetTimeOfDay(&fsp->open_time); - fsp->uid = current_user.id; - fsp->size = 0; - fsp->pos = -1; - fsp->open = True; - fsp->mmap_ptr = NULL; - fsp->mmap_size = 0; - fsp->can_lock = True; - fsp->can_read = ((flags & O_WRONLY)==0); - fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0); - fsp->share_mode = 0; - fsp->print_file = Connections[cnum].printer; - fsp->modified = False; - fsp->granted_oplock = False; - fsp->cnum = cnum; - string_set(&fsp->name,dos_to_unix(fname,False)); - fsp->wbmpx_ptr = NULL; - - /* - * If the printer is marked as postscript output a leading - * file identifier to ensure the file is treated as a raw - * postscript file. - * This has a similar effect as CtrlD=0 in WIN.INI file. - * tim@fsg.com 09/06/94 - */ - if (fsp->print_file && POSTSCRIPT(cnum) && - fsp->can_write) - { - DEBUG(3,("Writing postscript line\n")); - write_file(fnum,"%!\n",3); - } - - DEBUG(2,("%s %s opened file %s read=%s write=%s (numopen=%d fnum=%d)\n", - timestring(),Connections[cnum].user,fname, - BOOLSTR(fsp->can_read),BOOLSTR(fsp->can_write), - Connections[cnum].num_files_open,fnum)); - - } - -#if USE_MMAP - /* mmap it if read-only */ - if (!fsp->can_write) - { - fsp->mmap_size = file_size(fname); - fsp->mmap_ptr = (char *)mmap(NULL,fsp->mmap_size, - PROT_READ,MAP_SHARED,fsp->fd_ptr->fd,0); - - if (fsp->mmap_ptr == (char *)-1 || !fsp->mmap_ptr) - { - DEBUG(3,("Failed to mmap() %s - %s\n",fname,strerror(errno))); - fsp->mmap_ptr = NULL; - } - } -#endif -} - -/******************************************************************* -sync a file -********************************************************************/ -void sync_file(int fnum) -{ -#ifndef NO_FSYNC - fsync(Files[fnum].fd_ptr->fd); -#endif -} - -/**************************************************************************** -run a file if it is a magic script -****************************************************************************/ -static void check_magic(int fnum,int cnum) -{ - if (!*lp_magicscript(SNUM(cnum))) - return; - - DEBUG(5,("checking magic for %s\n",Files[fnum].name)); - - { - char *p; - if (!(p = strrchr(Files[fnum].name,'/'))) - p = Files[fnum].name; - else - p++; - - if (!strequal(lp_magicscript(SNUM(cnum)),p)) - return; - } - - { - int ret; - pstring magic_output; - pstring fname; - pstrcpy(fname,Files[fnum].name); - - if (*lp_magicoutput(SNUM(cnum))) - pstrcpy(magic_output,lp_magicoutput(SNUM(cnum))); - else - sprintf(magic_output,"%s.out",fname); - - chmod(fname,0755); - ret = smbrun(fname,magic_output,False); - DEBUG(3,("Invoking magic command %s gave %d\n",fname,ret)); - unlink(fname); - } -} - - -/**************************************************************************** -close a file - possibly invalidating the read prediction -****************************************************************************/ -void close_file(int fnum) -{ - 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(fs_p->wbmpx_ptr) - { - free((char *)fs_p->wbmpx_ptr); - fs_p->wbmpx_ptr = NULL; - } - -#if USE_MMAP - if(fs_p->mmap_ptr) - { - munmap(fs_p->mmap_ptr,fs_p->mmap_size); - fs_p->mmap_ptr = NULL; - } -#endif - - if (lp_share_modes(SNUM(cnum))) - { - lock_share_entry( cnum, dev, inode, &token); - del_share_mode(token, fnum); - } - - 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 (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,fs_p->name, - Connections[cnum].num_files_open)); -} - -enum {AFAIL,AREAD,AWRITE,AALL}; - -/******************************************************************* -reproduce the share mode access table -********************************************************************/ -static int access_table(int new_deny,int old_deny,int old_mode, - int share_pid,char *fname) -{ - if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL); - - if (new_deny == DENY_DOS || old_deny == DENY_DOS) { - int pid = getpid(); - if (old_deny == new_deny && share_pid == pid) - return(AALL); - - if (old_mode == 0) return(AREAD); - - /* the new smbpub.zip spec says that if the file extension is - .com, .dll, .exe or .sym then allow the open. I will force - it to read-only as this seems sensible although the spec is - a little unclear on this. */ - if ((fname = strrchr(fname,'.'))) { - if (strequal(fname,".com") || - strequal(fname,".dll") || - strequal(fname,".exe") || - strequal(fname,".sym")) - return(AREAD); - } - - return(AFAIL); - } - - switch (new_deny) - { - case DENY_WRITE: - if (old_deny==DENY_WRITE && old_mode==0) return(AREAD); - if (old_deny==DENY_READ && old_mode==0) return(AWRITE); - if (old_deny==DENY_NONE && old_mode==0) return(AALL); - return(AFAIL); - case DENY_READ: - if (old_deny==DENY_WRITE && old_mode==1) return(AREAD); - if (old_deny==DENY_READ && old_mode==1) return(AWRITE); - if (old_deny==DENY_NONE && old_mode==1) return(AALL); - return(AFAIL); - case DENY_NONE: - if (old_deny==DENY_WRITE) return(AREAD); - if (old_deny==DENY_READ) return(AWRITE); - if (old_deny==DENY_NONE) return(AALL); - return(AFAIL); - } - return(AFAIL); -} - -/******************************************************************* -check if the share mode on a file allows it to be deleted or unlinked -return True if sharing doesn't prevent the operation -********************************************************************/ -BOOL check_file_sharing(int cnum,char *fname) -{ - 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(); - uint32 dev, inode; - - if(!lp_share_modes(SNUM(cnum))) - return True; - - if (stat(fname,&sbuf) == -1) return(True); - - dev = (uint32)sbuf.st_dev; - inode = (uint32)sbuf.st_ino; - - lock_share_entry(cnum, dev, inode, &token); - num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares); - - /* - * Check if the share modes will give us access. - */ - - if(num_share_modes != 0) - { - BOOL broke_oplock; - - do - { - - broke_oplock = False; - for(i = 0; i < num_share_modes; i++) - { - min_share_mode_entry *share_entry = &old_shares[i]; - - /* - * Break oplocks before checking share modes. See comment in - * open_file_shared for details. - * Check if someone has an oplock on this file. If so we must - * break it before continuing. - */ - if(share_entry->op_type & BATCH_OPLOCK) - { - - DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \ -dev = %x, inode = %x\n", share_entry->op_type, fname, dev, inode)); - - /* Oplock break.... */ - unlock_share_entry(cnum, dev, inode, token); - if(request_oplock_break(share_entry, dev, inode) == False) - { - free((char *)old_shares); - DEBUG(0,("check_file_sharing: FAILED when breaking oplock (%x) on file %s, \ -dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode)); - return False; - } - lock_share_entry(cnum, dev, inode, &token); - broke_oplock = True; - break; - } - - /* someone else has a share lock on it, check to see - if we can too */ - if ((share_entry->share_mode != DENY_DOS) || (share_entry->pid != pid)) - goto free_and_exit; - - } /* end for */ - - if(broke_oplock) - { - free((char *)old_shares); - num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares); - } - } while(broke_oplock); - } - - /* XXXX exactly what share mode combinations should be allowed for - deleting/renaming? */ - /* 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, dev, inode, token); - if(old_shares != NULL) - free((char *)old_shares); - return(ret); -} - -/**************************************************************************** - C. Hoch 11/22/95 - Helper for open_file_shared. - Truncate a file after checking locking; close file if locked. - **************************************************************************/ -static void truncate_unless_locked(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_ptr->fd,0); - } -} - -/**************************************************************************** -check if we can open a file with a share mode -****************************************************************************/ -int check_share_mode( min_share_mode_entry *share, int deny_mode, char *fname, - BOOL fcbopen, int *flags) -{ - int old_open_mode = share->share_mode &0xF; - int old_deny_mode = (share->share_mode >>4)&7; - - if (old_deny_mode > 4 || old_open_mode > 2) - { - DEBUG(0,("Invalid share mode found (%d,%d,%d) on file %s\n", - deny_mode,old_deny_mode,old_open_mode,fname)); - return False; - } - - { - int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode, - share->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)) - { - DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n", - deny_mode,old_deny_mode,old_open_mode, - share->pid,fname, access_allowed)); - return False; - } - - if (access_allowed == AREAD) - *flags = O_RDONLY; - - if (access_allowed == AWRITE) - *flags = O_WRONLY; - - } - return True; -} - -/**************************************************************************** -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 oplock_request, 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; - share_lock_token token; - uint32 dev = 0; - uint32 inode = 0; - int num_share_modes = 0; - - 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,".+,;=[].")) - { - unix_ERR_class = ERRDOS; - /* OS/2 Workplace shell fix may be main code stream in a later release. */ -#ifdef OS2_WPS_FIX - unix_ERR_code = ERRcannotopen; -#else /* OS2_WPS_FIX */ - unix_ERR_code = ERROR_EAS_NOT_SUPPORTED; -#endif /* OS2_WPS_FIX */ - - return; - } - - if ((ofun & 0x3) == 0 && file_existed) - { - errno = EEXIST; - return; - } - - if (ofun & 0x10) - flags2 |= O_CREAT; - if ((ofun & 0x3) == 2) - flags2 |= O_TRUNC; - - /* note that we ignore the append flag as - append does not mean the same thing under dos and unix */ - - switch (share_mode&0xF) - { - case 1: - flags = O_WRONLY; - break; - case 0xF: - fcbopen = True; - flags = O_RDWR; - break; - case 2: - flags = O_RDWR; - break; - default: - flags = O_RDONLY; - break; - } - - if (flags != O_RDONLY && file_existed && - (!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) - { - DEBUG(2,("Invalid deny mode %d on file %s\n",deny_mode,fname)); - errno = EINVAL; - return; - } - - if (deny_mode == DENY_FCB) deny_mode = DENY_DOS; - - if (lp_share_modes(SNUM(cnum))) - { - int i; - min_share_mode_entry *old_shares = 0; - - if (file_existed) - { - dev = (uint32)sbuf.st_dev; - inode = (uint32)sbuf.st_ino; - lock_share_entry(cnum, dev, inode, &token); - share_locked = True; - num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares); - } - - /* - * Check if the share modes will give us access. - */ - - if(share_locked && (num_share_modes != 0)) - { - BOOL broke_oplock; - - do - { - - broke_oplock = False; - for(i = 0; i < num_share_modes; i++) - { - min_share_mode_entry *share_entry = &old_shares[i]; - - /* - * By observation of NetBench, oplocks are broken *before* share - * modes are checked. This allows a file to be closed by the client - * if the share mode would deny access and the client has an oplock. - * Check if someone has an oplock on this file. If so we must break - * it before continuing. - */ - if(share_entry->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) - { - - DEBUG(5,("open_file_shared: breaking oplock (%x) on file %s, \ -dev = %x, inode = %x\n", share_entry->op_type, fname, dev, inode)); - - /* Oplock break.... */ - unlock_share_entry(cnum, dev, inode, token); - if(request_oplock_break(share_entry, dev, inode) == False) - { - free((char *)old_shares); - DEBUG(0,("open_file_shared: FAILED when breaking oplock (%x) on file %s, \ -dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode)); - errno = EACCES; - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadshare; - return; - } - lock_share_entry(cnum, dev, inode, &token); - broke_oplock = True; - break; - } - - /* someone else has a share lock on it, check to see - if we can too */ - if(check_share_mode(share_entry, deny_mode, fname, fcbopen, &flags) == False) - { - free((char *)old_shares); - unlock_share_entry(cnum, dev, inode, token); - errno = EACCES; - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadshare; - return; - } - - } /* end for */ - - if(broke_oplock) - { - free((char *)old_shares); - num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares); - } - } while(broke_oplock); - } - - 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,file_existed ? &sbuf : 0); - if (!fs_p->open && flags==O_RDWR && errno!=ENOENT && fcbopen) - { - flags = O_RDONLY; - open_file(fnum,cnum,fname,flags,mode,file_existed ? &sbuf : 0 ); - } - - if (fs_p->open) - { - int open_mode=0; - - 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; - } - - switch (flags) - { - case O_RDONLY: - open_mode = 0; - break; - case O_RDWR: - open_mode = 2; - break; - case O_WRONLY: - open_mode = 1; - break; - } - - fs_p->share_mode = (deny_mode<<4) | open_mode; - - if (Access) - (*Access) = open_mode; - - if (action) - { - if (file_existed && !(flags2 & O_TRUNC)) *action = 1; - if (!file_existed) *action = 2; - if (file_existed && (flags2 & O_TRUNC)) *action = 3; - } - /* 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))) - { - uint16 port = 0; - /* JRA. Currently this only services Exlcusive and batch - oplocks (no other opens on this file). This needs to - be extended to level II oplocks (multiple reader - oplocks). */ - - if(oplock_request && (num_share_modes == 0) && lp_oplocks(SNUM(cnum))) - { - fs_p->granted_oplock = True; - global_oplocks_open++; - port = oplock_port; - - DEBUG(5,("open_file_shared: granted oplock (%x) on file %s, \ -dev = %x, inode = %x\n", oplock_request, fname, dev, inode)); - - } - else - { - port = 0; - oplock_request = 0; - } - set_share_mode(token, fnum, port, oplock_request); - } - - if ((flags2&O_TRUNC) && file_existed) - truncate_unless_locked(fnum,cnum,token,&share_locked); - } - - if (share_locked && lp_share_modes(SNUM(cnum))) - unlock_share_entry( cnum, dev, inode, token); -} - -/**************************************************************************** -seek a file. Try to avoid the seek if possible -****************************************************************************/ -int seek_file(int fnum,uint32 pos) -{ - uint32 offset = 0; - if (Files[fnum].print_file && POSTSCRIPT(Files[fnum].cnum)) - offset = 3; - - Files[fnum].pos = (int)(lseek(Files[fnum].fd_ptr->fd,pos+offset,SEEK_SET) - - offset); - return(Files[fnum].pos); -} - -/**************************************************************************** -read from a file -****************************************************************************/ -int read_file(int fnum,char *data,uint32 pos,int n) -{ - int ret=0,readret; - - if (!Files[fnum].can_write) - { - ret = read_predict(Files[fnum].fd_ptr->fd,pos,data,NULL,n); - - data += ret; - n -= ret; - pos += ret; - } - -#if USE_MMAP - if (Files[fnum].mmap_ptr) - { - int num = MIN(n,(int)(Files[fnum].mmap_size-pos)); - if (num > 0) - { - memcpy(data,Files[fnum].mmap_ptr+pos,num); - data += num; - pos += num; - n -= num; - ret += num; - } - } -#endif - - if (n <= 0) - return(ret); - - if (seek_file(fnum,pos) != pos) - { - DEBUG(3,("Failed to seek to %d\n",pos)); - return(ret); - } - - if (n > 0) { - readret = read(Files[fnum].fd_ptr->fd,data,n); - if (readret > 0) ret += readret; - } - - return(ret); -} - - -/**************************************************************************** -write to a file -****************************************************************************/ -int write_file(int fnum,char *data,int n) -{ - if (!Files[fnum].can_write) { - errno = EPERM; - return(0); - } - - if (!Files[fnum].modified) { - struct stat st; - Files[fnum].modified = True; - 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); - } - } - } - - return(write_data(Files[fnum].fd_ptr->fd,data,n)); -} - - -/**************************************************************************** -load parameters specific to a connection/service -****************************************************************************/ -BOOL become_service(int cnum,BOOL do_chdir) -{ - extern char magic_char; - static int last_cnum = -1; - int snum; - - if (!OPEN_CNUM(cnum)) - { - last_cnum = -1; - return(False); - } - - Connections[cnum].lastused = smb_last_time; - - snum = SNUM(cnum); - - if (do_chdir && - ChDir(Connections[cnum].connectpath) != 0 && - ChDir(Connections[cnum].origpath) != 0) - { - DEBUG(0,("%s chdir (%s) failed cnum=%d\n",timestring(), - Connections[cnum].connectpath,cnum)); - return(False); - } - - if (cnum == last_cnum) - return(True); - - last_cnum = cnum; - - case_default = lp_defaultcase(snum); - case_preserve = lp_preservecase(snum); - short_case_preserve = lp_shortpreservecase(snum); - case_mangle = lp_casemangle(snum); - case_sensitive = lp_casesensitive(snum); - magic_char = lp_magicchar(snum); - use_mangled_map = (*lp_mangled_map(snum) ? True:False); - return(True); -} - - -/**************************************************************************** - find a service entry -****************************************************************************/ -int find_service(char *service) -{ - int iService; - - string_sub(service,"\\","/"); - - iService = lp_servicenumber(service); - - /* now handle the special case of a home directory */ - if (iService < 0) - { - char *phome_dir = get_home_dir(service); - DEBUG(3,("checking for home directory %s gave %s\n",service, - phome_dir?phome_dir:"(NULL)")); - if (phome_dir) - { - int iHomeService; - if ((iHomeService = lp_servicenumber(HOMES_NAME)) >= 0) - { - lp_add_home(service,iHomeService,phome_dir); - iService = lp_servicenumber(service); - } - } - } - - /* If we still don't have a service, attempt to add it as a printer. */ - if (iService < 0) - { - int iPrinterService; - - if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) - { - char *pszTemp; - - DEBUG(3,("checking whether %s is a valid printer name...\n", service)); - pszTemp = PRINTCAP; - if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp)) - { - DEBUG(3,("%s is a valid printer name\n", service)); - DEBUG(3,("adding %s as a printer service\n", service)); - lp_add_printer(service,iPrinterService); - iService = lp_servicenumber(service); - if (iService < 0) - DEBUG(0,("failed to add %s as a printer service!\n", service)); - } - else - DEBUG(3,("%s is not a valid printer name\n", service)); - } - } - - /* just possibly it's a default service? */ - if (iService < 0) - { - char *defservice = lp_defaultservice(); - if (defservice && *defservice && !strequal(defservice,service)) { - iService = find_service(defservice); - if (iService >= 0) { - string_sub(service,"_","/"); - iService = lp_add_service(service,iService); - } - } - } - - if (iService >= 0) - if (!VALID_SNUM(iService)) - { - DEBUG(0,("Invalid snum %d for %s\n",iService,service)); - iService = -1; - } - - if (iService < 0) - DEBUG(3,("find_service() failed to find service %s\n", service)); - - return (iService); -} - - -/**************************************************************************** - create an error packet from a cached error. -****************************************************************************/ -int cached_error_packet(char *inbuf,char *outbuf,int fnum,int line) -{ - write_bmpx_struct *wbmpx = Files[fnum].wbmpx_ptr; - - int32 eclass = wbmpx->wr_errclass; - int32 err = wbmpx->wr_error; - - /* We can now delete the auxiliary struct */ - free((char *)wbmpx); - Files[fnum].wbmpx_ptr = NULL; - return error_packet(inbuf,outbuf,eclass,err,line); -} - - -struct -{ - int unixerror; - int smbclass; - int smbcode; -} unix_smb_errmap[] = -{ - {EPERM,ERRDOS,ERRnoaccess}, - {EACCES,ERRDOS,ERRnoaccess}, - {ENOENT,ERRDOS,ERRbadfile}, - {ENOTDIR,ERRDOS,ERRbadpath}, - {EIO,ERRHRD,ERRgeneral}, - {EBADF,ERRSRV,ERRsrverror}, - {EINVAL,ERRSRV,ERRsrverror}, - {EEXIST,ERRDOS,ERRfilexists}, - {ENFILE,ERRDOS,ERRnofids}, - {EMFILE,ERRDOS,ERRnofids}, - {ENOSPC,ERRHRD,ERRdiskfull}, -#ifdef EDQUOT - {EDQUOT,ERRHRD,ERRdiskfull}, -#endif -#ifdef ENOTEMPTY - {ENOTEMPTY,ERRDOS,ERRnoaccess}, -#endif -#ifdef EXDEV - {EXDEV,ERRDOS,ERRdiffdevice}, -#endif - {EROFS,ERRHRD,ERRnowrite}, - {0,0,0} -}; - -/**************************************************************************** - create an error packet from errno -****************************************************************************/ -int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int line) -{ - int eclass=def_class; - int ecode=def_code; - int i=0; - - if (unix_ERR_class != SUCCESS) - { - eclass = unix_ERR_class; - ecode = unix_ERR_code; - unix_ERR_class = SUCCESS; - unix_ERR_code = 0; - } - else - { - while (unix_smb_errmap[i].smbclass != 0) - { - if (unix_smb_errmap[i].unixerror == errno) - { - eclass = unix_smb_errmap[i].smbclass; - ecode = unix_smb_errmap[i].smbcode; - break; - } - i++; - } - } - - return(error_packet(inbuf,outbuf,eclass,ecode,line)); -} - - -/**************************************************************************** - create an error packet. Normally called using the ERROR() macro -****************************************************************************/ -int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line) -{ - int outsize = set_message(outbuf,0,0,True); - int cmd; - cmd = CVAL(inbuf,smb_com); - - CVAL(outbuf,smb_rcls) = error_class; - SSVAL(outbuf,smb_err,error_code); - - DEBUG(3,("%s error packet at line %d cmd=%d (%s) eclass=%d ecode=%d\n", - timestring(), - line, - (int)CVAL(inbuf,smb_com), - smb_fn_name(CVAL(inbuf,smb_com)), - error_class, - error_code)); - - if (errno != 0) - DEBUG(3,("error string = %s\n",strerror(errno))); - - return(outsize); -} - - -#ifndef SIGCLD_IGNORE -/**************************************************************************** -this prevents zombie child processes -****************************************************************************/ -static int sig_cld() -{ - static int depth = 0; - if (depth != 0) - { - DEBUG(0,("ERROR: Recursion in sig_cld? Perhaps you need `#define USE_WAITPID'?\n")); - depth=0; - return(0); - } - depth++; - - BlockSignals(True,SIGCLD); - DEBUG(5,("got SIGCLD\n")); - -#ifdef USE_WAITPID - while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0); -#endif - - /* Stop zombies */ - /* Stevens, Adv. Unix Prog. says that on system V you must call - wait before reinstalling the signal handler, because the kernel - calls the handler from within the signal-call when there is a - child that has exited. This would lead to an infinite recursion - if done vice versa. */ - -#ifndef DONT_REINSTALL_SIG -#ifdef SIGCLD_IGNORE - signal(SIGCLD, SIG_IGN); -#else - signal(SIGCLD, SIGNAL_CAST sig_cld); -#endif -#endif - -#ifndef USE_WAITPID - while (wait3(WAIT3_CAST1 NULL, WNOHANG, WAIT3_CAST2 NULL) > 0); -#endif - depth--; - BlockSignals(False,SIGCLD); - return 0; -} -#endif - -/**************************************************************************** - this is called when the client exits abruptly - **************************************************************************/ -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); -} - -/**************************************************************************** - open the socket communication -****************************************************************************/ -static BOOL open_sockets(BOOL is_daemon,int port) -{ - extern int Client; - - if (is_daemon) - { - int s; - struct sockaddr addr; - int in_addrlen = sizeof(addr); - - /* Stop zombies */ -#ifdef SIGCLD_IGNORE - signal(SIGCLD, SIG_IGN); -#else - signal(SIGCLD, SIGNAL_CAST sig_cld); -#endif - - /* open an incoming socket */ - s = open_socket_in(SOCK_STREAM, port, 0,interpret_addr(lp_socket_address())); - if (s == -1) - return(False); - - /* ready to listen */ - if (listen(s, 5) == -1) - { - DEBUG(0,("listen: %s\n",strerror(errno))); - close(s); - return False; - } - - if(atexit_set == 0) - atexit(killkids); - - /* now accept incoming connections - forking a new process - for each incoming connection */ - DEBUG(2,("waiting for a connection\n")); - while (1) - { - Client = accept(s,&addr,&in_addrlen); - - if (Client == -1 && errno == EINTR) - continue; - - if (Client == -1) - { - DEBUG(0,("accept: %s\n",strerror(errno))); - continue; - } - -#ifdef NO_FORK_DEBUG -#ifndef NO_SIGNAL_TEST - signal(SIGPIPE, SIGNAL_CAST sig_pipe); - signal(SIGCLD, SIGNAL_CAST SIG_DFL); -#endif - return True; -#else - if (Client != -1 && fork()==0) - { - /* Child code ... */ -#ifndef NO_SIGNAL_TEST - signal(SIGPIPE, SIGNAL_CAST sig_pipe); - signal(SIGCLD, SIGNAL_CAST SIG_DFL); -#endif - /* close the listening socket */ - close(s); - - /* close our standard file descriptors */ - close_low_fds(); - am_parent = 0; - - set_socket_options(Client,"SO_KEEPALIVE"); - set_socket_options(Client,user_socket_options); - - /* Reset global variables in util.c so that - client substitutions will be done correctly - in the process. - */ - reset_globals_after_fork(); - return True; - } - close(Client); /* The parent doesn't need this socket */ -#endif - } - } - else - { - /* We will abort gracefully when the client or remote system - goes away */ -#ifndef NO_SIGNAL_TEST - signal(SIGPIPE, SIGNAL_CAST sig_pipe); -#endif - Client = dup(0); - - /* close our standard file descriptors */ - close_low_fds(); - - set_socket_options(Client,"SO_KEEPALIVE"); - set_socket_options(Client,user_socket_options); - } - - return True; -} - -/**************************************************************************** - process an smb from the client - split out from the process() code so - it can be used by the oplock break code. -****************************************************************************/ - -static void process_smb(char *inbuf, char *outbuf) -{ - extern int Client; - static int trans_num; - int msg_type = CVAL(inbuf,0); - int32 len = smb_len(inbuf); - int nread = len + 4; - - if (trans_num == 0) { - /* on the first packet, check the global hosts allow/ hosts - deny parameters before doing any parsing of the packet - passed to us by the client. This prevents attacks on our - parsing code from hosts not in the hosts allow list */ - if (!check_access(-1)) { - /* send a negative session response "not listining on calling - name" */ - static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81}; - DEBUG(1,("%s Connection denied from %s\n", - timestring(),client_addr())); - send_smb(Client,(char *)buf); - exit_server("connection denied"); - } - } - - DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len)); - DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread)); - -#ifdef WITH_VTP - if(trans_num == 1 && VT_Check(inbuf)) - { - VT_Process(); - return; - } -#endif - - if (msg_type == 0) - show_msg(inbuf); - - nread = construct_reply(inbuf,outbuf,nread,max_send); - - if(nread > 0) - { - if (CVAL(outbuf,0) == 0) - show_msg(outbuf); - - if (nread != smb_len(outbuf) + 4) - { - DEBUG(0,("ERROR: Invalid message response size! %d %d\n", - nread, smb_len(outbuf))); - } - else - send_smb(Client,outbuf); - } - trans_num++; -} - -/**************************************************************************** - open the oplock IPC socket communication -****************************************************************************/ -static BOOL open_oplock_ipc() -{ - struct sockaddr_in sock_name; - int len = sizeof(sock_name); - - DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n")); - - /* Open a lookback UDP socket on a random port. */ - oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0, htonl(INADDR_LOOPBACK)); - if (oplock_sock == -1) - { - DEBUG(0,("open_oplock_ipc: Failed to get local UDP socket for \ -address %x. Error was %s\n", htonl(INADDR_LOOPBACK), strerror(errno))); - oplock_port = 0; - return(False); - } - - /* Find out the transient UDP port we have been allocated. */ - if(getsockname(oplock_sock, (struct sockaddr *)&sock_name, &len)<0) - { - DEBUG(0,("open_oplock_ipc: Failed to get local UDP port. Error was %s\n", - strerror(errno))); - close(oplock_sock); - oplock_sock = -1; - oplock_port = 0; - return False; - } - oplock_port = ntohs(sock_name.sin_port); - - DEBUG(3,("open_oplock ipc: pid = %d, oplock_port = %u\n", - getpid(), oplock_port)); - - return True; -} - -/**************************************************************************** - process an oplock break message. -****************************************************************************/ -static BOOL process_local_message(int sock, char *buffer, int buf_size) -{ - int32 msg_len; - int16 from_port; - char *msg_start; - - msg_len = IVAL(buffer,UDP_CMD_LEN_OFFSET); - from_port = SVAL(buffer,UDP_CMD_PORT_OFFSET); - - msg_start = &buffer[UDP_CMD_HEADER_LEN]; - - DEBUG(5,("process_local_message: Got a message of length %d from port (%d)\n", - msg_len, from_port)); - - /* Switch on message command - currently OPLOCK_BREAK_CMD is the - only valid request. */ - - switch(SVAL(msg_start,UDP_MESSAGE_CMD_OFFSET)) - { - case OPLOCK_BREAK_CMD: - /* Ensure that the msg length is correct. */ - if(msg_len != OPLOCK_BREAK_MSG_LEN) - { - DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, \ -should be %d).\n", msg_len, OPLOCK_BREAK_MSG_LEN)); - return False; - } - { - uint32 remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET); - uint32 dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET); - uint32 inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET); - struct timeval tval; - struct sockaddr_in toaddr; - - tval.tv_sec = IVAL(msg_start, OPLOCK_BREAK_SEC_OFFSET); - tval.tv_usec = IVAL(msg_start, OPLOCK_BREAK_USEC_OFFSET); - - DEBUG(5,("process_local_message: oplock break request from \ -pid %d, port %d, dev = %x, inode = %x\n", remotepid, from_port, dev, inode)); - - /* - * If we have no record of any currently open oplocks, - * it's not an error, as a close command may have - * just been issued on the file that was oplocked. - * Just return success in this case. - */ - - if(global_oplocks_open != 0) - { - if(oplock_break(dev, inode, &tval) == False) - { - DEBUG(0,("process_local_message: oplock break failed - \ -not returning udp message.\n")); - return False; - } - } - else - { - DEBUG(3,("process_local_message: oplock break requested with no outstanding \ -oplocks. Returning success.\n")); - } - - /* Send the message back after OR'ing in the 'REPLY' bit. */ - SSVAL(msg_start,UDP_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD | CMD_REPLY); - - bzero((char *)&toaddr,sizeof(toaddr)); - toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - toaddr.sin_port = htons(from_port); - toaddr.sin_family = AF_INET; - - if(sendto( sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0, - (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0) - { - DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n", - remotepid, strerror(errno))); - return False; - } - - DEBUG(5,("process_local_message: oplock break reply sent to \ -pid %d, port %d, for file dev = %x, inode = %x\n", remotepid, - from_port, dev, inode)); - - } - break; - /* - * Keep this as a debug case - eventually we can remove it. - */ - case 0x8001: - DEBUG(0,("process_local_message: Received unsolicited break \ -reply - dumping info.\n")); - - if(msg_len != OPLOCK_BREAK_MSG_LEN) - { - DEBUG(0,("process_local_message: ubr: incorrect length for reply \ -(was %d, should be %d).\n", msg_len, OPLOCK_BREAK_MSG_LEN)); - return False; - } - - { - uint32 remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET); - uint32 dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET); - uint32 inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET); - - DEBUG(0,("process_local_message: unsolicited oplock break reply from \ -pid %d, port %d, dev = %x, inode = %x\n", remotepid, from_port, dev, inode)); - - } - return False; - - default: - DEBUG(0,("process_local_message: unknown UDP message command code (%x) - ignoring.\n", - (unsigned int)SVAL(msg_start,0))); - return False; - } - return True; -} - -/**************************************************************************** - Process an oplock break directly. -****************************************************************************/ -BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval) -{ - extern int Client; - static char *inbuf = NULL; - static char *outbuf = NULL; - files_struct *fsp = NULL; - int fnum; - time_t start_time; - BOOL shutdown_server = False; - - DEBUG(5,("oplock_break: called for dev = %x, inode = %x. Current \ -global_oplocks_open = %d\n", dev, inode, global_oplocks_open)); - - if(inbuf == NULL) - { - inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); - if(inbuf == NULL) { - DEBUG(0,("oplock_break: malloc fail for input buffer.\n")); - return False; - } - outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); - if(outbuf == NULL) { - DEBUG(0,("oplock_break: malloc fail for output buffer.\n")); - free(inbuf); - inbuf = NULL; - return False; - } - } - - /* We need to search the file open table for the - entry containing this dev and inode, and ensure - we have an oplock on it. */ - for( fnum = 0; fnum < MAX_OPEN_FILES; fnum++) - { - if(OPEN_FNUM(fnum)) - { - fsp = &Files[fnum]; - if((fsp->fd_ptr->dev == dev) && (fsp->fd_ptr->inode == inode) && - (fsp->open_time.tv_sec == tval->tv_sec) && - (fsp->open_time.tv_usec == tval->tv_usec)) - break; - } - } - - if(fsp == NULL) - { - /* The file could have been closed in the meantime - return success. */ - DEBUG(3,("oplock_break: cannot find open file with dev = %x, inode = %x (fnum = %d) \ -allowing break to succeed.\n", dev, inode, fnum)); - return True; - } - - /* Ensure we have an oplock on the file */ - - /* There is a potential race condition in that an oplock could - have been broken due to another udp request, and yet there are - still oplock break messages being sent in the udp message - queue for this file. So return true if we don't have an oplock, - as we may have just freed it. - */ - - if(!fsp->granted_oplock) - { - DEBUG(3,("oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock. \ -Allowing break to succeed regardless.\n", fsp->name, fnum, dev, inode)); - return True; - } - - /* Now comes the horrid part. We must send an oplock break to the client, - and then process incoming messages until we get a close or oplock release. - */ - - /* Prepare the SMBlockingX message. */ - bzero(outbuf,smb_size); - set_message(outbuf,8,0,True); - - SCVAL(outbuf,smb_com,SMBlockingX); - SSVAL(outbuf,smb_tid,fsp->cnum); - SSVAL(outbuf,smb_pid,0xFFFF); - SSVAL(outbuf,smb_uid,0); - SSVAL(outbuf,smb_mid,0xFFFF); - SCVAL(outbuf,smb_vwv0,0xFF); - SSVAL(outbuf,smb_vwv2,fnum); - SCVAL(outbuf,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE); - /* Change this when we have level II oplocks. */ - SCVAL(outbuf,smb_vwv3+1,OPLOCKLEVEL_NONE); - - send_smb(Client, outbuf); - - global_oplock_break = True; - - /* Process incoming messages. */ - - /* JRA - If we don't get a break from the client in OPLOCK_BREAK_TIMEOUT - seconds we should just die.... */ - - start_time = time(NULL); - - while(OPEN_FNUM(fnum) && fsp->granted_oplock) - { - if(receive_smb(Client,inbuf,OPLOCK_BREAK_TIMEOUT * 1000) == False) - { - /* - * Die if we got an error. - */ - - if (smb_read_error == READ_EOF) - DEBUG(0,("oplock_break: end of file from client\n")); - - if (smb_read_error == READ_ERROR) - DEBUG(0,("oplock_break: receive_smb error (%s)\n", - strerror(errno))); - - if (smb_read_error == READ_TIMEOUT) - DEBUG(0,("oplock_break: receive_smb timed out after %d seconds.\n", - OPLOCK_BREAK_TIMEOUT)); - - DEBUG(0,("oplock_break failed for file %s (fnum = %d, dev = %x, \ -inode = %x).\n", fsp->name, fnum, dev, inode)); - shutdown_server = True; - break; - } - process_smb(inbuf, outbuf); - - /* We only need this in case a readraw crossed on the wire. */ - if(global_oplock_break) - global_oplock_break = False; - - /* - * Die if we go over the time limit. - */ - - if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT) - { - DEBUG(0,("oplock_break: no break received from client within \ -%d seconds.\n", OPLOCK_BREAK_TIMEOUT)); - DEBUG(0,("oplock_break failed for file %s (fnum = %d, dev = %x, \ -inode = %x).\n", fsp->name, fnum, dev, inode)); - shutdown_server = True; - break; - } - } - - /* - * If the client did not respond we must die. - */ - - if(shutdown_server) - { - DEBUG(0,("oplock_break: client failure in break - shutting down this smbd.\n")); - close_sockets(); - close(oplock_sock); - exit_server("oplock break failure"); - } - - if(OPEN_FNUM(fnum)) - { - /* The lockingX reply will have removed the oplock flag - from the sharemode. */ - /* Paranoia.... */ - fsp->granted_oplock = False; - } - - global_oplocks_open--; - - /* Santity check - remove this later. JRA */ - if(global_oplocks_open < 0) - { - DEBUG(0,("oplock_break: global_oplocks_open < 0 (%d). PANIC ERROR\n", - global_oplocks_open)); - exit_server("oplock_break: global_oplocks_open < 0"); - } - - DEBUG(5,("oplock_break: returning success for fnum = %d, dev = %x, inode = %x. Current \ -global_oplocks_open = %d\n", fnum, dev, inode, global_oplocks_open)); - - return True; -} - -/**************************************************************************** -Send an oplock break message to another smbd process. If the oplock is held -by the local smbd then call the oplock break function directly. -****************************************************************************/ - -BOOL request_oplock_break(min_share_mode_entry *share_entry, - uint32 dev, uint32 inode) -{ - char op_break_msg[OPLOCK_BREAK_MSG_LEN]; - struct sockaddr_in addr_out; - int pid = getpid(); - - if(pid == share_entry->pid) - { - /* We are breaking our own oplock, make sure it's us. */ - if(share_entry->op_port != oplock_port) - { - DEBUG(0,("request_oplock_break: corrupt share mode entry - pid = %d, port = %d \ -should be %d\n", pid, share_entry->op_port, oplock_port)); - return False; - } - - DEBUG(5,("request_oplock_break: breaking our own oplock\n")); - - /* Call oplock break direct. */ - return oplock_break(dev, inode, &share_entry->time); - } - - /* We need to send a OPLOCK_BREAK_CMD message to the - port in the share mode entry. */ - - SSVAL(op_break_msg,UDP_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD); - SIVAL(op_break_msg,OPLOCK_BREAK_PID_OFFSET,pid); - SIVAL(op_break_msg,OPLOCK_BREAK_DEV_OFFSET,dev); - SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET,inode); - SIVAL(op_break_msg,OPLOCK_BREAK_SEC_OFFSET,(uint32)share_entry->time.tv_sec); - SIVAL(op_break_msg,OPLOCK_BREAK_USEC_OFFSET,(uint32)share_entry->time.tv_usec); - - /* set the address and port */ - bzero((char *)&addr_out,sizeof(addr_out)); - addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr_out.sin_port = htons( share_entry->op_port ); - addr_out.sin_family = AF_INET; - - DEBUG(3,("request_oplock_break: sending a oplock break message to pid %d on port %d \ -for dev = %x, inode = %x\n", share_entry->pid, share_entry->op_port, dev, inode)); - - if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0, - (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0) - { - DEBUG(0,("request_oplock_break: failed when sending a oplock break message \ -to pid %d on port %d for dev = %x, inode = %x. Error was %s\n", - share_entry->pid, share_entry->op_port, dev, inode, - strerror(errno))); - return False; - } - - /* - * Now we must await the oplock broken message coming back - * from the target smbd process. Timeout if it fails to - * return in OPLOCK_BREAK_TIMEOUT seconds. - * While we get messages that aren't ours, loop. - */ - - while(1) - { - char op_break_reply[UDP_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN]; - int32 reply_msg_len; - int16 reply_from_port; - char *reply_msg_start; - - if(receive_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply), - OPLOCK_BREAK_TIMEOUT * 1000) == False) - { - if(smb_read_error == READ_TIMEOUT) - DEBUG(0,("request_oplock_break: no response received to oplock break request to \ -pid %d on port %d for dev = %x, inode = %x\n", share_entry->pid, - share_entry->op_port, dev, inode)); - else - DEBUG(0,("request_oplock_break: error in response received to oplock break request to \ -pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", share_entry->pid, - share_entry->op_port, dev, inode, strerror(errno))); - return False; - } - - /* - * If the response we got was not an answer to our message, but - * was a completely different request, push it onto the pending - * udp message stack so that we can deal with it in the main loop. - * It may be another oplock break request to us. - */ - - /* - * Local note from JRA. There exists the possibility of a denial - * of service attack here by allowing non-root processes running - * on a local machine sending many of these pending messages to - * a smbd port. Currently I'm not sure how to restrict the messages - * I will queue (although I could add a limit to the queue) to - * those received by root processes only. There should be a - * way to make this bulletproof.... - */ - - reply_msg_len = IVAL(op_break_reply,UDP_CMD_LEN_OFFSET); - reply_from_port = SVAL(op_break_reply,UDP_CMD_PORT_OFFSET); - - reply_msg_start = &op_break_reply[UDP_CMD_HEADER_LEN]; - - if(reply_msg_len != OPLOCK_BREAK_MSG_LEN) - { - /* Ignore it. */ - DEBUG(0,("request_oplock_break: invalid message length received. Ignoring\n")); - continue; - } - - if(((SVAL(reply_msg_start,UDP_MESSAGE_CMD_OFFSET) & CMD_REPLY) == 0) || - (reply_from_port != share_entry->op_port) || - (memcmp(&reply_msg_start[OPLOCK_BREAK_PID_OFFSET], - &op_break_msg[OPLOCK_BREAK_PID_OFFSET], - OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) != 0)) - { - DEBUG(3,("request_oplock_break: received other message whilst awaiting \ -oplock break response from pid %d on port %d for dev = %x, inode = %x.\n", - share_entry->pid, share_entry->op_port, dev, inode)); - if(push_local_message(op_break_reply, sizeof(op_break_reply)) == False) - return False; - continue; - } - - break; - } - - DEBUG(3,("request_oplock_break: broke oplock.\n")); - - return True; -} - -/**************************************************************************** -check if a snum is in use -****************************************************************************/ -BOOL snum_used(int snum) -{ - int i; - for (i=0;i<MAX_CONNECTIONS;i++) - if (OPEN_CNUM(i) && (SNUM(i) == snum)) - return(True); - return(False); -} - -/**************************************************************************** - reload the services file - **************************************************************************/ -BOOL reload_services(BOOL test) -{ - BOOL ret; - - if (lp_loaded()) - { - pstring fname; - pstrcpy(fname,lp_configfile()); - if (file_exist(fname,NULL) && !strcsequal(fname,servicesf)) - { - pstrcpy(servicesf,fname); - test = False; - } - } - - reopen_logs(); - - if (test && !lp_file_list_changed()) - return(True); - - lp_killunused(snum_used); - - ret = lp_load(servicesf,False); - - /* perhaps the config filename is now set */ - if (!test) - reload_services(True); - - reopen_logs(); - - load_interfaces(); - - { - extern int Client; - if (Client != -1) { - set_socket_options(Client,"SO_KEEPALIVE"); - set_socket_options(Client,user_socket_options); - } - } - - create_mangled_stack(lp_mangledstack()); - - /* this forces service parameters to be flushed */ - become_service(-1,True); - - return(ret); -} - - - -/**************************************************************************** -this prevents zombie child processes -****************************************************************************/ -static int sig_hup() -{ - BlockSignals(True,SIGHUP); - DEBUG(0,("Got SIGHUP\n")); - reload_services(False); -#ifndef DONT_REINSTALL_SIG - signal(SIGHUP,SIGNAL_CAST sig_hup); -#endif - BlockSignals(False,SIGHUP); - return(0); -} - -/**************************************************************************** -Setup the groups a user belongs to. -****************************************************************************/ -int setup_groups(char *user, int uid, int gid, int *p_ngroups, - int **p_igroups, gid_t **p_groups) -{ - if (-1 == initgroups(user,gid)) - { - if (getuid() == 0) - { - DEBUG(0,("Unable to initgroups!\n")); - if (gid < 0 || gid > 16000 || uid < 0 || uid > 16000) - DEBUG(0,("This is probably a problem with the account %s\n",user)); - } - } - else - { - int i,ngroups; - int *igroups; - gid_t grp = 0; - ngroups = getgroups(0,&grp); - if (ngroups <= 0) - ngroups = 32; - igroups = (int *)malloc(sizeof(int)*ngroups); - for (i=0;i<ngroups;i++) - igroups[i] = 0x42424242; - ngroups = getgroups(ngroups,(gid_t *)igroups); - - if (igroups[0] == 0x42424242) - ngroups = 0; - - *p_ngroups = ngroups; - - /* The following bit of code is very strange. It is due to the - fact that some OSes use int* and some use gid_t* for - getgroups, and some (like SunOS) use both, one in prototypes, - and one in man pages and the actual code. Thus we detect it - dynamically using some very ugly code */ - if (ngroups > 0) - { - /* does getgroups return ints or gid_t ?? */ - static BOOL groups_use_ints = True; - - if (groups_use_ints && - ngroups == 1 && - SVAL(igroups,2) == 0x4242) - groups_use_ints = False; - - for (i=0;groups_use_ints && i<ngroups;i++) - if (igroups[i] == 0x42424242) - groups_use_ints = False; - - if (groups_use_ints) - { - *p_igroups = igroups; - *p_groups = (gid_t *)igroups; - } - else - { - gid_t *groups = (gid_t *)igroups; - igroups = (int *)malloc(sizeof(int)*ngroups); - for (i=0;i<ngroups;i++) - igroups[i] = groups[i]; - *p_igroups = igroups; - *p_groups = (gid_t *)groups; - } - } - DEBUG(3,("%s is in %d groups\n",user,ngroups)); - for (i=0;i<ngroups;i++) - DEBUG(3,("%d ",igroups[i])); - DEBUG(3,("\n")); - } - return 0; -} - -/**************************************************************************** - make a connection to a service -****************************************************************************/ -int make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid) -{ - int cnum; - int snum; - struct passwd *pass = NULL; - connection_struct *pcon; - BOOL guest = False; - BOOL force = False; - static BOOL first_connection = True; - - strlower(service); - - snum = find_service(service); - if (snum < 0) - { - if (strequal(service,"IPC$")) - { - DEBUG(3,("%s refusing IPC connection\n",timestring())); - return(-3); - } - - DEBUG(0,("%s couldn't find service %s\n",timestring(),service)); - return(-2); - } - - if (strequal(service,HOMES_NAME)) - { - if (*user && Get_Pwnam(user,True)) - return(make_connection(user,user,password,pwlen,dev,vuid)); - - if (validated_username(vuid)) - { - strcpy(user,validated_username(vuid)); - return(make_connection(user,user,password,pwlen,dev,vuid)); - } - } - - if (!lp_snum_ok(snum) || !check_access(snum)) { - return(-4); - } - - /* you can only connect to the IPC$ service as an ipc device */ - if (strequal(service,"IPC$")) - strcpy(dev,"IPC"); - - if (*dev == '?' || !*dev) - { - if (lp_print_ok(snum)) - strcpy(dev,"LPT1:"); - else - strcpy(dev,"A:"); - } - - /* if the request is as a printer and you can't print then refuse */ - strupper(dev); - if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) { - DEBUG(1,("Attempt to connect to non-printer as a printer\n")); - return(-6); - } - - /* lowercase the user name */ - strlower(user); - - /* add it as a possible user name */ - add_session_user(service); - - /* shall we let them in? */ - if (!authorise_login(snum,user,password,pwlen,&guest,&force,vuid)) - { - DEBUG(2,("%s invalid username/password for %s\n",timestring(),service)); - return(-1); - } - - cnum = find_free_connection(str_checksum(service) + str_checksum(user)); - if (cnum < 0) - { - DEBUG(0,("%s couldn't find free connection\n",timestring())); - return(-1); - } - - pcon = &Connections[cnum]; - bzero((char *)pcon,sizeof(*pcon)); - - /* find out some info about the user */ - pass = Get_Pwnam(user,True); - - if (pass == NULL) - { - DEBUG(0,("%s couldn't find account %s\n",timestring(),user)); - return(-7); - } - - pcon->read_only = lp_readonly(snum); - - { - pstring list; - StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1); - string_sub(list,"%S",service); - - if (user_in_list(user,list)) - pcon->read_only = True; - - StrnCpy(list,lp_writelist(snum),sizeof(pstring)-1); - string_sub(list,"%S",service); - - if (user_in_list(user,list)) - pcon->read_only = False; - } - - /* admin user check */ - - /* JRA - original code denied admin user if the share was - marked read_only. Changed as I don't think this is needed, - but old code left in case there is a problem here. - */ - if (user_in_list(user,lp_admin_users(snum)) -#if 0 - && !pcon->read_only) -#else - ) -#endif - { - pcon->admin_user = True; - DEBUG(0,("%s logged in as admin user (root privileges)\n",user)); - } - else - 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; - pcon->lastused = time(NULL); - pcon->service = snum; - pcon->used = True; - pcon->printer = (strncmp(dev,"LPT",3) == 0); - pcon->ipc = (strncmp(dev,"IPC",3) == 0); - pcon->dirptr = NULL; - pcon->veto_list = NULL; - pcon->hide_list = NULL; - string_set(&pcon->dirpath,""); - string_set(&pcon->user,user); - -#if HAVE_GETGRNAM - if (*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",gname)); - } - else - DEBUG(1,("Couldn't find group %s\n",gname)); - } -#endif - - if (*lp_force_user(snum)) - { - struct passwd *pass2; - fstring fuser; - fstrcpy(fuser,lp_force_user(snum)); - pass2 = (struct passwd *)Get_Pwnam(fuser,True); - if (pass2) - { - pcon->uid = pass2->pw_uid; - string_set(&pcon->user,fuser); - fstrcpy(user,fuser); - pcon->force_user = True; - DEBUG(3,("Forced user %s\n",fuser)); - } - else - DEBUG(1,("Couldn't find user %s\n",fuser)); - } - - { - pstring s; - pstrcpy(s,lp_pathname(snum)); - standard_sub(cnum,s); - string_set(&pcon->connectpath,s); - DEBUG(3,("Connect path is %s\n",s)); - } - - /* groups stuff added by ih */ - pcon->ngroups = 0; - pcon->groups = NULL; - - if (!IS_IPC(cnum)) - { - /* Find all the groups this uid is in and store them. Used by become_user() */ - setup_groups(pcon->user,pcon->uid,pcon->gid,&pcon->ngroups,&pcon->igroups,&pcon->groups); - - /* check number of connections */ - if (!claim_connection(cnum, - lp_servicename(SNUM(cnum)), - lp_max_connections(SNUM(cnum)),False)) - { - DEBUG(1,("too many connections - rejected\n")); - return(-8); - } - - if (lp_status(SNUM(cnum))) - claim_connection(cnum,"STATUS.",MAXSTATUS,first_connection); - - first_connection = False; - } /* IS_IPC */ - - pcon->open = True; - - /* execute any "root preexec = " line */ - if (*lp_rootpreexec(SNUM(cnum))) - { - pstring cmd; - pstrcpy(cmd,lp_rootpreexec(SNUM(cnum))); - standard_sub(cnum,cmd); - DEBUG(5,("cmd=%s\n",cmd)); - smbrun(cmd,NULL,False); - } - - if (!become_user(cnum,pcon->vuid)) - { - DEBUG(0,("Can't become connected user!\n")); - pcon->open = False; - if (!IS_IPC(cnum)) { - yield_connection(cnum, - lp_servicename(SNUM(cnum)), - lp_max_connections(SNUM(cnum))); - if (lp_status(SNUM(cnum))) yield_connection(cnum,"STATUS.",MAXSTATUS); - } - return(-1); - } - - if (ChDir(pcon->connectpath) != 0) - { - DEBUG(0,("Can't change directory to %s (%s)\n", - pcon->connectpath,strerror(errno))); - pcon->open = False; - unbecome_user(); - if (!IS_IPC(cnum)) { - yield_connection(cnum, - lp_servicename(SNUM(cnum)), - lp_max_connections(SNUM(cnum))); - if (lp_status(SNUM(cnum))) yield_connection(cnum,"STATUS.",MAXSTATUS); - } - return(-5); - } - - string_set(&pcon->origpath,pcon->connectpath); - -#if SOFTLINK_OPTIMISATION - /* resolve any soft links early */ - { - pstring s; - pstrcpy(s,pcon->connectpath); - GetWd(s); - string_set(&pcon->connectpath,s); - ChDir(pcon->connectpath); - } -#endif - - num_connections_open++; - add_session_user(user); - - /* execute any "preexec = " line */ - if (*lp_preexec(SNUM(cnum))) - { - pstring cmd; - pstrcpy(cmd,lp_preexec(SNUM(cnum))); - standard_sub(cnum,cmd); - smbrun(cmd,NULL,False); - } - - /* we've finished with the sensitive stuff */ - unbecome_user(); - - /* Add veto/hide lists */ - if (!IS_IPC(cnum) && !IS_PRINT(cnum)) - { - set_namearray( &pcon->veto_list, lp_veto_files(SNUM(cnum))); - set_namearray( &pcon->hide_list, lp_hide_files(SNUM(cnum))); - } - - { - DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) connect to service %s as user %s (uid=%d,gid=%d) (pid %d)\n", - timestring(), - remote_machine, - client_addr(), - lp_servicename(SNUM(cnum)),user, - pcon->uid, - pcon->gid, - (int)getpid())); - } - - return(cnum); -} - - -/**************************************************************************** - find first available file slot -****************************************************************************/ -int find_free_file(void ) -{ - int i; - /* we start at 1 here for an obscure reason I can't now remember, - but I think is important :-) */ - for (i=1;i<MAX_OPEN_FILES;i++) - if (!Files[i].open) - return(i); - DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n")); - return(-1); -} - -/**************************************************************************** - find first available connection slot, starting from a random position. -The randomisation stops problems with the server dieing and clients -thinking the server is still available. -****************************************************************************/ -static int find_free_connection(int hash ) -{ - int i; - BOOL used=False; - hash = (hash % (MAX_CONNECTIONS-2))+1; - - again: - - for (i=hash+1;i!=hash;) - { - if (!Connections[i].open && Connections[i].used == used) - { - DEBUG(3,("found free connection number %d\n",i)); - return(i); - } - i++; - if (i == MAX_CONNECTIONS) - i = 1; - } - - if (!used) - { - used = !used; - goto again; - } - - DEBUG(1,("ERROR! Out of connection structures\n")); - return(-1); -} - - -/**************************************************************************** -reply for the core protocol -****************************************************************************/ -int reply_corep(char *outbuf) -{ - int outsize = set_message(outbuf,1,0,True); - - Protocol = PROTOCOL_CORE; - - return outsize; -} - - -/**************************************************************************** -reply for the coreplus protocol -****************************************************************************/ -int reply_coreplus(char *outbuf) -{ - int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); - int outsize = set_message(outbuf,13,0,True); - SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support - readbraw and writebraw (possibly) */ - CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */ - SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */ - - Protocol = PROTOCOL_COREPLUS; - - return outsize; -} - - -/**************************************************************************** -reply for the lanman 1.0 protocol -****************************************************************************/ -int reply_lanman1(char *outbuf) -{ - int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); - 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; - - set_message(outbuf,13,doencrypt?8:0,True); - SSVAL(outbuf,smb_vwv1,secword); - /* Create a token value and add it to the outgoing packet. */ - if (doencrypt) - generate_next_challenge(smb_buf(outbuf)); - - Protocol = PROTOCOL_LANMAN1; - - if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) { - DEBUG(3,("using password server validation\n")); - if (doencrypt) set_challenge(smb_buf(outbuf)); - } - - CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */ - SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */ - SSVAL(outbuf,smb_vwv2,max_recv); - SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */ - SSVAL(outbuf,smb_vwv4,1); - SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support - readbraw writebraw (possibly) */ - SIVAL(outbuf,smb_vwv6,getpid()); - SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60); - - put_dos_date(outbuf,smb_vwv8,t); - - return (smb_len(outbuf)+4); -} - - -/**************************************************************************** -reply for the lanman 2.0 protocol -****************************************************************************/ -int reply_lanman2(char *outbuf) -{ - int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); - 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; - - set_message(outbuf,13,doencrypt?8:0,True); - SSVAL(outbuf,smb_vwv1,secword); - /* Create a token value and add it to the outgoing packet. */ - if (doencrypt) - generate_next_challenge(smb_buf(outbuf)); - - SIVAL(outbuf,smb_vwv6,getpid()); - - Protocol = PROTOCOL_LANMAN2; - - if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) { - DEBUG(3,("using password server validation\n")); - if (doencrypt) set_challenge(smb_buf(outbuf)); - } - - CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */ - SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */ - SSVAL(outbuf,smb_vwv2,max_recv); - SSVAL(outbuf,smb_vwv3,lp_maxmux()); - SSVAL(outbuf,smb_vwv4,1); - SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */ - SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60); - put_dos_date(outbuf,smb_vwv8,t); - - return (smb_len(outbuf)+4); -} - - -/**************************************************************************** -reply for the nt protocol -****************************************************************************/ -int reply_nt1(char *outbuf) -{ - /* 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; - - /* 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; - /* Create a token value and add it to the outgoing packet. */ - if (doencrypt) - { - generate_next_challenge(smb_buf(outbuf)); - - /* Tell the nt machine how long the challenge is. */ - SSVALS(outbuf,smb_vwv16+1,challenge_len); - } - - Protocol = PROTOCOL_NT1; - - if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) { - DEBUG(3,("using password server validation\n")); - if (doencrypt) set_challenge(smb_buf(outbuf)); - } - - SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */ - SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */ - SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */ - SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */ - SIVAL(outbuf,smb_vwv5+1,0xffff); /* raw size. LOTS! */ - SIVAL(outbuf,smb_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: -protocol [PC NETWORK PROGRAM 1.0] -protocol [XENIX CORE] -protocol [MICROSOFT NETWORKS 1.03] -protocol [LANMAN1.0] -protocol [Windows for Workgroups 3.1a] -protocol [LM1.2X002] -protocol [LANMAN2.1] -protocol [NT LM 0.12] - -Win95: -protocol [PC NETWORK PROGRAM 1.0] -protocol [XENIX CORE] -protocol [MICROSOFT NETWORKS 1.03] -protocol [LANMAN1.0] -protocol [Windows for Workgroups 3.1a] -protocol [LM1.2X002] -protocol [LANMAN2.1] -protocol [NT LM 0.12] - -OS/2: -protocol [PC NETWORK PROGRAM 1.0] -protocol [XENIX CORE] -protocol [LANMAN1.0] -protocol [LM1.2X002] -protocol [LANMAN2.1] -*/ - -/* - * Modified to recognize the architecture of the remote machine better. - * - * This appears to be the matrix of which protocol is used by which - * MS product. - Protocol WfWg Win95 WinNT OS/2 - PC NETWORK PROGRAM 1.0 1 1 1 1 - XENIX CORE 2 2 - MICROSOFT NETWORKS 3.0 2 2 - DOS LM1.2X002 3 3 - MICROSOFT NETWORKS 1.03 3 - DOS LANMAN2.1 4 4 - LANMAN1.0 4 3 - Windows for Workgroups 3.1a 5 5 5 - LM1.2X002 6 4 - LANMAN2.1 7 5 - NT LM 0.12 6 8 - * - * tim@fsg.com 09/29/95 - */ - -#define ARCH_WFWG 0x3 /* This is a fudge because WfWg is like Win95 */ -#define ARCH_WIN95 0x2 -#define ARCH_OS2 0xC /* Again OS/2 is like NT */ -#define ARCH_WINNT 0x8 -#define ARCH_SAMBA 0x10 - -#define ARCH_ALL 0x1F - -/* List of supported protocols, most desired first */ -struct { - char *proto_name; - char *short_name; - int (*proto_reply_fn)(char *); - int protocol_level; -} supported_protocols[] = { - {"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1}, - {"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1}, - {"LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, - {"Samba", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, - {"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2}, - {"LANMAN1.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1}, - {"MICROSOFT NETWORKS 3.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1}, - {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS}, - {"PC NETWORK PROGRAM 1.0", "CORE", reply_corep, PROTOCOL_CORE}, - {NULL,NULL}, -}; - - -/**************************************************************************** - reply to a negprot -****************************************************************************/ -static int reply_negprot(char *inbuf,char *outbuf) -{ - int outsize = set_message(outbuf,1,0,True); - int Index=0; - int choice= -1; - int protocol; - char *p; - int bcc = SVAL(smb_buf(inbuf),-2); - int arch = ARCH_ALL; - - p = smb_buf(inbuf)+1; - while (p < (smb_buf(inbuf) + bcc)) - { - Index++; - DEBUG(3,("Requested protocol [%s]\n",p)); - if (strcsequal(p,"Windows for Workgroups 3.1a")) - arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT ); - else if (strcsequal(p,"DOS LM1.2X002")) - arch &= ( ARCH_WFWG | ARCH_WIN95 ); - else if (strcsequal(p,"DOS LANMAN2.1")) - arch &= ( ARCH_WFWG | ARCH_WIN95 ); - else if (strcsequal(p,"NT LM 0.12")) - arch &= ( ARCH_WIN95 | ARCH_WINNT ); - else if (strcsequal(p,"LANMAN2.1")) - arch &= ( ARCH_WINNT | ARCH_OS2 ); - else if (strcsequal(p,"LM1.2X002")) - arch &= ( ARCH_WINNT | ARCH_OS2 ); - else if (strcsequal(p,"MICROSOFT NETWORKS 1.03")) - arch &= ARCH_WINNT; - else if (strcsequal(p,"XENIX CORE")) - arch &= ( ARCH_WINNT | ARCH_OS2 ); - else if (strcsequal(p,"Samba")) { - arch = ARCH_SAMBA; - break; - } - - p += strlen(p) + 2; - } - - switch ( arch ) { - case ARCH_SAMBA: - set_remote_arch(RA_SAMBA); - break; - case ARCH_WFWG: - set_remote_arch(RA_WFWG); - break; - case ARCH_WIN95: - set_remote_arch(RA_WIN95); - break; - case ARCH_WINNT: - set_remote_arch(RA_WINNT); - break; - case ARCH_OS2: - set_remote_arch(RA_OS2); - break; - default: - set_remote_arch(RA_UNKNOWN); - break; - } - - /* possibly reload - change of architecture */ - reload_services(True); - - /* a special case to stop password server loops */ - if (Index == 1 && strequal(remote_machine,myhostname) && - lp_security()==SEC_SERVER) - exit_server("Password server loop!"); - - /* Check for protocols, most desirable first */ - for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) - { - p = smb_buf(inbuf)+1; - Index = 0; - if (lp_maxprotocol() >= supported_protocols[protocol].protocol_level) - while (p < (smb_buf(inbuf) + bcc)) - { - if (strequal(p,supported_protocols[protocol].proto_name)) - choice = Index; - Index++; - p += strlen(p) + 2; - } - if(choice != -1) - break; - } - - SSVAL(outbuf,smb_vwv0,choice); - if(choice != -1) { - extern fstring remote_proto; - fstrcpy(remote_proto,supported_protocols[protocol].short_name); - reload_services(True); - outsize = supported_protocols[protocol].proto_reply_fn(outbuf); - DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name)); - } - else { - DEBUG(0,("No protocol supported !\n")); - } - SSVAL(outbuf,smb_vwv0,choice); - - DEBUG(5,("%s negprot index=%d\n",timestring(),choice)); - - return(outsize); -} - - -/**************************************************************************** -close all open files for a connection -****************************************************************************/ -static void close_open_files(int cnum) -{ - int i; - for (i=0;i<MAX_OPEN_FILES;i++) - if( Files[i].cnum == cnum && Files[i].open) { - close_file(i); - } -} - - - -/**************************************************************************** -close a cnum -****************************************************************************/ -void close_cnum(int cnum, uint16 vuid) -{ - DirCacheFlush(SNUM(cnum)); - - unbecome_user(); - - if (!OPEN_CNUM(cnum)) - { - DEBUG(0,("Can't close cnum %d\n",cnum)); - return; - } - - DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) closed connection to service %s\n", - timestring(), - remote_machine,client_addr(), - lp_servicename(SNUM(cnum)))); - - yield_connection(cnum, - lp_servicename(SNUM(cnum)), - lp_max_connections(SNUM(cnum))); - - if (lp_status(SNUM(cnum))) - yield_connection(cnum,"STATUS.",MAXSTATUS); - - close_open_files(cnum); - dptr_closecnum(cnum); - - /* execute any "postexec = " line */ - if (*lp_postexec(SNUM(cnum)) && become_user(cnum,vuid)) - { - pstring cmd; - strcpy(cmd,lp_postexec(SNUM(cnum))); - standard_sub(cnum,cmd); - smbrun(cmd,NULL,False); - unbecome_user(); - } - - unbecome_user(); - /* execute any "root postexec = " line */ - if (*lp_rootpostexec(SNUM(cnum))) - { - pstring cmd; - strcpy(cmd,lp_rootpostexec(SNUM(cnum))); - standard_sub(cnum,cmd); - smbrun(cmd,NULL,False); - } - - Connections[cnum].open = False; - num_connections_open--; - if (Connections[cnum].ngroups && Connections[cnum].groups) - { - if (Connections[cnum].igroups != (int *)Connections[cnum].groups) - free(Connections[cnum].groups); - free(Connections[cnum].igroups); - Connections[cnum].groups = NULL; - Connections[cnum].igroups = NULL; - Connections[cnum].ngroups = 0; - } - - free_namearray(Connections[cnum].veto_list); - free_namearray(Connections[cnum].hide_list); - - string_set(&Connections[cnum].user,""); - string_set(&Connections[cnum].dirpath,""); - string_set(&Connections[cnum].connectpath,""); -} - - -/**************************************************************************** -simple routines to do connection counting -****************************************************************************/ -BOOL yield_connection(int cnum,char *name,int max_connections) -{ - struct connect_record crec; - pstring fname; - FILE *f; - int mypid = getpid(); - int i; - - DEBUG(3,("Yielding connection to %d %s\n",cnum,name)); - - if (max_connections <= 0) - return(True); - - bzero(&crec,sizeof(crec)); - - pstrcpy(fname,lp_lockdir()); - standard_sub(cnum,fname); - trim_string(fname,"","/"); - - strcat(fname,"/"); - strcat(fname,name); - strcat(fname,".LCK"); - - f = fopen(fname,"r+"); - if (!f) - { - DEBUG(2,("Couldn't open lock file %s (%s)\n",fname,strerror(errno))); - return(False); - } - - fseek(f,0,SEEK_SET); - - /* find a free spot */ - for (i=0;i<max_connections;i++) - { - if (fread(&crec,sizeof(crec),1,f) != 1) - { - DEBUG(2,("Entry not found in lock file %s\n",fname)); - fclose(f); - return(False); - } - if (crec.pid == mypid && crec.cnum == cnum) - break; - } - - if (crec.pid != mypid || crec.cnum != cnum) - { - fclose(f); - DEBUG(2,("Entry not found in lock file %s\n",fname)); - return(False); - } - - bzero((void *)&crec,sizeof(crec)); - - /* remove our mark */ - if (fseek(f,i*sizeof(crec),SEEK_SET) != 0 || - fwrite(&crec,sizeof(crec),1,f) != 1) - { - DEBUG(2,("Couldn't update lock file %s (%s)\n",fname,strerror(errno))); - fclose(f); - return(False); - } - - DEBUG(3,("Yield successful\n")); - - fclose(f); - return(True); -} - - -/**************************************************************************** -simple routines to do connection counting -****************************************************************************/ -BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear) -{ - struct connect_record crec; - pstring fname; - FILE *f; - int snum = SNUM(cnum); - int i,foundi= -1; - int total_recs; - - if (max_connections <= 0) - return(True); - - DEBUG(5,("trying claim %s %s %d\n",lp_lockdir(),name,max_connections)); - - pstrcpy(fname,lp_lockdir()); - standard_sub(cnum,fname); - trim_string(fname,"","/"); - - if (!directory_exist(fname,NULL)) - mkdir(fname,0755); - - strcat(fname,"/"); - strcat(fname,name); - strcat(fname,".LCK"); - - if (!file_exist(fname,NULL)) - { - int oldmask = umask(022); - f = fopen(fname,"w"); - if (f) fclose(f); - umask(oldmask); - } - - total_recs = file_size(fname) / sizeof(crec); - - f = fopen(fname,"r+"); - - if (!f) - { - DEBUG(1,("couldn't open lock file %s\n",fname)); - return(False); - } - - /* find a free spot */ - for (i=0;i<max_connections;i++) - { - - if (i>=total_recs || - fseek(f,i*sizeof(crec),SEEK_SET) != 0 || - fread(&crec,sizeof(crec),1,f) != 1) - { - if (foundi < 0) foundi = i; - break; - } - - if (Clear && crec.pid && !process_exists(crec.pid)) - { - fseek(f,i*sizeof(crec),SEEK_SET); - bzero((void *)&crec,sizeof(crec)); - fwrite(&crec,sizeof(crec),1,f); - if (foundi < 0) foundi = i; - continue; - } - if (foundi < 0 && (!crec.pid || !process_exists(crec.pid))) - { - foundi=i; - if (!Clear) break; - } - } - - if (foundi < 0) - { - DEBUG(3,("no free locks in %s\n",fname)); - fclose(f); - return(False); - } - - /* fill in the crec */ - bzero((void *)&crec,sizeof(crec)); - crec.magic = 0x280267; - crec.pid = getpid(); - crec.cnum = cnum; - crec.uid = Connections[cnum].uid; - crec.gid = Connections[cnum].gid; - StrnCpy(crec.name,lp_servicename(snum),sizeof(crec.name)-1); - crec.start = time(NULL); - - StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1); - StrnCpy(crec.addr,client_addr(),sizeof(crec.addr)-1); - - /* make our mark */ - if (fseek(f,foundi*sizeof(crec),SEEK_SET) != 0 || - fwrite(&crec,sizeof(crec),1,f) != 1) - { - fclose(f); - return(False); - } - - fclose(f); - return(True); -} - -#if DUMP_CORE -/******************************************************************* -prepare to dump a core file - carefully! -********************************************************************/ -static BOOL dump_core(void) -{ - char *p; - pstring dname; - pstrcpy(dname,debugf); - if ((p=strrchr(dname,'/'))) *p=0; - strcat(dname,"/corefiles"); - mkdir(dname,0700); - sys_chown(dname,getuid(),getgid()); - chmod(dname,0700); - if (chdir(dname)) return(False); - umask(~(0700)); - -#ifndef NO_GETRLIMIT -#ifdef RLIMIT_CORE - { - struct rlimit rlp; - getrlimit(RLIMIT_CORE, &rlp); - rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur); - setrlimit(RLIMIT_CORE, &rlp); - getrlimit(RLIMIT_CORE, &rlp); - DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max)); - } -#endif -#endif - - - DEBUG(0,("Dumping core in %s\n",dname)); - return(True); -} -#endif - -/**************************************************************************** -exit the server -****************************************************************************/ -void exit_server(char *reason) -{ - static int firsttime=1; - int i; - - if (!firsttime) exit(0); - firsttime = 0; - - unbecome_user(); - DEBUG(2,("Closing connections\n")); - for (i=0;i<MAX_CONNECTIONS;i++) - if (Connections[i].open) - close_cnum(i,(uint16)-1); -#ifdef DFS_AUTH - if (dcelogin_atmost_once) - dfs_unlogin(); -#endif - if (!reason) { - int oldlevel = DEBUGLEVEL; - DEBUGLEVEL = 10; - DEBUG(0,("Last message was %s\n",smb_fn_name(last_message))); - if (last_inbuf) - show_msg(last_inbuf); - DEBUGLEVEL = oldlevel; - DEBUG(0,("===============================================================\n")); -#if DUMP_CORE - 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); -} - -/**************************************************************************** -do some standard substitutions in a string -****************************************************************************/ -void standard_sub(int cnum,char *str) -{ - if (VALID_CNUM(cnum)) { - char *p, *s, *home; - - for ( s=str ; (p=strchr(s, '%')) != NULL ; s=p ) { - switch (*(p+1)) { - case 'H' : if ((home = get_home_dir(Connections[cnum].user))!=NULL) - string_sub(p,"%H",home); - else - p += 2; - break; - case 'P' : string_sub(p,"%P",Connections[cnum].connectpath); break; - case 'S' : string_sub(p,"%S",lp_servicename(Connections[cnum].service)); break; - case 'g' : string_sub(p,"%g",gidtoname(Connections[cnum].gid)); break; - case 'u' : string_sub(p,"%u",Connections[cnum].user); break; - case '\0' : p++; break; /* don't run off the end of the string */ - default : p+=2; break; - } - } - } - standard_sub_basic(str); -} - -/* -These flags determine some of the permissions required to do an operation - -Note that I don't set NEED_WRITE on some write operations because they -are used by some brain-dead clients when printing, and I don't want to -force write permissions on print services. -*/ -#define AS_USER (1<<0) -#define NEED_WRITE (1<<1) -#define TIME_INIT (1<<2) -#define CAN_IPC (1<<3) -#define AS_GUEST (1<<5) - - -/* - define a list of possible SMB messages and their corresponding - functions. Any message that has a NULL function is unimplemented - - please feel free to contribute implementations! -*/ -struct smb_message_struct -{ - int code; - char *name; - int (*fn)(); - int flags; -#if PROFILING - unsigned long time; -#endif -} - smb_messages[] = { - - /* CORE PROTOCOL */ - - {SMBnegprot,"SMBnegprot",reply_negprot,0}, - {SMBtcon,"SMBtcon",reply_tcon,0}, - {SMBtdis,"SMBtdis",reply_tdis,0}, - {SMBexit,"SMBexit",reply_exit,0}, - {SMBioctl,"SMBioctl",reply_ioctl,0}, - {SMBecho,"SMBecho",reply_echo,0}, - {SMBsesssetupX,"SMBsesssetupX",reply_sesssetup_and_X,0}, - {SMBtconX,"SMBtconX",reply_tcon_and_X,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}, - {SMBsearch,"SMBsearch",reply_search,AS_USER}, - {SMBopen,"SMBopen",reply_open,AS_USER}, - - /* note that SMBmknew and SMBcreate are deliberately overloaded */ - {SMBcreate,"SMBcreate",reply_mknew,AS_USER}, - {SMBmknew,"SMBmknew",reply_mknew,AS_USER}, - - {SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE}, - {SMBread,"SMBread",reply_read,AS_USER}, - {SMBwrite,"SMBwrite",reply_write,AS_USER}, - {SMBclose,"SMBclose",reply_close,AS_USER | CAN_IPC}, - {SMBmkdir,"SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE}, - {SMBrmdir,"SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE}, - {SMBdskattr,"SMBdskattr",reply_dskattr,AS_USER}, - {SMBmv,"SMBmv",reply_mv,AS_USER | NEED_WRITE}, - - /* this is a Pathworks specific call, allowing the - changing of the root path */ - {pSETDIR,"pSETDIR",reply_setdir,AS_USER}, - - {SMBlseek,"SMBlseek",reply_lseek,AS_USER}, - {SMBflush,"SMBflush",reply_flush,AS_USER}, - {SMBctemp,"SMBctemp",reply_ctemp,AS_USER}, - {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER}, - {SMBsplclose,"SMBsplclose",reply_printclose,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}, - - /* CORE+ PROTOCOL FOLLOWS */ - - {SMBreadbraw,"SMBreadbraw",reply_readbraw,AS_USER}, - {SMBwritebraw,"SMBwritebraw",reply_writebraw,AS_USER}, - {SMBwriteclose,"SMBwriteclose",reply_writeclose,AS_USER}, - {SMBlockread,"SMBlockread",reply_lockread,AS_USER}, - {SMBwriteunlock,"SMBwriteunlock",reply_writeunlock,AS_USER}, - - /* LANMAN1.0 PROTOCOL FOLLOWS */ - - {SMBreadBmpx,"SMBreadBmpx",reply_readbmpx,AS_USER}, - {SMBreadBs,"SMBreadBs",NULL,AS_USER}, - {SMBwriteBmpx,"SMBwriteBmpx",reply_writebmpx,AS_USER}, - {SMBwriteBs,"SMBwriteBs",reply_writebs,AS_USER}, - {SMBwritec,"SMBwritec",NULL,AS_USER}, - {SMBsetattrE,"SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE}, - {SMBgetattrE,"SMBgetattrE",reply_getattrE,AS_USER}, - {SMBtrans,"SMBtrans",reply_trans,AS_USER | CAN_IPC}, - {SMBtranss,"SMBtranss",NULL,AS_USER | CAN_IPC}, - {SMBioctls,"SMBioctls",NULL,AS_USER}, - {SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE}, - {SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE}, - - {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}, - - {SMBffirst,"SMBffirst",reply_search,AS_USER}, - {SMBfunique,"SMBfunique",reply_search,AS_USER}, - {SMBfclose,"SMBfclose",reply_fclose,AS_USER}, - - /* LANMAN2.0 PROTOCOL FOLLOWS */ - {SMBfindnclose, "SMBfindnclose", reply_findnclose, AS_USER}, - {SMBfindclose, "SMBfindclose", reply_findclose,AS_USER}, - {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER}, - {SMBtranss2, "SMBtranss2", reply_transs2, AS_USER}, - - /* messaging routines */ - {SMBsends,"SMBsends",reply_sends,AS_GUEST}, - {SMBsendstrt,"SMBsendstrt",reply_sendstrt,AS_GUEST}, - {SMBsendend,"SMBsendend",reply_sendend,AS_GUEST}, - {SMBsendtxt,"SMBsendtxt",reply_sendtxt,AS_GUEST}, - - /* NON-IMPLEMENTED PARTS OF THE CORE PROTOCOL */ - - {SMBsendb,"SMBsendb",NULL,AS_GUEST}, - {SMBfwdname,"SMBfwdname",NULL,AS_GUEST}, - {SMBcancelf,"SMBcancelf",NULL,AS_GUEST}, - {SMBgetmac,"SMBgetmac",NULL,AS_GUEST} - }; - -/**************************************************************************** -return a string containing the function name of a SMB command -****************************************************************************/ -char *smb_fn_name(int type) -{ - static char *unknown_name = "SMBunknown"; - static int num_smb_messages = - sizeof(smb_messages) / sizeof(struct smb_message_struct); - int match; - - for (match=0;match<num_smb_messages;match++) - if (smb_messages[match].code == type) - break; - - if (match == num_smb_messages) - return(unknown_name); - - return(smb_messages[match].name); -} - - -/**************************************************************************** -do a switch on the message type, and return the response size -****************************************************************************/ -static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize) -{ - static int pid= -1; - int outsize = 0; - static int num_smb_messages = - sizeof(smb_messages) / sizeof(struct smb_message_struct); - int match; - -#if PROFILING - struct timeval msg_start_time; - struct timeval msg_end_time; - static unsigned long total_time = 0; - - GetTimeOfDay(&msg_start_time); -#endif - - if (pid == -1) - pid = getpid(); - - errno = 0; - last_message = type; - - /* make sure this is an SMB packet */ - if (strncmp(smb_base(inbuf),"\377SMB",4) != 0) - { - DEBUG(2,("Non-SMB packet of length %d\n",smb_len(inbuf))); - return(-1); - } - - for (match=0;match<num_smb_messages;match++) - if (smb_messages[match].code == type) - break; - - if (match == num_smb_messages) - { - DEBUG(0,("Unknown message type %d!\n",type)); - outsize = reply_unknown(inbuf,outbuf); - } - else - { - DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,pid)); - if (smb_messages[match].fn) - { - int cnum = SVAL(inbuf,smb_tid); - int flags = smb_messages[match].flags; - 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,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)) - return(ERROR(ERRSRV,ERRaccess)); - - /* ipc services are limited */ - if (IS_IPC(cnum) && (flags & AS_USER) && !(flags & CAN_IPC)) - return(ERROR(ERRSRV,ERRaccess)); - - /* load service specific parameters */ - if (OPEN_CNUM(cnum) && !become_service(cnum,(flags & AS_USER)?True:False)) - return(ERROR(ERRSRV,ERRaccess)); - - /* does this protocol need to be run as guest? */ - if ((flags & AS_GUEST) && (!become_guest() || !check_access(-1))) - return(ERROR(ERRSRV,ERRaccess)); - - last_inbuf = inbuf; - - outsize = smb_messages[match].fn(inbuf,outbuf,size,bufsize); - } - else - { - outsize = reply_unknown(inbuf,outbuf); - } - } - -#if PROFILING - GetTimeOfDay(&msg_end_time); - if (!(smb_messages[match].flags & TIME_INIT)) - { - smb_messages[match].time = 0; - smb_messages[match].flags |= TIME_INIT; - } - { - unsigned long this_time = - (msg_end_time.tv_sec - msg_start_time.tv_sec)*1e6 + - (msg_end_time.tv_usec - msg_start_time.tv_usec); - smb_messages[match].time += this_time; - total_time += this_time; - } - DEBUG(2,("TIME %s %d usecs %g pct\n", - smb_fn_name(type),smb_messages[match].time, - (100.0*smb_messages[match].time) / total_time)); -#endif - - return(outsize); -} - - -/**************************************************************************** - 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; - } - - /* 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; - - /* 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; - - /* remember the original command type */ - smb_com1 = CVAL(orig_inbuf,smb_com); - - /* save the data which will be overwritten by the new headers */ - memcpy(inbuf_saved,inbuf2,smb_wct); - memcpy(outbuf_saved,outbuf2,smb_wct); - - /* give the new packet the same header as the last part of the SMB */ - memmove(inbuf2,inbuf,smb_wct); - - /* create the in buffer */ - CVAL(inbuf2,smb_com) = smb_com2; - - /* create the out buffer */ - bzero(outbuf2,smb_size); - set_message(outbuf2,0,0,True); - CVAL(outbuf2,smb_com) = CVAL(inbuf2,smb_com); - - 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(inbuf2); - - /* process the request */ - outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size, - bufsize-chain_size); - - /* 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; - - /* 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 outsize2; -} - - - -/**************************************************************************** - construct a reply to the incoming packet -****************************************************************************/ -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); - - if (msg_type != 0) - return(reply_special(inbuf,outbuf)); - - CVAL(outbuf,smb_com) = CVAL(inbuf,smb_com); - set_message(outbuf,0,0,True); - - memcpy(outbuf+4,inbuf+4,4); - CVAL(outbuf,smb_rcls) = SUCCESS; - CVAL(outbuf,smb_reh) = 0; - CVAL(outbuf,smb_flg) = 0x80 | (CVAL(inbuf,smb_flg) & 0x8); /* bit 7 set - means a reply */ - SSVAL(outbuf,smb_flg2,1); /* say we support long filenames */ - SSVAL(outbuf,smb_err,SUCCESS); - SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid)); - SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid)); - SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid)); - SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid)); - - outsize = switch_message(type,inbuf,outbuf,size,bufsize); - - outsize += chain_size; - - if(outsize > 4) - smb_setlen(outbuf,outsize - 4); - return(outsize); -} - -/**************************************************************************** - process commands from the client -****************************************************************************/ -static void process(void) -{ - extern int Client; - - InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); - OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); - if ((InBuffer == NULL) || (OutBuffer == NULL)) - return; - - InBuffer += SMB_ALIGNMENT; - OutBuffer += SMB_ALIGNMENT; - -#if PRIME_NMBD - DEBUG(3,("priming nmbd\n")); - { - struct in_addr ip; - ip = *interpret_addr2("localhost"); - if (zero_ip(ip)) ip = *interpret_addr2("127.0.0.1"); - *OutBuffer = 0; - send_one_packet(OutBuffer,1,ip,NMB_PORT,SOCK_DGRAM); - } -#endif - - while (True) - { - int deadtime = lp_deadtime()*60; - int counter; - int last_keepalive=0; - int service_load_counter = 0; - BOOL got_smb = False; - - if (deadtime <= 0) - deadtime = DEFAULT_SMBD_TIMEOUT; - - if (lp_readprediction()) - do_read_prediction(); - - errno = 0; - - for (counter=SMBD_SELECT_LOOP; - !receive_message_or_smb(Client,oplock_sock, - InBuffer,BUFFER_SIZE,SMBD_SELECT_LOOP*1000,&got_smb); - counter += SMBD_SELECT_LOOP) - { - int i; - time_t t; - BOOL allidle = True; - extern int keepalive; - - if (counter > 365 * 3600) /* big number of seconds. */ - { - counter = 0; - service_load_counter = 0; - } - - if (smb_read_error == READ_EOF) - { - DEBUG(3,("end of file from client\n")); - return; - } - - if (smb_read_error == READ_ERROR) - { - DEBUG(3,("receive_smb error (%s) exiting\n", - strerror(errno))); - return; - } - - t = time(NULL); - - /* become root again if waiting */ - unbecome_user(); - - /* check for smb.conf reload */ - if (counter >= service_load_counter + SMBD_RELOAD_CHECK) - { - service_load_counter = counter; - - /* reload services, if files have changed. */ - reload_services(True); - } - - /* automatic timeout if all connections are closed */ - if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) - { - DEBUG(2,("%s Closing idle connection\n",timestring())); - return; - } - - 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; - } - - /* check for connection timeouts */ - for (i=0;i<MAX_CONNECTIONS;i++) - if (Connections[i].open) - { - /* close dirptrs on connections that are idle */ - if ((t-Connections[i].lastused)>DPTR_IDLE_TIMEOUT) - dptr_idlecnum(i); - - if (Connections[i].num_files_open > 0 || - (t-Connections[i].lastused)<deadtime) - allidle = False; - } - - if (allidle && num_connections_open>0) - { - DEBUG(2,("%s Closing idle connection 2\n",timestring())); - return; - } - } - - if(got_smb) - process_smb(InBuffer, OutBuffer); - else - process_local_message(oplock_sock, InBuffer, BUFFER_SIZE); - } -} - - -/**************************************************************************** - initialise connect, service and file structs -****************************************************************************/ -static void init_structs(void ) -{ - int i; - get_myname(myhostname,NULL); - - for (i=0;i<MAX_CONNECTIONS;i++) - { - Connections[i].open = False; - Connections[i].num_files_open=0; - Connections[i].lastused=0; - Connections[i].used=False; - string_init(&Connections[i].user,""); - string_init(&Connections[i].dirpath,""); - string_init(&Connections[i].connectpath,""); - string_init(&Connections[i].origpath,""); - } - - for (i=0;i<MAX_OPEN_FILES;i++) - { - Files[i].open = False; - string_init(&Files[i].name,""); - - } - - for (i=0;i<MAX_OPEN_FILES;i++) - { - file_fd_struct *fd_ptr = &FileFd[i]; - fd_ptr->ref_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(); -} - -/**************************************************************************** -usage on the program -****************************************************************************/ -static void usage(char *pname) -{ - DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n")); - - printf("Usage: %s [-D] [-p port] [-d debuglevel] [-l log basename] [-s services file]\n",pname); - printf("Version %s\n",VERSION); - printf("\t-D become a daemon\n"); - printf("\t-p port listen on the specified port\n"); - printf("\t-d debuglevel set the debuglevel\n"); - printf("\t-l log basename. Basename for log/debug files\n"); - printf("\t-s services file. Filename of services file\n"); - printf("\t-P passive only\n"); - printf("\t-a overwrite log file, don't append\n"); - printf("\n"); -} - - -/**************************************************************************** - main program -****************************************************************************/ - int main(int argc,char *argv[]) -{ - extern BOOL append_log; - /* shall I run as a daemon */ - BOOL is_daemon = False; - int port = SMB_PORT; - int opt; - extern char *optarg; - char pidFile[100] = { 0 }; - -#ifdef NEED_AUTH_PARAMETERS - set_auth_parameters(argc,argv); -#endif - -#ifdef SecureWare - setluid(0); -#endif - - append_log = True; - - TimeInit(); - - strcpy(debugf,SMBLOGFILE); - - setup_logging(argv[0],False); - - charset_initialise(); - - /* make absolutely sure we run as root - to handle cases whre people - are crazy enough to have it setuid */ -#ifdef USE_SETRES - setresuid(0,0,0); -#else - setuid(0); - seteuid(0); - setuid(0); - seteuid(0); -#endif - - fault_setup(exit_server); - signal(SIGTERM , SIGNAL_CAST dflt_sig); - - /* we want total control over the permissions on created files, - so set our umask to 0 */ - umask(0); - - GetWd(OriginalDir); - - init_uid(); - - /* this is for people who can't start the program correctly */ - while (argc > 1 && (*argv[1] != '-')) - { - argv++; - argc--; - } - - 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; - case 'i': - strcpy(scope,optarg); - break; - case 'P': - { - extern BOOL passive; - passive = True; - } - break; - case 's': - strcpy(servicesf,optarg); - break; - case 'l': - strcpy(debugf,optarg); - break; - case 'a': - { - extern BOOL append_log; - append_log = !append_log; - } - break; - case 'D': - is_daemon = True; - break; - case 'd': - if (*optarg == 'A') - DEBUGLEVEL = 10000; - else - DEBUGLEVEL = atoi(optarg); - break; - case 'p': - port = atoi(optarg); - break; - case 'h': - usage(argv[0]); - exit(0); - break; - default: - usage(argv[0]); - exit(1); - } - - reopen_logs(); - - DEBUG(2,("%s smbd version %s started\n",timestring(),VERSION)); - DEBUG(2,("Copyright Andrew Tridgell 1992-1997\n")); - -#ifndef NO_GETRLIMIT -#ifdef RLIMIT_NOFILE - { - struct rlimit rlp; - getrlimit(RLIMIT_NOFILE, &rlp); - rlp.rlim_cur = (MAX_OPEN_FILES>rlp.rlim_max)? rlp.rlim_max:MAX_OPEN_FILES; - setrlimit(RLIMIT_NOFILE, &rlp); - getrlimit(RLIMIT_NOFILE, &rlp); - DEBUG(3,("Maximum number of open files per session is %d\n",rlp.rlim_cur)); - } -#endif -#endif - - - DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n", - getuid(),getgid(),geteuid(),getegid())); - - if (sizeof(uint16) < 2 || sizeof(uint32) < 4) - { - DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n")); - exit(1); - } - - init_structs(); - - if (!reload_services(False)) - return(-1); - - codepage_initialise(lp_client_code_page()); - - strcpy(myworkgroup, lp_workgroup()); - -#ifndef NO_SIGNAL_TEST - signal(SIGHUP,SIGNAL_CAST sig_hup); -#endif - - DEBUG(3,("%s loaded services\n",timestring())); - - if (!is_daemon && !is_a_socket(0)) - { - DEBUG(0,("standard input is not a socket, assuming -D option\n")); - is_daemon = True; - } - - if (is_daemon) - { - DEBUG(3,("%s becoming a daemon\n",timestring())); - become_daemon(); - } - - if (*pidFile) - { - int fd; - char buf[20]; - - if ((fd = open(pidFile, -#ifdef O_NONBLOCK - O_NONBLOCK | -#endif - O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0) - { - DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno))); - exit(1); - } - if(fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False) - { - DEBUG(0,("ERROR: smbd is already running\n")); - exit(1); - } - sprintf(buf, "%u\n", (unsigned int) getpid()); - if (write(fd, buf, strlen(buf)) < 0) - { - DEBUG(0,("ERROR: can't write to %s: %s\n", pidFile, strerror(errno))); - exit(1); - } - /* Leave pid file open & locked for the duration... */ - } - - if (!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); - - max_recv = 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())); - } - - /* Setup the oplock IPC socket. */ - if(!open_oplock_ipc()) - exit(1); - - process(); - close_sockets(); - - exit_server("normal exit"); - return(0); -} - - diff --git a/source/smbd/smbrun.c b/source/smbd/smbrun.c deleted file mode 100644 index 42ce7f60ad0..00000000000 --- a/source/smbd/smbrun.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - external program running routine - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - - -/******************************************************************* -close the low 3 fd's and open dev/null in their place -********************************************************************/ -static void close_fds(void) -{ - int fd; - int i; - close(0); close(1); close(2); - /* try and use up these file descriptors, so silly - library routines writing to stdout etc won't cause havoc */ - for (i=0;i<3;i++) { - fd = open("/dev/null",O_RDWR,0); - if (fd < 0) fd = open("/dev/null",O_WRONLY,0); - if (fd != i) return; - } -} - - -/* -This is a wrapper around the system() call to allow commands to run correctly -as non root from a program which is switching between root and non-root - -It takes 3 arguments as uid,gid,command and runs command after -becoming a non-root user */ - int main(int argc,char *argv[]) -{ - int uid,gid; - - close_fds(); - - if (argc != 4) exit(2); - - uid = atoi(argv[1]); - gid = atoi(argv[2]); - - /* first become root - we may need to do this in order to lose - our privilages! */ -#ifdef USE_SETRES - setresgid(0,0,0); - setresuid(0,0,0); -#else - setuid(0); - seteuid(0); -#endif - -#ifdef USE_SETFS - setfsuid(uid); - setfsgid(gid); -#endif - -#ifdef USE_SETRES - setresgid(gid,gid,gid); - setresuid(uid,uid,uid); -#else - setgid(gid); - setegid(gid); - setuid(uid); - seteuid(uid); -#endif - - - /* paranoia :-) */ - if (getuid() != uid) - return(3); - - if (geteuid() != getuid()) - return(4); - - /* this is to make sure that the system() call doesn't run forever */ - alarm(30); - - return(system(argv[3])); -} diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c deleted file mode 100644 index a56df9cb9cc..00000000000 --- a/source/smbd/trans2.c +++ /dev/null @@ -1,1794 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - SMB transaction2 handling - Copyright (C) Jeremy Allison 1994-1997 - - Extensively modified by Andrew Tridgell, 1995 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "trans2.h" - -extern int DEBUGLEVEL; -extern int Protocol; -extern connection_struct Connections[]; -extern files_struct Files[]; -extern BOOL case_sensitive; -extern int Client; - -/**************************************************************************** - Send the required number of replies back. - We assume all fields other than the data fields are - set correctly for the type of call. - HACK ! Always assumes smb_setup field is zero. -****************************************************************************/ -static int send_trans2_replies(char *outbuf, int bufsize, char *params, - int paramsize, char *pdata, int datasize) -{ - /* As we are using a protocol > LANMAN1 then the max_send - variable must have been set in the sessetupX call. - This takes precedence over the max_xmit field in the - global struct. These different max_xmit variables should - be merged as this is now too confusing */ - - extern int max_send; - int data_to_send = datasize; - int params_to_send = paramsize; - int useable_space; - char *pp = params; - char *pd = pdata; - int params_sent_thistime, data_sent_thistime, total_sent_thistime; - int alignment_offset = 1; - - /* Initially set the wcnt area to be 10 - this is true for all - trans2 replies */ - set_message(outbuf,10,0,True); - - /* If there genuinely are no parameters or data to send just send - the empty packet */ - if(params_to_send == 0 && data_to_send == 0) - { - send_smb(Client,outbuf); - return 0; - } - - /* Space is bufsize minus Netbios over TCP header minus SMB header */ - /* The alignment_offset is to align the param and data bytes on an even byte - boundary. NT 4.0 Beta needs this to work correctly. */ - useable_space = bufsize - ((smb_buf(outbuf)+alignment_offset) - outbuf); - /* useable_space can never be more than max_send minus the - alignment offset. */ - useable_space = MIN(useable_space, max_send - alignment_offset); - - while( params_to_send || data_to_send) - { - /* Calculate whether we will totally or partially fill this packet */ - total_sent_thistime = params_to_send + data_to_send + alignment_offset; - /* We can never send more than useable_space */ - total_sent_thistime = MIN(total_sent_thistime, useable_space); - - set_message(outbuf, 10, total_sent_thistime, True); - - /* Set total params and data to be sent */ - SSVAL(outbuf,smb_tprcnt,paramsize); - SSVAL(outbuf,smb_tdrcnt,datasize); - - /* Calculate how many parameters and data we can fit into - this packet. Parameters get precedence */ - - params_sent_thistime = MIN(params_to_send,useable_space); - data_sent_thistime = useable_space - params_sent_thistime; - data_sent_thistime = MIN(data_sent_thistime,data_to_send); - - SSVAL(outbuf,smb_prcnt, params_sent_thistime); - if(params_sent_thistime == 0) - { - SSVAL(outbuf,smb_proff,0); - SSVAL(outbuf,smb_prdisp,0); - } else { - /* smb_proff is the offset from the start of the SMB header to the - parameter bytes, however the first 4 bytes of outbuf are - the Netbios over TCP header. Thus use smb_base() to subtract - them from the calculation */ - SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf))); - /* Absolute displacement of param bytes sent in this packet */ - SSVAL(outbuf,smb_prdisp,pp - params); - } - - SSVAL(outbuf,smb_drcnt, data_sent_thistime); - if(data_sent_thistime == 0) - { - SSVAL(outbuf,smb_droff,0); - SSVAL(outbuf,smb_drdisp, 0); - } else { - /* The offset of the data bytes is the offset of the - parameter bytes plus the number of parameters being sent this time */ - SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) - - smb_base(outbuf)) + params_sent_thistime); - SSVAL(outbuf,smb_drdisp, pd - pdata); - } - - /* Copy the param bytes into the packet */ - if(params_sent_thistime) - memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime); - /* Copy in the data bytes */ - if(data_sent_thistime) - memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime,pd,data_sent_thistime); - - DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", - params_sent_thistime, data_sent_thistime, useable_space)); - DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n", - params_to_send, data_to_send, paramsize, datasize)); - - /* Send the packet */ - send_smb(Client,outbuf); - - pp += params_sent_thistime; - pd += data_sent_thistime; - - params_to_send -= params_sent_thistime; - data_to_send -= data_sent_thistime; - - /* Sanity check */ - if(params_to_send < 0 || data_to_send < 0) - { - DEBUG(2,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!", - params_to_send, data_to_send)); - return -1; - } - } - - return 0; -} - - -/**************************************************************************** - reply to a TRANSACT2_OPEN -****************************************************************************/ -static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum, - char **pparams, char **ppdata) -{ - char *params = *pparams; - int16 open_mode = SVAL(params, 2); - int16 open_attr = SVAL(params,6); - BOOL oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1)); -#if 0 - BOOL return_additional_info = BITSETW(params,0); - int16 open_sattr = SVAL(params, 4); - time_t open_time = make_unix_date3(params+8); -#endif - int16 open_ofun = SVAL(params,12); - int32 open_size = IVAL(params,14); - char *pname = ¶ms[28]; - int16 namelen = strlen(pname)+1; - - pstring fname; - int fnum = -1; - int unixmode; - int size=0,fmode=0,mtime=0,rmode; - int32 inode = 0; - struct stat sbuf; - int smb_action = 0; - BOOL bad_path = False; - - StrnCpy(fname,pname,namelen); - - DEBUG(3,("trans2open %s cnum=%d mode=%d attr=%d ofun=%d size=%d\n", - fname,cnum,open_mode, open_attr, open_ofun, open_size)); - - /* XXXX we need to handle passed times, sattr and flags */ - - unix_convert(fname,cnum,0,&bad_path); - - fnum = find_free_file(); - if (fnum < 0) - return(ERROR(ERRSRV,ERRnofids)); - - if (!check_name(fname,cnum)) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - unixmode = unix_mode(cnum,open_attr | aARCH); - - - open_file_shared(fnum,cnum,fname,open_mode,open_ofun,unixmode, - oplock_request, &rmode,&smb_action); - - if (!Files[fnum].open) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) { - close_file(fnum); - return(ERROR(ERRDOS,ERRnoaccess)); - } - - size = sbuf.st_size; - fmode = dos_mode(cnum,fname,&sbuf); - mtime = sbuf.st_mtime; - inode = sbuf.st_ino; - if (fmode & aDIR) { - close_file(fnum); - return(ERROR(ERRDOS,ERRnoaccess)); - } - - /* Realloc the size of parameters and data we will return */ - params = *pparams = Realloc(*pparams, 28); - if(params == NULL) - return(ERROR(ERRDOS,ERRnomem)); - - bzero(params,28); - SSVAL(params,0,fnum); - SSVAL(params,2,fmode); - put_dos_date2(params,4, mtime); - SIVAL(params,8, size); - SSVAL(params,12,rmode); - - if (oplock_request && lp_fake_oplocks(SNUM(cnum))) { - smb_action |= EXTENDED_OPLOCK_GRANTED; - } - - SSVAL(params,18,smb_action); - SIVAL(params,20,inode); - - /* Send the required number of replies */ - send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0); - - return -1; -} - -/**************************************************************************** - get a level dependent lanman2 dir entry. -****************************************************************************/ -static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_level, - int requires_resume_key, - BOOL dont_descend,char **ppdata, - char *base_data, int space_remaining, - BOOL *out_of_space, - int *last_name_off) -{ - char *dname; - BOOL found = False; - struct stat sbuf; - pstring mask; - pstring pathreal; - pstring fname; - BOOL matched; - char *p, *pdata = *ppdata; - int reskey=0, prev_dirpos=0; - int mode=0; - uint32 size=0,len; - uint32 mdate=0, adate=0, cdate=0; - char *nameptr; - BOOL isrootdir = (strequal(Connections[cnum].dirpath,"./") || - strequal(Connections[cnum].dirpath,".") || - strequal(Connections[cnum].dirpath,"/")); - BOOL was_8_3; - int nt_extmode; /* Used for NT connections instead of mode */ - BOOL needslash = ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/'); - - *fname = 0; - *out_of_space = False; - - if (!Connections[cnum].dirptr) - return(False); - - p = strrchr(path_mask,'/'); - if(p != NULL) - { - if(p[1] == '\0') - strcpy(mask,"*.*"); - else - pstrcpy(mask, p+1); - } - else - pstrcpy(mask, path_mask); - - while (!found) - { - /* Needed if we run out of space */ - prev_dirpos = TellDir(Connections[cnum].dirptr); - dname = ReadDirName(Connections[cnum].dirptr); - - reskey = TellDir(Connections[cnum].dirptr); - - DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%x now at offset %d\n", - Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr))); - - if (!dname) - return(False); - - matched = False; - - pstrcpy(fname,dname); - - if(mask_match(fname, mask, case_sensitive, True)) - { - BOOL isdots = (strequal(fname,"..") || strequal(fname,".")); - if (dont_descend && !isdots) - continue; - - if (isrootdir && isdots) - continue; - - pstrcpy(pathreal,Connections[cnum].dirpath); - if(needslash) - strcat(pathreal,"/"); - strcat(pathreal,dname); - if (sys_stat(pathreal,&sbuf) != 0) - { - DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",pathreal,strerror(errno))); - continue; - } - - mode = dos_mode(cnum,pathreal,&sbuf); - - if (!dir_check_ftype(cnum,mode,&sbuf,dirtype)) { - DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype)); - continue; - } - - size = sbuf.st_size; - mdate = sbuf.st_mtime; - adate = sbuf.st_atime; - cdate = sbuf.st_ctime; - if(mode & aDIR) - size = 0; - - DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname)); - - found = True; - } - } - - name_map_mangle(fname,False,SNUM(cnum)); - - p = pdata; - nameptr = p; - - nt_extmode = mode ? mode : NT_FILE_ATTRIBUTE_NORMAL; - - switch (info_level) - { - case 1: - if(requires_resume_key) { - SIVAL(p,0,reskey); - p += 4; - } - put_dos_date2(p,l1_fdateCreation,cdate); - put_dos_date2(p,l1_fdateLastAccess,adate); - put_dos_date2(p,l1_fdateLastWrite,mdate); - SIVAL(p,l1_cbFile,size); - SIVAL(p,l1_cbFileAlloc,ROUNDUP(size,1024)); - SSVAL(p,l1_attrFile,mode); - SCVAL(p,l1_cchName,strlen(fname)); - strcpy(p + l1_achName, fname); - nameptr = p + l1_achName; - p += l1_achName + strlen(fname) + 1; - break; - - case 2: - /* info_level 2 */ - if(requires_resume_key) { - SIVAL(p,0,reskey); - p += 4; - } - put_dos_date2(p,l2_fdateCreation,cdate); - put_dos_date2(p,l2_fdateLastAccess,adate); - put_dos_date2(p,l2_fdateLastWrite,mdate); - SIVAL(p,l2_cbFile,size); - SIVAL(p,l2_cbFileAlloc,ROUNDUP(size,1024)); - SSVAL(p,l2_attrFile,mode); - SIVAL(p,l2_cbList,0); /* No extended attributes */ - SCVAL(p,l2_cchName,strlen(fname)); - strcpy(p + l2_achName, fname); - nameptr = p + l2_achName; - p += l2_achName + strlen(fname) + 1; - break; - - case 3: - SIVAL(p,0,reskey); - put_dos_date2(p,4,cdate); - put_dos_date2(p,8,adate); - put_dos_date2(p,12,mdate); - SIVAL(p,16,size); - SIVAL(p,20,ROUNDUP(size,1024)); - SSVAL(p,24,mode); - SIVAL(p,26,4); - CVAL(p,30) = strlen(fname); - strcpy(p+31, fname); - nameptr = p+31; - p += 31 + strlen(fname) + 1; - break; - - case 4: - if(requires_resume_key) { - SIVAL(p,0,reskey); - p += 4; - } - SIVAL(p,0,33+strlen(fname)+1); - put_dos_date2(p,4,cdate); - put_dos_date2(p,8,adate); - put_dos_date2(p,12,mdate); - SIVAL(p,16,size); - SIVAL(p,20,ROUNDUP(size,1024)); - SSVAL(p,24,mode); - CVAL(p,32) = strlen(fname); - strcpy(p + 33, fname); - nameptr = p+33; - p += 33 + strlen(fname) + 1; - break; - - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - was_8_3 = is_8_3(fname, True); - len = 94+strlen(fname); - len = (len + 3) & ~3; - SIVAL(p,0,len); p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date(p,cdate); p += 8; - put_long_date(p,adate); p += 8; - put_long_date(p,mdate); p += 8; - put_long_date(p,mdate); p += 8; - SIVAL(p,0,size); p += 8; - SIVAL(p,0,size); p += 8; - SIVAL(p,0,nt_extmode); p += 4; - SIVAL(p,0,strlen(fname)); p += 4; - SIVAL(p,0,0); p += 4; - if (!was_8_3) { - strcpy(p+2,fname); - if (!name_map_mangle(p+2,True,SNUM(cnum))) - (p+2)[12] = 0; - } else - *(p+2) = 0; - strupper(p+2); - SSVAL(p,0,strlen(p+2)); - p += 2 + 24; - /* nameptr = p; */ - strcpy(p,fname); p += strlen(p); - p = pdata + len; - break; - - case SMB_FIND_FILE_DIRECTORY_INFO: - len = 64+strlen(fname); - len = (len + 3) & ~3; - SIVAL(p,0,len); p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date(p,cdate); p += 8; - put_long_date(p,adate); p += 8; - put_long_date(p,mdate); p += 8; - put_long_date(p,mdate); p += 8; - SIVAL(p,0,size); p += 8; - SIVAL(p,0,size); p += 8; - SIVAL(p,0,nt_extmode); p += 4; - SIVAL(p,0,strlen(fname)); p += 4; - strcpy(p,fname); - p = pdata + len; - break; - - - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - len = 68+strlen(fname); - len = (len + 3) & ~3; - SIVAL(p,0,len); p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date(p,cdate); p += 8; - put_long_date(p,adate); p += 8; - put_long_date(p,mdate); p += 8; - put_long_date(p,mdate); p += 8; - SIVAL(p,0,size); p += 8; - SIVAL(p,0,size); p += 8; - SIVAL(p,0,nt_extmode); p += 4; - SIVAL(p,0,strlen(fname)); p += 4; - SIVAL(p,0,0); p += 4; - strcpy(p,fname); - p = pdata + len; - break; - - case SMB_FIND_FILE_NAMES_INFO: - len = 12+strlen(fname); - len = (len + 3) & ~3; - SIVAL(p,0,len); p += 4; - SIVAL(p,0,reskey); p += 4; - SIVAL(p,0,strlen(fname)); p += 4; - strcpy(p,fname); - p = pdata + len; - break; - - default: - return(False); - } - - - if (PTR_DIFF(p,pdata) > space_remaining) { - /* Move the dirptr back to prev_dirpos */ - SeekDir(Connections[cnum].dirptr, prev_dirpos); - *out_of_space = True; - DEBUG(9,("get_lanman2_dir_entry: out of space\n")); - return False; /* Not finished - just out of space */ - } - - /* Setup the last_filename pointer, as an offset from base_data */ - *last_name_off = PTR_DIFF(nameptr,base_data); - /* Advance the data pointer to the next slot */ - *ppdata = p; - return(found); -} - -/**************************************************************************** - reply to a TRANS2_FINDFIRST -****************************************************************************/ -static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum, - char **pparams, char **ppdata) -{ - /* We must be careful here that we don't return more than the - allowed number of data bytes. If this means returning fewer than - maxentries then so be it. We assume that the redirector has - enough room for the fixed number of parameter bytes it has - requested. */ - uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt); - char *params = *pparams; - char *pdata = *ppdata; - int dirtype = SVAL(params,0); - int maxentries = SVAL(params,2); - BOOL close_after_first = BITSETW(params+4,0); - BOOL close_if_end = BITSETW(params+4,1); - BOOL requires_resume_key = BITSETW(params+4,2); - int info_level = SVAL(params,6); - pstring directory; - pstring mask; - char *p, *wcard; - int last_name_off=0; - int dptr_num = -1; - int numentries = 0; - int i; - BOOL finished = False; - BOOL dont_descend = False; - BOOL out_of_space = False; - int space_remaining; - BOOL bad_path = False; - - *directory = *mask = 0; - - DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n", - dirtype, maxentries, close_after_first, close_if_end, requires_resume_key, - info_level, max_data_bytes)); - - switch (info_level) - { - case 1: - case 2: - case 3: - case 4: - case SMB_FIND_FILE_DIRECTORY_INFO: - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - case SMB_FIND_FILE_NAMES_INFO: - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - break; - default: - return(ERROR(ERRDOS,ERRunknownlevel)); - } - - pstrcpy(directory, params + 12); /* Complete directory path with - wildcard mask appended */ - - DEBUG(5,("path=%s\n",directory)); - - unix_convert(directory,cnum,0,&bad_path); - if(!check_name(directory,cnum)) { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - -#if 0 - /* Ugly - NT specific hack - maybe not needed ? (JRA) */ - if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && - (get_remote_arch() == RA_WINNT)) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbaddirectory; - } -#endif - - return(ERROR(ERRDOS,ERRbadpath)); - } - - p = strrchr(directory,'/'); - if(p == NULL) { - strcpy(mask,directory); - strcpy(directory,"./"); - } else { - strcpy(mask,p+1); - *p = 0; - } - - DEBUG(5,("dir=%s, mask = %s\n",directory, mask)); - - pdata = *ppdata = Realloc(*ppdata, max_data_bytes + 1024); - if(!*ppdata) - return(ERROR(ERRDOS,ERRnomem)); - bzero(pdata,max_data_bytes); - - /* Realloc the params space */ - params = *pparams = Realloc(*pparams, 10); - if(params == NULL) - return(ERROR(ERRDOS,ERRnomem)); - - dptr_num = dptr_create(cnum,directory, True ,SVAL(inbuf,smb_pid)); - if (dptr_num < 0) - { - if(dptr_num == -2) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - -#if 0 - /* Ugly - NT specific hack - maybe not needed ? (JRA) */ - if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && - (get_remote_arch() == RA_WINNT)) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbaddirectory; - } -#endif - - return (UNIXERROR(ERRDOS,ERRbadpath)); - } - return(ERROR(ERRDOS,ERRbadpath)); - } - - /* convert the formatted masks */ - { - p = mask; - while (*p) { - if (*p == '<') *p = '*'; - if (*p == '>') *p = '?'; - if (*p == '"') *p = '.'; - p++; - } - } - - /* a special case for 16 bit apps */ - if (strequal(mask,"????????.???")) strcpy(mask,"*"); - - /* handle broken clients that send us old 8.3 format */ - string_sub(mask,"????????","*"); - string_sub(mask,".???",".*"); - - /* Save the wildcard match and attribs we are using on this directory - - needed as lanman2 assumes these are being saved between calls */ - - if(!(wcard = strdup(mask))) { - dptr_close(dptr_num); - return(ERROR(ERRDOS,ERRnomem)); - } - - dptr_set_wcard(dptr_num, wcard); - dptr_set_attr(dptr_num, dirtype); - - DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype)); - - /* We don't need to check for VOL here as this is returned by - a different TRANS2 call. */ - - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", - Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)))); - if (in_list(Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)),case_sensitive)) - dont_descend = True; - - p = pdata; - space_remaining = max_data_bytes; - out_of_space = False; - - for (i=0;(i<maxentries) && !finished && !out_of_space;i++) - { - - /* this is a heuristic to avoid seeking the dirptr except when - absolutely necessary. It allows for a filename of about 40 chars */ - if (space_remaining < DIRLEN_GUESS && numentries > 0) - { - out_of_space = True; - finished = False; - } - else - { - finished = - !get_lanman2_dir_entry(cnum,mask,dirtype,info_level, - requires_resume_key,dont_descend, - &p,pdata,space_remaining, &out_of_space, - &last_name_off); - } - - if (finished && out_of_space) - finished = False; - - if (!finished && !out_of_space) - numentries++; - space_remaining = max_data_bytes - PTR_DIFF(p,pdata); - } - - /* Check if we can close the dirptr */ - if(close_after_first || (finished && close_if_end)) - { - dptr_close(dptr_num); - DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num)); - dptr_num = -1; - } - - /* At this point pdata points to numentries directory entries. */ - - /* Set up the return parameter block */ - SSVAL(params,0,dptr_num); - SSVAL(params,2,numentries); - SSVAL(params,4,finished); - SSVAL(params,6,0); /* Never an EA error */ - SSVAL(params,8,last_name_off); - - send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata)); - - if ((! *directory) && dptr_path(dptr_num)) - sprintf(directory,"(%s)",dptr_path(dptr_num)); - - DEBUG(4,("%s %s mask=%s directory=%s cnum=%d dirtype=%d numentries=%d\n", - timestring(), - smb_fn_name(CVAL(inbuf,smb_com)), - mask,directory,cnum,dirtype,numentries)); - - return(-1); -} - - -/**************************************************************************** - reply to a TRANS2_FINDNEXT -****************************************************************************/ -static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsize, - int cnum, char **pparams, char **ppdata) -{ - /* We must be careful here that we don't return more than the - allowed number of data bytes. If this means returning fewer than - maxentries then so be it. We assume that the redirector has - enough room for the fixed number of parameter bytes it has - requested. */ - int max_data_bytes = SVAL(inbuf, smb_mdrcnt); - char *params = *pparams; - char *pdata = *ppdata; - int16 dptr_num = SVAL(params,0); - int maxentries = SVAL(params,2); - uint16 info_level = SVAL(params,4); - uint32 resume_key = IVAL(params,6); - BOOL close_after_request = BITSETW(params+10,0); - BOOL close_if_end = BITSETW(params+10,1); - BOOL requires_resume_key = BITSETW(params+10,2); - BOOL continue_bit = BITSETW(params+10,3); - pstring mask; - pstring directory; - char *p; - uint16 dirtype; - int numentries = 0; - int i, last_name_off=0; - BOOL finished = False; - BOOL dont_descend = False; - BOOL out_of_space = False; - int space_remaining; - - *mask = *directory = 0; - - DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, close_after_request=%d, close_if_end = %d requires_resume_key = %d resume_key = %d continue=%d level = %d\n", - dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, - requires_resume_key, resume_key, continue_bit, info_level)); - - switch (info_level) - { - case 1: - case 2: - case 3: - case 4: - case SMB_FIND_FILE_DIRECTORY_INFO: - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - case SMB_FIND_FILE_NAMES_INFO: - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - break; - default: - return(ERROR(ERRDOS,ERRunknownlevel)); - } - - pdata = *ppdata = Realloc( *ppdata, max_data_bytes + 1024); - if(!*ppdata) - return(ERROR(ERRDOS,ERRnomem)); - bzero(pdata,max_data_bytes); - - /* Realloc the params space */ - params = *pparams = Realloc(*pparams, 6*SIZEOFWORD); - if(!params) - return(ERROR(ERRDOS,ERRnomem)); - - /* Check that the dptr is valid */ - if(!(Connections[cnum].dirptr = dptr_fetch_lanman2(params, dptr_num))) - return(ERROR(ERRDOS,ERRnofiles)); - - string_set(&Connections[cnum].dirpath,dptr_path(dptr_num)); - - /* Get the wildcard mask from the dptr */ - if((p = dptr_wcard(dptr_num))== NULL) { - DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num)); - return (ERROR(ERRDOS,ERRnofiles)); - } - strcpy(mask, p); - strcpy(directory,Connections[cnum].dirpath); - - /* Get the attr mask from the dptr */ - dirtype = dptr_attr(dptr_num); - - DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%X,%d)\n", - dptr_num, mask, dirtype, - Connections[cnum].dirptr, - TellDir(Connections[cnum].dirptr))); - - /* We don't need to check for VOL here as this is returned by - a different TRANS2 call. */ - - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)))); - if (in_list(Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)),case_sensitive)) - dont_descend = True; - - p = pdata; - space_remaining = max_data_bytes; - out_of_space = False; - - /* If we have a resume key - seek to the correct position. */ - if(requires_resume_key && !continue_bit) - SeekDir(Connections[cnum].dirptr, resume_key); - - for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) - { - /* this is a heuristic to avoid seeking the dirptr except when - absolutely necessary. It allows for a filename of about 40 chars */ - if (space_remaining < DIRLEN_GUESS && numentries > 0) - { - out_of_space = True; - finished = False; - } - else - { - finished = - !get_lanman2_dir_entry(cnum,mask,dirtype,info_level, - requires_resume_key,dont_descend, - &p,pdata,space_remaining, &out_of_space, - &last_name_off); - } - - if (finished && out_of_space) - finished = False; - - if (!finished && !out_of_space) - numentries++; - space_remaining = max_data_bytes - PTR_DIFF(p,pdata); - } - - /* Check if we can close the dirptr */ - if(close_after_request || (finished && close_if_end)) - { - dptr_close(dptr_num); /* This frees up the saved mask */ - DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num)); - dptr_num = -1; - } - - - /* Set up the return parameter block */ - SSVAL(params,0,numentries); - SSVAL(params,2,finished); - SSVAL(params,4,0); /* Never an EA error */ - SSVAL(params,6,last_name_off); - - send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata)); - - if ((! *directory) && dptr_path(dptr_num)) - sprintf(directory,"(%s)",dptr_path(dptr_num)); - - DEBUG(3,("%s %s mask=%s directory=%s cnum=%d dirtype=%d numentries=%d\n", - timestring(), - smb_fn_name(CVAL(inbuf,smb_com)), - mask,directory,cnum,dirtype,numentries)); - - return(-1); -} - -/**************************************************************************** - reply to a TRANS2_QFSINFO (query filesystem info) -****************************************************************************/ -static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize, - int cnum, char **pparams, char **ppdata) -{ - char *pdata = *ppdata; - char *params = *pparams; - uint16 info_level = SVAL(params,0); - int data_len; - struct stat st; - char *vname = volume_label(SNUM(cnum)); - - DEBUG(3,("call_trans2qfsinfo: cnum = %d, level = %d\n", cnum, info_level)); - - if(sys_stat(".",&st)!=0) { - DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno))); - return (ERROR(ERRSRV,ERRinvdevice)); - } - - pdata = *ppdata = Realloc(*ppdata, 1024); bzero(pdata,1024); - - switch (info_level) - { - case 1: - { - int dfree,dsize,bsize; - data_len = 18; - sys_disk_free(".",&bsize,&dfree,&dsize); - SIVAL(pdata,l1_idFileSystem,st.st_dev); - SIVAL(pdata,l1_cSectorUnit,bsize/512); - SIVAL(pdata,l1_cUnit,dsize); - SIVAL(pdata,l1_cUnitAvail,dfree); - SSVAL(pdata,l1_cbSector,512); - DEBUG(5,("call_trans2qfsinfo : bsize=%d, id=%x, cSectorUnit=%d, cUnit=%d, cUnitAvail=%d, cbSector=%d\n", - bsize, st.st_dev, bsize/512, dsize, dfree, 512)); - break; - } - case 2: - { - /* Return volume name */ - int volname_len = MIN(strlen(vname),11); - data_len = l2_vol_szVolLabel + volname_len + 1; - put_dos_date2(pdata,l2_vol_fdateCreation,st.st_ctime); - SCVAL(pdata,l2_vol_cch,volname_len); - StrnCpy(pdata+l2_vol_szVolLabel,vname,volname_len); - DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",st.st_ctime, volname_len, - pdata+l2_vol_szVolLabel)); - break; - } - case SMB_QUERY_FS_ATTRIBUTE_INFO: - data_len = 12 + 2*strlen(FSTYPE_STRING); - SIVAL(pdata,0,0x4006); /* FS ATTRIBUTES == long filenames supported? */ - SIVAL(pdata,4,128); /* Max filename component length */ - SIVAL(pdata,8,2*strlen(FSTYPE_STRING)); - PutUniCode(pdata+12,FSTYPE_STRING); - break; - case SMB_QUERY_FS_LABEL_INFO: - data_len = 4 + strlen(vname); - SIVAL(pdata,0,strlen(vname)); - strcpy(pdata+4,vname); - break; - case SMB_QUERY_FS_VOLUME_INFO: - data_len = 18 + 2*strlen(vname); - SIVAL(pdata,12,2*strlen(vname)); - PutUniCode(pdata+18,vname); - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n", strlen(vname), - vname)); - break; - case SMB_QUERY_FS_SIZE_INFO: - { - int dfree,dsize,bsize; - data_len = 24; - sys_disk_free(".",&bsize,&dfree,&dsize); - SIVAL(pdata,0,dsize); - SIVAL(pdata,8,dfree); - SIVAL(pdata,16,bsize/512); - SIVAL(pdata,20,512); - } - break; - case SMB_QUERY_FS_DEVICE_INFO: - data_len = 8; - SIVAL(pdata,0,0); /* dev type */ - SIVAL(pdata,4,0); /* characteristics */ - break; - default: - return(ERROR(ERRDOS,ERRunknownlevel)); - } - - - send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len); - - DEBUG(4,("%s %s info_level =%d\n",timestring(),smb_fn_name(CVAL(inbuf,smb_com)), info_level)); - - return -1; -} - -/**************************************************************************** - reply to a TRANS2_SETFSINFO (set filesystem info) -****************************************************************************/ -static int call_trans2setfsinfo(char *inbuf, char *outbuf, int length, int bufsize, - int cnum, char **pparams, char **ppdata) -{ - /* Just say yes we did it - there is nothing that - can be set here so it doesn't matter. */ - int outsize; - DEBUG(3,("call_trans2setfsinfo\n")); - - if (!CAN_WRITE(cnum)) - return(ERROR(ERRSRV,ERRaccess)); - - outsize = set_message(outbuf,10,0,True); - - return outsize; -} - -/**************************************************************************** - reply to a TRANS2_QFILEINFO (query file info by fileid) -****************************************************************************/ -static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length, - int bufsize,int cnum, - char **pparams,char **ppdata, - int total_data) -{ - char *params = *pparams; - char *pdata = *ppdata; - uint16 tran_call = SVAL(inbuf, smb_setup0); - uint16 info_level; - int mode=0; - int size=0; - unsigned int data_size; - struct stat sbuf; - pstring fname1; - char *fname; - char *p; - int l,pos; - BOOL bad_path = False; - - if (tran_call == TRANSACT2_QFILEINFO) { - int16 fnum = SVALS(params,0); - info_level = SVAL(params,2); - - CHECK_FNUM(fnum,cnum); - CHECK_ERROR(fnum); - - fname = Files[fnum].name; - if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) { - DEBUG(3,("fstat of fnum %d failed (%s)\n",fnum, strerror(errno))); - return(UNIXERROR(ERRDOS,ERRbadfid)); - } - pos = lseek(Files[fnum].fd_ptr->fd,0,SEEK_CUR); - } else { - /* qpathinfo */ - info_level = SVAL(params,0); - fname = &fname1[0]; - pstrcpy(fname,¶ms[6]); - unix_convert(fname,cnum,0,&bad_path); - if (!check_name(fname,cnum) || sys_stat(fname,&sbuf)) { - DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno))); - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - pos = 0; - } - - - DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n", - fname,info_level,tran_call,total_data)); - - p = strrchr(fname,'/'); - if (!p) - p = fname; - else - p++; - l = strlen(p); - mode = dos_mode(cnum,fname,&sbuf); - size = sbuf.st_size; - if (mode & aDIR) size = 0; - - params = *pparams = Realloc(*pparams,2); bzero(params,2); - data_size = 1024; - pdata = *ppdata = Realloc(*ppdata, data_size); - - if (total_data > 0 && IVAL(pdata,0) == total_data) { - /* uggh, EAs for OS2 */ - DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data)); - return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED)); - } - - bzero(pdata,data_size); - - switch (info_level) - { - case SMB_INFO_STANDARD: - case SMB_INFO_QUERY_EA_SIZE: - data_size = (info_level==1?22:26); - put_dos_date2(pdata,l1_fdateCreation,sbuf.st_ctime); /* create = inode mod */ - put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime); /* access time */ - put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */ - SIVAL(pdata,l1_cbFile,size); - SIVAL(pdata,l1_cbFileAlloc,ROUNDUP(size,1024)); - SSVAL(pdata,l1_attrFile,mode); - SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */ - break; - - case SMB_INFO_QUERY_EAS_FROM_LIST: - data_size = 24; - put_dos_date2(pdata,0,sbuf.st_ctime); /* create time = inode mod time */ - put_dos_date2(pdata,4,sbuf.st_atime); - put_dos_date2(pdata,8,sbuf.st_mtime); - SIVAL(pdata,12,size); - SIVAL(pdata,16,ROUNDUP(size,1024)); - SIVAL(pdata,20,mode); - break; - - case SMB_INFO_QUERY_ALL_EAS: - data_size = 4; - SIVAL(pdata,0,data_size); - break; - - case 6: - return(ERROR(ERRDOS,ERRbadfunc)); /* os/2 needs this */ - - case SMB_QUERY_FILE_BASIC_INFO: - data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */ - put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */ - put_long_date(pdata+8,sbuf.st_atime); /* access time */ - put_long_date(pdata+16,sbuf.st_mtime); /* write time */ - put_long_date(pdata+24,sbuf.st_mtime); /* change time */ - SIVAL(pdata,32,mode); - - DEBUG(5,("SMB_QFBI - ")); - DEBUG(5,("create: %s ", ctime(&sbuf.st_ctime))); - DEBUG(5,("access: %s ", ctime(&sbuf.st_atime))); - DEBUG(5,("write: %s ", ctime(&sbuf.st_mtime))); - DEBUG(5,("change: %s ", ctime(&sbuf.st_mtime))); - DEBUG(5,("mode: %x\n", mode)); - - break; - - case SMB_QUERY_FILE_STANDARD_INFO: - data_size = 22; - SIVAL(pdata,0,size); - SIVAL(pdata,8,size); - SIVAL(pdata,16,sbuf.st_nlink); - CVAL(pdata,20) = 0; - CVAL(pdata,21) = (mode&aDIR)?1:0; - break; - - case SMB_QUERY_FILE_EA_INFO: - data_size = 4; - break; - - /* Get the 8.3 name - used if NT SMB was negotiated. */ - case SMB_QUERY_FILE_ALT_NAME_INFO: - { - pstring short_name; - pstrcpy(short_name,fname); - /* Mangle if not already 8.3 */ - if(!is_8_3(short_name, True)) - { - if(!name_map_mangle(short_name,True,SNUM(cnum))) - *short_name = '\0'; - } - strncpy(pdata + 4,short_name,12); - (pdata + 4)[12] = 0; - strupper(pdata + 4); - l = strlen(pdata + 4); - data_size = 4 + l; - SIVAL(pdata,0,l); - } - break; - - case SMB_QUERY_FILE_NAME_INFO: - data_size = 4 + l; - SIVAL(pdata,0,l); - pstrcpy(pdata+4,fname); - break; - - case SMB_QUERY_FILE_ALLOCATION_INFO: - case SMB_QUERY_FILE_END_OF_FILEINFO: - data_size = 8; - SIVAL(pdata,0,size); - break; - - case SMB_QUERY_FILE_ALL_INFO: - put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */ - put_long_date(pdata+8,sbuf.st_atime); /* access time */ - put_long_date(pdata+16,sbuf.st_mtime); /* write time */ - put_long_date(pdata+24,sbuf.st_mtime); /* change time */ - SIVAL(pdata,32,mode); - pdata += 40; - SIVAL(pdata,0,size); - SIVAL(pdata,8,size); - SIVAL(pdata,16,sbuf.st_nlink); - CVAL(pdata,20) = 0; - CVAL(pdata,21) = (mode&aDIR)?1:0; - pdata += 24; - pdata += 8; /* index number */ - pdata += 4; /* EA info */ - if (mode & aRONLY) - SIVAL(pdata,0,0xA9); - else - SIVAL(pdata,0,0xd01BF); - pdata += 4; - SIVAL(pdata,0,pos); /* current offset */ - pdata += 8; - SIVAL(pdata,0,mode); /* is this the right sort of mode info? */ - pdata += 4; - pdata += 4; /* alignment */ - SIVAL(pdata,0,l); - pstrcpy(pdata+4,fname); - pdata += 4 + l; - data_size = PTR_DIFF(pdata,(*ppdata)); - break; - - case SMB_QUERY_FILE_STREAM_INFO: - data_size = 24 + l; - SIVAL(pdata,0,pos); - SIVAL(pdata,4,size); - SIVAL(pdata,12,size); - SIVAL(pdata,20,l); - pstrcpy(pdata+24,fname); - break; - default: - return(ERROR(ERRDOS,ERRunknownlevel)); - } - - send_trans2_replies( outbuf, bufsize, params, 2, *ppdata, data_size); - - return(-1); -} - -/**************************************************************************** - reply to a TRANS2_SETFILEINFO (set file info by fileid) -****************************************************************************/ -static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length, - int bufsize, int cnum, char **pparams, - char **ppdata, int total_data) -{ - char *params = *pparams; - char *pdata = *ppdata; - uint16 tran_call = SVAL(inbuf, smb_setup0); - uint16 info_level; - int mode=0; - int size=0; - struct utimbuf tvs; - struct stat st; - pstring fname1; - char *fname; - int fd = -1; - BOOL bad_path = False; - - if (!CAN_WRITE(cnum)) - return(ERROR(ERRSRV,ERRaccess)); - - if (tran_call == TRANSACT2_SETFILEINFO) { - int16 fnum = SVALS(params,0); - info_level = SVAL(params,2); - - CHECK_FNUM(fnum,cnum); - CHECK_ERROR(fnum); - - fname = Files[fnum].name; - fd = Files[fnum].fd_ptr->fd; - - if(fstat(fd,&st)!=0) { - DEBUG(3,("fstat of %s failed (%s)\n", fname, strerror(errno))); - return(ERROR(ERRDOS,ERRbadpath)); - } - } else { - /* set path info */ - info_level = SVAL(params,0); - fname = fname1; - pstrcpy(fname,¶ms[6]); - unix_convert(fname,cnum,0,&bad_path); - if(!check_name(fname, cnum)) - { - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - - if(sys_stat(fname,&st)!=0) { - DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno))); - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRbadpath)); - } - } - - DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n", - tran_call,fname,info_level,total_data)); - - /* Realloc the parameter and data sizes */ - params = *pparams = Realloc(*pparams,2); SSVAL(params,0,0); - if(params == NULL) - return(ERROR(ERRDOS,ERRnomem)); - - size = st.st_size; - tvs.modtime = st.st_mtime; - tvs.actime = st.st_atime; - mode = dos_mode(cnum,fname,&st); - - if (total_data > 0 && IVAL(pdata,0) == total_data) { - /* uggh, EAs for OS2 */ - DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data)); - return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED)); - } - - switch (info_level) - { - case SMB_INFO_STANDARD: - case SMB_INFO_QUERY_EA_SIZE: - { - /* access time */ - tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess); - - /* write time */ - tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite); - - mode = SVAL(pdata,l1_attrFile); - size = IVAL(pdata,l1_cbFile); - break; - } - - /* XXXX um, i don't think this is right. - it's also not in the cifs6.txt spec. - */ - case SMB_INFO_QUERY_EAS_FROM_LIST: - tvs.actime = make_unix_date2(pdata+8); - tvs.modtime = make_unix_date2(pdata+12); - size = IVAL(pdata,16); - mode = IVAL(pdata,24); - break; - - /* XXXX nor this. not in cifs6.txt, either. */ - case SMB_INFO_QUERY_ALL_EAS: - tvs.actime = make_unix_date2(pdata+8); - tvs.modtime = make_unix_date2(pdata+12); - size = IVAL(pdata,16); - mode = IVAL(pdata,24); - break; - - case SMB_SET_FILE_BASIC_INFO: - { - /* Ignore create time at offset pdata. */ - - /* access time */ - tvs.actime = interpret_long_date(pdata+8); - - /* write time + changed time, combined. */ - tvs.modtime=MAX(interpret_long_date(pdata+16), - interpret_long_date(pdata+24)); - -#if 0 /* Needs more testing... */ - /* Test from Luke to prevent Win95 from - setting incorrect values here. - */ - if (tvs.actime < tvs.modtime) - return(ERROR(ERRDOS,ERRnoaccess)); -#endif /* Needs more testing... */ - - /* attributes */ - mode = IVAL(pdata,32); - break; - } - - case SMB_SET_FILE_END_OF_FILE_INFO: - { - if (IVAL(pdata,4) != 0) /* more than 32 bits? */ - return(ERROR(ERRDOS,ERRunknownlevel)); - size = IVAL(pdata,0); - break; - } - - case SMB_SET_FILE_DISPOSITION_INFO: /* not supported yet */ - case SMB_SET_FILE_ALLOCATION_INFO: /* not supported yet */ - default: - { - return(ERROR(ERRDOS,ERRunknownlevel)); - } - } - - DEBUG(6,("actime: %s " , ctime(&tvs.actime))); - DEBUG(6,("modtime: %s ", ctime(&tvs.modtime))); - DEBUG(6,("size: %x " , size)); - DEBUG(6,("mode: %x\n" , mode)); - - /* get some defaults (no modifications) if any info is zero. */ - if (!tvs.actime) tvs.actime = st.st_atime; - if (!tvs.modtime) tvs.modtime = st.st_mtime; - if (!size) size = st.st_size; - - /* Try and set the times, size and mode of this file - - if they are different from the current values - */ - if (st.st_mtime != tvs.modtime || st.st_atime != tvs.actime) - { - if(sys_utime(fname, &tvs)!=0) - { - return(ERROR(ERRDOS,ERRnoaccess)); - } - } - - /* check the mode isn't different, before changing it */ - if (mode != dos_mode(cnum, fname, &st) && dos_chmod(cnum, fname, mode, NULL)) - { - DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno))); - return(ERROR(ERRDOS,ERRnoaccess)); - } - - if(size != st.st_size) - { - if (fd == -1) - { - fd = sys_open(fname,O_RDWR,0); - if (fd == -1) - { - return(ERROR(ERRDOS,ERRbadpath)); - } - set_filelen(fd, size); - close(fd); - } - else - { - set_filelen(fd, size); - } - } - - SSVAL(params,0,0); - - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - - return(-1); -} - -/**************************************************************************** - reply to a TRANS2_MKDIR (make directory with extended attributes). -****************************************************************************/ -static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize, - int cnum, char **pparams, char **ppdata) -{ - char *params = *pparams; - pstring directory; - int ret = -1; - BOOL bad_path = False; - - if (!CAN_WRITE(cnum)) - return(ERROR(ERRSRV,ERRaccess)); - - pstrcpy(directory, ¶ms[4]); - - DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); - - unix_convert(directory,cnum,0,&bad_path); - if (check_name(directory,cnum)) - ret = sys_mkdir(directory,unix_mode(cnum,aDIR)); - - if(ret < 0) - { - DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno))); - if((errno == ENOENT) && bad_path) - { - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadpath; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - /* Realloc the parameter and data sizes */ - params = *pparams = Realloc(*pparams,2); - if(params == NULL) - return(ERROR(ERRDOS,ERRnomem)); - - SSVAL(params,0,0); - - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); - - return(-1); -} - -/**************************************************************************** - reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes) - We don't actually do this - we just send a null response. -****************************************************************************/ -static int call_trans2findnotifyfirst(char *inbuf, char *outbuf, int length, int bufsize, - int cnum, char **pparams, char **ppdata) -{ - static uint16 fnf_handle = 257; - char *params = *pparams; - uint16 info_level = SVAL(params,4); - - DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level)); - - switch (info_level) - { - case 1: - case 2: - break; - default: - return(ERROR(ERRDOS,ERRunknownlevel)); - } - - /* Realloc the parameter and data sizes */ - params = *pparams = Realloc(*pparams,6); - if(params == NULL) - return(ERROR(ERRDOS,ERRnomem)); - - SSVAL(params,0,fnf_handle); - SSVAL(params,2,0); /* No changes */ - SSVAL(params,4,0); /* No EA errors */ - - fnf_handle++; - - if(fnf_handle == 0) - fnf_handle = 257; - - send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0); - - return(-1); -} - -/**************************************************************************** - reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for - changes). Currently this does nothing. -****************************************************************************/ -static int call_trans2findnotifynext(char *inbuf, char *outbuf, int length, int bufsize, - int cnum, char **pparams, char **ppdata) -{ - char *params = *pparams; - - DEBUG(3,("call_trans2findnotifynext\n")); - - /* Realloc the parameter and data sizes */ - params = *pparams = Realloc(*pparams,4); - if(params == NULL) - return(ERROR(ERRDOS,ERRnomem)); - - SSVAL(params,0,0); /* No changes */ - SSVAL(params,2,0); /* No EA errors */ - - send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0); - - return(-1); -} - -/**************************************************************************** - reply to a SMBfindclose (stop trans2 directory search) -****************************************************************************/ -int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize) -{ - int cnum; - int outsize = 0; - int16 dptr_num=SVALS(inbuf,smb_vwv0); - - cnum = SVAL(inbuf,smb_tid); - - DEBUG(3,("reply_findclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num)); - - dptr_close(dptr_num); - - outsize = set_message(outbuf,0,0,True); - - DEBUG(3,("%s SMBfindclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num)); - - return(outsize); -} - -/**************************************************************************** - reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search) -****************************************************************************/ -int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize) -{ - int cnum; - int outsize = 0; - int dptr_num= -1; - - cnum = SVAL(inbuf,smb_tid); - dptr_num = SVAL(inbuf,smb_vwv0); - - DEBUG(3,("reply_findnclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num)); - - /* We never give out valid handles for a - findnotifyfirst - so any dptr_num is ok here. - Just ignore it. */ - - outsize = set_message(outbuf,0,0,True); - - DEBUG(3,("%s SMB_findnclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num)); - - return(outsize); -} - - -/**************************************************************************** - reply to a SMBtranss2 - just ignore it! -****************************************************************************/ -int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize) -{ - DEBUG(4,("Ignoring transs2 of length %d\n",length)); - return(-1); -} - -/**************************************************************************** - reply to a SMBtrans2 -****************************************************************************/ -int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize) -{ - int outsize = 0; - int cnum = SVAL(inbuf,smb_tid); - unsigned int total_params = SVAL(inbuf, smb_tpscnt); - unsigned int total_data =SVAL(inbuf, smb_tdscnt); -#if 0 - unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt); - unsigned int max_data_reply = SVAL(inbuf, smb_mdrcnt); - unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt); - BOOL close_tid = BITSETW(inbuf+smb_flags,0); - BOOL no_final_response = BITSETW(inbuf+smb_flags,1); - int32 timeout = IVALS(inbuf,smb_timeout); -#endif - unsigned int suwcnt = SVAL(inbuf, smb_suwcnt); - unsigned int tran_call = SVAL(inbuf, smb_setup0); - char *params = NULL, *data = NULL; - int num_params, num_params_sofar, num_data, num_data_sofar; - - outsize = set_message(outbuf,0,0,True); - - /* All trans2 messages we handle have smb_sucnt == 1 - ensure this - is so as a sanity check */ - if(suwcnt != 1 ) - { - DEBUG(2,("Invalid smb_sucnt in trans2 call\n")); - return(ERROR(ERRSRV,ERRerror)); - } - - /* Allocate the space for the maximum needed parameters and data */ - if (total_params > 0) - params = (char *)malloc(total_params); - if (total_data > 0) - data = (char *)malloc(total_data); - - if ((total_params && !params) || (total_data && !data)) - { - DEBUG(2,("Out of memory in reply_trans2\n")); - return(ERROR(ERRDOS,ERRnomem)); - } - - /* Copy the param and data bytes sent with this request into - the params buffer */ - num_params = num_params_sofar = SVAL(inbuf,smb_pscnt); - num_data = num_data_sofar = SVAL(inbuf, smb_dscnt); - - if (num_params > total_params || num_data > total_data) - exit_server("invalid params in reply_trans2"); - - memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params); - memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data); - - if(num_data_sofar < total_data || num_params_sofar < total_params) - { - /* We need to send an interim response then receive the rest - of the parameter/data bytes */ - outsize = set_message(outbuf,0,0,True); - send_smb(Client,outbuf); - - while( num_data_sofar < total_data || num_params_sofar < total_params) - { - if(!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT) || - CVAL(inbuf, smb_com) != SMBtranss2) - { - outsize = set_message(outbuf,0,0,True); - DEBUG(2,("Invalid secondary trans2 packet\n")); - free(params); - free(data); - return(ERROR(ERRSRV,ERRerror)); - } - - /* Revise total_params and total_data in case they have changed downwards */ - total_params = SVAL(inbuf, smb_tpscnt); - total_data = SVAL(inbuf, smb_tdscnt); - num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt)); - num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt)); - if (num_params_sofar > total_params || num_data_sofar > total_data) - exit_server("data overflow in trans2"); - - memcpy( ¶ms[ SVAL(inbuf, smb_spsdisp)], - smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params); - memcpy( &data[SVAL(inbuf, smb_sdsdisp)], - smb_base(inbuf)+ SVAL(inbuf, smb_sdsoff), num_data); - } - } - - if (Protocol >= PROTOCOL_NT1) { - uint16 flg2 = SVAL(outbuf,smb_flg2); - SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */ - } - - /* Now we must call the relevant TRANS2 function */ - switch(tran_call) - { - case TRANSACT2_OPEN: - outsize = call_trans2open(inbuf, outbuf, bufsize, cnum, ¶ms, &data); - break; - case TRANSACT2_FINDFIRST: - outsize = call_trans2findfirst(inbuf, outbuf, bufsize, cnum, ¶ms, &data); - break; - case TRANSACT2_FINDNEXT: - outsize = call_trans2findnext(inbuf, outbuf, length, bufsize, cnum, ¶ms, &data); - break; - case TRANSACT2_QFSINFO: - outsize = call_trans2qfsinfo(inbuf, outbuf, length, bufsize, cnum, ¶ms, &data); - break; - case TRANSACT2_SETFSINFO: - outsize = call_trans2setfsinfo(inbuf, outbuf, length, bufsize, cnum, ¶ms, &data); - break; - case TRANSACT2_QPATHINFO: - case TRANSACT2_QFILEINFO: - outsize = call_trans2qfilepathinfo(inbuf, outbuf, length, bufsize, cnum, ¶ms, &data, total_data); - break; - case TRANSACT2_SETPATHINFO: - case TRANSACT2_SETFILEINFO: - outsize = call_trans2setfilepathinfo(inbuf, outbuf, length, bufsize, cnum, ¶ms, &data, total_data); - break; - case TRANSACT2_FINDNOTIFYFIRST: - outsize = call_trans2findnotifyfirst(inbuf, outbuf, length, bufsize, cnum, ¶ms, &data); - break; - case TRANSACT2_FINDNOTIFYNEXT: - outsize = call_trans2findnotifynext(inbuf, outbuf, length, bufsize, cnum, ¶ms, &data); - break; - case TRANSACT2_MKDIR: - outsize = call_trans2mkdir(inbuf, outbuf, length, bufsize, cnum, ¶ms, &data); - break; - default: - /* Error in request */ - DEBUG(2,("%s Unknown request %d in trans2 call\n",timestring(), tran_call)); - if(params) - free(params); - if(data) - free(data); - return (ERROR(ERRSRV,ERRerror)); - } - - /* As we do not know how many data packets will need to be - returned here the various call_trans2xxxx calls - must send their own. Thus a call_trans2xxx routine only - returns a value other than -1 when it wants to send - an error packet. - */ - - if(params) - free(params); - if(data) - free(data); - return outsize; /* If a correct response was needed the call_trans2xxx - calls have already sent it. If outsize != -1 then it is - returning an error packet. */ -} diff --git a/source/smbd/uid.c b/source/smbd/uid.c deleted file mode 100644 index cdc4e474c61..00000000000 --- a/source/smbd/uid.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - uid/user handling - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -extern int DEBUGLEVEL; - -extern connection_struct Connections[]; - -static int initial_uid; -static int initial_gid; - -/* what user is current? */ -struct current_user current_user; - -extern pstring OriginalDir; - -/**************************************************************************** -initialise the uid routines -****************************************************************************/ -void init_uid(void) -{ - initial_uid = current_user.uid = geteuid(); - initial_gid = current_user.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(); - - current_user.cnum = -1; - - ChDir(OriginalDir); -} - - -/**************************************************************************** - become the specified uid -****************************************************************************/ -static BOOL become_uid(int uid) -{ - if (initial_uid != 0) - return(True); - - if (uid == -1 || uid == 65535) { - DEBUG(1,("WARNING: using uid %d is a security risk\n",uid)); - } - -#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)\n")); - } -#endif - -#ifdef USE_SETRES - if (setresuid(-1,uid,-1) != 0) -#elif defined(USE_SETFS) - if (setfsuid(uid) != 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); - } - - current_user.uid = uid; - - return(True); -} - - -/**************************************************************************** - become the specified gid -****************************************************************************/ -static BOOL become_gid(int gid) -{ - if (initial_uid != 0) - return(True); - - if (gid == -1 || gid == 65535) { - DEBUG(1,("WARNING: using gid %d is a security risk\n",gid)); - } - -#ifdef USE_SETRES - if (setresgid(-1,gid,-1) != 0) -#elif defined(USE_SETFS) - if (setfsgid(gid) != 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); - } - - current_user.gid = gid; - - 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 -****************************************************************************/ -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")); - - current_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, uint16 vuid) -{ - user_struct *vuser = get_valid_user_struct(vuid); - int snum,gid; - int uid; - - if (current_user.cnum == cnum && vuser != 0 && current_user.id == vuser->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) || (vuser->guest) || - !check_user_ok(cnum,vuser,snum)) { - uid = Connections[cnum].uid; - gid = Connections[cnum].gid; - current_user.groups = Connections[cnum].groups; - current_user.igroups = Connections[cnum].igroups; - current_user.ngroups = Connections[cnum].ngroups; - } else { - if (!vuser) { - DEBUG(2,("Invalid vuid used %d\n",vuid)); - return(False); - } - uid = vuser->uid; - if(!*lp_force_group(snum)) - gid = vuser->gid; - else - gid = Connections[cnum].gid; - current_user.groups = vuser->user_groups; - current_user.igroups = vuser->user_igroups; - current_user.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 (current_user.ngroups > 0) - if (setgroups(current_user.ngroups,current_user.groups)<0) - DEBUG(0,("setgroups call failed!\n")); - } -#endif - - if (!Connections[cnum].admin_user && !become_uid(uid)) - return(False); - } - - current_user.cnum = cnum; - current_user.id = uid; - - DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d)\n", - getuid(),geteuid(),getgid(),getegid())); - - return(True); -} - -/**************************************************************************** - unbecome the user of a connection number -****************************************************************************/ -BOOL unbecome_user(void ) -{ - if (current_user.cnum == -1) - return(False); - - ChDir(OriginalDir); - - if (initial_uid == 0) - { -#ifdef USE_SETRES - setresuid(-1,getuid(),-1); - setresgid(-1,getgid(),-1); -#elif defined(USE_SETFS) - setfsuid(initial_uid); - setfsgid(initial_gid); -#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 - - current_user.uid = initial_uid; - current_user.gid = initial_gid; - - 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())); - - current_user.cnum = -1; - - return(True); -} - - -/**************************************************************************** -This is a utility function of smbrun(). It must be called only from -the child as it may leave the caller in a privilaged state. -****************************************************************************/ -static BOOL setup_stdout_file(char *outfile,BOOL shared) -{ - int fd; - struct stat st; - mode_t mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH; - int flags = O_RDWR|O_CREAT|O_TRUNC|O_EXCL; - - close(1); - - if (shared) { - /* become root - unprivilaged users can't delete these files */ -#ifdef USE_SETRES - setresgid(0,0,0); - setresuid(0,0,0); -#else - setuid(0); - seteuid(0); -#endif - } - - if(stat(outfile, &st) == 0) { - /* Check we're not deleting a device file. */ - if(st.st_mode & S_IFREG) - unlink(outfile); - else - flags = O_RDWR; - } - /* now create the file */ - fd = open(outfile,flags,mode); - - if (fd == -1) return False; - - if (fd != 1) { - if (dup2(fd,1) != 0) { - DEBUG(2,("Failed to create stdout file descriptor\n")); - close(fd); - return False; - } - close(fd); - } - return True; -} - - -/**************************************************************************** -run a command being careful about uid/gid handling and putting the output in -outfile (or discard it if outfile is NULL). - -if shared is True then ensure the file will be writeable by all users -but created such that its owned by root. This overcomes a security hole. - -if shared is not set then open the file with O_EXCL set -****************************************************************************/ -int smbrun(char *cmd,char *outfile,BOOL shared) -{ - int fd,pid; - int uid = current_user.uid; - int gid = current_user.gid; - -#if USE_SYSTEM - int ret; - pstring syscmd; - char *path = lp_smbrun(); - - /* in the old method we use system() to execute smbrun which then - executes the command (using system() again!). This involves lots - of shell launches and is very slow. It also suffers from a - potential security hole */ - if (!file_exist(path,NULL)) - { - DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",path)); - return(1); - } - - sprintf(syscmd,"%s %d %d \"(%s 2>&1) > %s\"", - path,uid,gid,cmd, - outfile?outfile:"/dev/null"); - - DEBUG(5,("smbrun - running %s ",syscmd)); - ret = system(syscmd); - DEBUG(5,("gave %d\n",ret)); - return(ret); -#else - /* in this newer method we will exec /bin/sh with the correct - arguments, after first setting stdout to point at the file */ - - if ((pid=fork())) { - int status=0; - /* the parent just waits for the child to exit */ - if (sys_waitpid(pid,&status,0) != pid) { - DEBUG(2,("waitpid(%d) : %s\n",pid,strerror(errno))); - return -1; - } - return status; - } - - - /* we are in the child. we exec /bin/sh to do the work for us. we - don't directly exec the command we want because it may be a - pipeline or anything else the config file specifies */ - - /* point our stdout at the file we want output to go into */ - if (outfile && !setup_stdout_file(outfile,shared)) { - exit(80); - } - - /* now completely lose our privilages. This is a fairly paranoid - way of doing it, but it does work on all systems that I know of */ -#ifdef USE_SETRES - setresgid(0,0,0); - setresuid(0,0,0); - setresgid(gid,gid,gid); - setresuid(uid,uid,uid); -#else - setuid(0); - seteuid(0); - setgid(gid); - setegid(gid); - setuid(uid); - seteuid(uid); -#endif - - if (getuid() != uid || geteuid() != uid || - getgid() != gid || getegid() != gid) { - /* we failed to lose our privilages - do not execute the command */ - exit(81); /* we can't print stuff at this stage, instead use exit codes - for debugging */ - } - - /* close all other file descriptors, leaving only 0, 1 and 2. 0 and - 2 point to /dev/null from the startup code */ - for (fd=3;fd<256;fd++) close(fd); - - execl("/bin/sh","sh","-c",cmd,NULL); - - /* not reached */ - exit(82); -#endif - return 1; -} diff --git a/source/smbd/vt_mode.c b/source/smbd/vt_mode.c deleted file mode 100644 index 07558274a52..00000000000 --- a/source/smbd/vt_mode.c +++ /dev/null @@ -1,490 +0,0 @@ -/* vt_mode.c */ -/* -support vtp-sessions - -written by Christian A. Lademann <cal@zls.com> -*/ - -/* -02.05.95:cal:ported to samba-1.9.13 -*/ - -#define __vt_mode_c__ - - -/* #include <stdio.h> */ -/* #include <fcntl.h> */ -/* #include <sys/types.h> */ -/* #include <unistd.h> */ -/* #include <signal.h> */ -/* #include <errno.h> */ -/* #include <ctype.h> */ -/* #include <utmp.h> */ -/* #include <sys/param.h> */ -/* #include <sys/ioctl.h> */ -/* #include <stdlib.h> */ -/* #include <string.h> */ - -#include "includes.h" -#include "vt_mode.h" -#include <utmp.h> - -#ifdef SCO - extern char *strdup(); -#endif - -extern int Client; - -#ifdef LINUX -# define HAS_VTY -#endif - -#ifdef SCO -# define HAS_PTY -# define HAS_VTY - -# include <sys/tty.h> -#endif - -extern int DEBUGLEVEL; -extern char *InBuffer, *OutBuffer; -extern int done_become_user; - -char master_name [64], slave_name [64]; -int master, slave, i, o, e; - -int ms_type = MS_NONE, - ms_poll = 0; - - -/* -VT_Check: test incoming packet for "vtp" or "iVT1\0" -*/ -int VT_Check(char *buffer) -{ - DEBUG(3,("Checking packet: <%10s...>\n", buffer+4)); - if((strncmp(buffer+4, "vtp", 3) == 0 && smb_len(buffer) == 3) || (strncmp(buffer+4, "iVT1\0", 5) == 0 && smb_len(buffer) == 5)) - return(1); - else - return(0); -} - - -/* -VT_Start_utmp: prepare /etc/utmp for /bin/login -*/ -int VT_Start_utmp(void) -{ - struct utmp u, *v; - char *tt; - - - setutent(); - - fstrcpy(u.ut_line, VT_Line); - - if((v = getutline(&u)) == NULL) { - if(strncmp(VT_Line, "tty", 3) == 0) - tt = VT_Line + 3; - else if(strlen(VT_Line) > 4) - tt = VT_Line + strlen(VT_Line) - 4; - else - tt = VT_Line; - - fstrcpy(u.ut_id, tt); - u.ut_time = time((time_t*)0); - } - - fstrcpy(u.ut_user, "LOGIN"); - fstrcpy(u.ut_line, VT_Line); - u.ut_pid = getpid(); - u.ut_type = LOGIN_PROCESS; - pututline(&u); - - endutent(); - - return(0); -} - - -/* -VT_Stop_utmp: prepare /etc/utmp for other processes -*/ -int VT_Stop_utmp(void) -{ - struct utmp u, *v; - - - if(VT_Line != NULL) { - setutent(); - - fstrcpy(u.ut_line, VT_Line); - - if((v = getutline(&u)) != NULL) { - fstrcpy(v->ut_user, ""); - v->ut_type = DEAD_PROCESS; - v->ut_time = time((time_t*)0); - pututline(v); - } - - endutent(); - } - - return(0); -} - - -/* -VT_AtExit: Things to do when the program exits -*/ -void VT_AtExit(void) -{ - if(VT_ChildPID > 0) { - kill(VT_ChildPID, SIGHUP); - (void)wait(NULL); - } - - VT_Stop_utmp(); -} - - -/* -VT_SigCLD: signalhandler for SIGCLD: set flag if child-process died -*/ -void VT_SigCLD(int sig) -{ - if(wait(NULL) == VT_ChildPID) - VT_ChildDied = True; - else - signal(SIGCLD, VT_SigCLD); -} - - -/* -VT_SigEXIT: signalhandler for signals that cause the process to exit -*/ -void VT_SigEXIT(int sig) -{ - VT_AtExit(); - - exit(1); -} - - -/* -VT_Start: initialize vt-specific data, alloc pty, spawn shell and send ACK -*/ -int VT_Start(void) -{ - char OutBuf [64], *X, *Y; - - - ms_type = MS_NONE; - master = slave = -1; - -#ifdef HAS_VTY -#ifdef LINUX -# define MASTER_TMPL "/dev/pty " -# define SLAVE_TMPL "/dev/tty " -# define LETTER1 "pqrs" -# define POS1 8 -# define LETTER2 "0123456789abcdef" -# define POS2 9 -#endif - -#ifdef SCO -# define MASTER_TMPL "/dev/ptyp_ " -# define SLAVE_TMPL "/dev/ttyp_ " -# define LETTER1 "0123456" -# define POS1 10 -# define LETTER2 "0123456789abcdef" -# define POS2 11 -#endif - - if(ms_poll == MS_VTY || ms_poll == 0) { - strcpy(master_name, MASTER_TMPL); - strcpy(slave_name, SLAVE_TMPL); - - for(X = LETTER1; *X && master < 0; X++) - for(Y = LETTER2; *Y && master < 0; Y++) { - master_name [POS1] = *X; - master_name [POS2] = *Y; - if((master = open(master_name, O_RDWR)) >= 0) { - slave_name [POS1] = *X; - slave_name [POS2] = *Y; - if((slave = open(slave_name, O_RDWR)) < 0) - close(master); - } - } - - if(master >= 0 && slave >= 0) - ms_type = MS_VTY; - } - -# undef MASTER_TMPL -# undef SLAVE_TMPL -# undef LETTER1 -# undef LETTER2 -# undef POS1 -# undef POS2 -#endif - - -#ifdef HAS_PTY -#ifdef SCO -# define MASTER_TMPL "/dev/ptyp%d" -# define SLAVE_TMPL "/dev/ttyp%d" -# define MIN_I 0 -# define MAX_I 63 -#endif - - if(ms_poll == MS_PTY || ms_poll == 0) { - int i; - - for(i = MIN_I; i <= MAX_I && master < 0; i++) { - sprintf(master_name, MASTER_TMPL, i); - if((master = open(master_name, O_RDWR)) >= 0) { - sprintf(slave_name, SLAVE_TMPL, i); - if((slave = open(slave_name, O_RDWR)) < 0) - close(master); - } - } - - if(master >= 0 && slave >= 0) - ms_type = MS_PTY; - } - -# undef MASTER_TMPL -# undef SLAVE_TMPL -# undef MIN_I -# undef MAX_I -#endif - - - if(! ms_type) - return(-1); - - VT_Line = strdup(strrchr(slave_name, '/') + 1); - - switch((VT_ChildPID = fork())) { - case -1: - return(-1); - break; - - case 0: -#ifdef SCO - setsid(); -#endif - close(0); - close(1); - close(2); - - i = open(slave_name, O_RDWR); - o = open(slave_name, O_RDWR); - e = open(slave_name, O_RDWR); - -#ifdef LINUX - setsid(); - if (ioctl(slave, TIOCSCTTY, (char *)NULL) == -1) - exit(1); -#endif -#ifdef SCO - tcsetpgrp(0, getpid()); -#endif - - VT_Start_utmp(); - - system("stty sane"); - execlp("/bin/login", "login", "-c", (char*)0); - exit(1); - break; - - default: - VT_Mode = True; - VT_Status = VT_OPEN; - VT_ChildDied = False; - VT_Fd = master; - - signal(SIGCLD, VT_SigCLD); - - signal(SIGHUP, VT_SigEXIT); - signal(SIGTERM, VT_SigEXIT); - signal(SIGINT, VT_SigEXIT); - signal(SIGQUIT, VT_SigEXIT); - - memset(OutBuf, 0, sizeof(OutBuf)); - OutBuf [4] = 0x06; - _smb_setlen(OutBuf, 1); - - send_smb(Client,OutBuf); - - return(0); - break; - } -} - - -/* -VT_Output: transport data from socket to pty -*/ -int VT_Output(char *Buffer) -{ - int i, len, nb; - - - if(VT_Status != VT_OPEN) - return(-1); - - len = smb_len(Buffer); - - nb = write(VT_Fd, Buffer + 4, len); - - return((nb == len) ? 0 : -1); -} - - -/* -VT_Input: transport data from pty to socket -*/ -int VT_Input(char *Buffer,int Size) -{ - int len; - - - if(VT_Status != VT_OPEN) - return(-1); - - memset(Buffer, 0, Size); - len = read(VT_Fd, Buffer + 4, MIN(VT_MAXREAD, Size)); - - _smb_setlen(Buffer, len); - - return(len + 4); -} - - -/* -VT_Process: main loop while in vt-mode -*/ -void VT_Process(void) -{ - static int trans_num = 0; - extern int Client; - int nread; - - - VT_Start(); - - atexit(VT_AtExit); - - while (True) { - int32 len; - int msg_type; - int msg_flags; - int counter; - int last_keepalive=0; - struct fd_set si; - struct timeval to, *top; - int n, ret, t; - - - errno = 0; - t = SMBD_SELECT_LOOP*1000; - - - FD_ZERO(&si); - FD_SET(Client, &si); - - FD_SET(VT_Fd, &si); - - if(t >= 0) { - to.tv_sec = t / 1000; - to.tv_usec = t - (to.tv_sec * 1000); - - top = &to; - } else - top = NULL; - - if(VT_ChildDied) - goto leave_VT_Process; - - n = select(MAX(VT_Fd, Client) + 1, &si, NULL, NULL, top); - - if(VT_ChildDied) - goto leave_VT_Process; - - if(n == 0) { - int i; - time_t t; - BOOL allidle = True; - extern int keepalive; - - counter += SMBD_SELECT_LOOP; - - t = time(NULL); - - if (keepalive && (counter-last_keepalive)>keepalive) { - if (!send_keepalive(Client)) - goto leave_VT_Process; - last_keepalive = counter; - } - } else if(n > 0) { - counter = 0; - - if(FD_ISSET(VT_Fd, &si)) { - /* got input from vt */ - nread = VT_Input(OutBuffer, MIN(BUFFER_SIZE,lp_maxxmit())); - - if(nread > 0) - send_smb(Client,OutBuffer); - } - - if(FD_ISSET(Client, &si)) { - /* got input from socket */ - - if(receive_smb(Client,InBuffer, 0)) { - msg_type = CVAL(InBuffer,0); - msg_flags = CVAL(InBuffer,1); - - len = smb_len(InBuffer); - - DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len)); - - nread = len + 4; - - DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread)); - - if(msg_type == 0) - VT_Output(InBuffer); - else { - nread = construct_reply(InBuffer,OutBuffer,nread,MIN(BUFFER_SIZE,lp_maxxmit())); - - if(nread > 0) { - if (nread != smb_len(OutBuffer) + 4) { - DEBUG(0,("ERROR: Invalid message response size! %d %d\n", - nread, - smb_len(OutBuffer))); - } else - send_smb(Client,OutBuffer); - } - } - } else - if(errno == EBADF) - goto leave_VT_Process; - } - } - - trans_num++; - } - - leave_VT_Process: -/* - if(VT_ChildPID > 0) - kill(VT_ChildPID, SIGHUP); - - VT_Stop_utmp(VT_Line); - return; -*/ - close_sockets(); - exit(0); -} |