/* connect.c 15-Apr-00 */ /* (C)opyright (C) 1993-2000, Martin Stover, Marburg, Germany * * 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. */ /* history since 01-Sep-00 * mst:01-Sep-00: pcz:added real unix rights patch from Przemyslaw Czerpak * */ #include "net.h" #include "unxfile.h" #include #include /* #define TEST_FNAME "PRINT.000" */ int use_mmap=USE_MMAP; int tells_server_version=1; /* defaults to 3.11 */ int server_version_flags=0; int max_burst_send_size=0x2000; int max_burst_recv_size=0x2000; int default_uid=-1; int default_gid=-1; #ifdef TEST_FNAME static int test_handle=-1; #endif static int default_umode_dir = 0751; static int default_umode_file = 0640; static int act_umode_dir=0; static int act_umode_file=0; #include "nwfname.h" #include "nwvolume.h" #include "nwshare.h" #include "nwattrib.h" #include "trustee.h" #include "nwfile.h" #include "nwconn.h" #include "namspace.h" #include "connect.h" typedef struct { int dev; /* unix dev */ ino_t inode; /* unix inode */ time_t timestamp; /* Zeitmarke */ uint8 *path; /* path ab Volume */ uint8 volume; /* Welches Volume */ uint8 is_temp; /* 0:perm. 1:temp 2: spez. temp */ uint8 drive; /* driveletter */ uint8 task; /* actual task */ } NW_DIR; NW_DIR dirs[MAX_NW_DIRS]; int used_dirs=0; int act_uid=-1; /* unix uid 0=root */ int act_gid=-1; /* unix gid */ int act_obj_id=0L; /* mars_nwe UID, 0=not logged in, 1=supervisor */ int act_id_flags=0; /* &1 == supervisor equivalence !!! */ int entry8_flags=0; /* special flags, see examples nw.ini, entry 8 */ int entry31_flags=0; /* not used yet */ static gid_t *act_grouplist=NULL; /* first element is counter !! */ static int connect_is_init = 0; #define MAX_DIRHANDLES 80 #define EXPIRE_COST 86400 /* Is one day enough? :) */ typedef struct { DIR *f; char unixname[256]; /* full unixname */ int dev; /* Unix dev */ ino_t inode; /* Unix Inode */ time_t timestamp; /* last allocation */ char *kpath; /* one char after unixname */ int vol_options; /* searchoptions */ int volume; /* Volume Number */ int sequence; /* Search sequence */ off_t dirpos; /* Current pos in unix dir */ int no_search_trustee; /* mst:15-Apr-00 */ } DIR_HANDLE; static DIR_HANDLE dir_handles[MAX_DIRHANDLES]; static int anz_dirhandles=0; static char *build_unix_name(NW_PATH *nwpath, int modus) /* * returns complete UNIX path * modus & 1 : ignore fn, (only path) * modus & 2 : no '/' at end */ { static char unixname[300]; /* must be big enouugh */ int volume = nwpath->volume; char *p; if (volume < 0 || volume >= used_nw_volumes || !nw_volumes[volume].unixnamlen || nw_volumes[volume].unixnamlen > 250) { errorp(10, "build_unix_name", "volume=%d not ok\n", volume); xstrcpy(unixname, "Z/Z/Z/Z"); /* */ return(unixname); } memcpy(unixname, (char*)nw_volumes[volume].unixname, nw_volumes[volume].unixnamlen ); /* first UNIXNAME VOLUME */ p = unixname + nw_volumes[volume].unixnamlen; p += strmaxcpy(p, (char*)nwpath->path, sizeof(unixname) - nw_volumes[volume].unixnamlen -1); /* now the path */ if ( (!(modus & 1)) && nwpath->fn[0]) strmaxcpy(p, (char*)nwpath->fn, sizeof(unixname) - (int)(p-unixname) -1); /* and now fn */ else if ((modus & 2) && (*(p-1) == '/')) { if (p > unixname+1) *(--p) = '\0'; else { *p++ = '.'; *p = '\0'; } } dos2unixcharset(unixname); return(unixname); } static int new_dir_handle(struct stat *stb, NW_PATH *nwpath) /* * RETURN=errorcode (<0) or dir_handle */ { int rethandle; DIR_HANDLE *dh = NULL; time_t akttime = time(NULL); time_t last_time = akttime; int thandle = 1; int nhandle = 0; for (rethandle=0; rethandle < anz_dirhandles; rethandle++){ dh=&(dir_handles[rethandle]); if (dh->f) { /* only the actual dir-handle should remain open */ closedir(dh->f); dh->f=NULL; } if (!dh->inode) { if (!nhandle) nhandle = rethandle+1; } else if (dh->dev == stb->st_dev && dh->inode == stb->st_ino && dh->volume == nwpath->volume){ nhandle = rethandle+1; break; } else if (dh->timestamp < last_time){ thandle = rethandle+1; last_time = dh->timestamp; } } if (!nhandle){ if (anz_dirhandles < MAX_DIRHANDLES) { dh=&(dir_handles[anz_dirhandles]); dh->f=NULL; rethandle = ++anz_dirhandles; } else { dh=&(dir_handles[thandle-1]); rethandle = thandle; } } else rethandle=nhandle; /* init dir_handle */ dh=&(dir_handles[rethandle-1]); dh->kpath = dh->unixname + xstrcpy(dh->unixname, build_unix_name(nwpath, 0)); if (dh->f) { closedir(dh->f); dh->f=NULL; } if ( ( !(dh->no_search_trustee=tru_eff_rights_exists(nwpath->volume, dh->unixname, stb, TRUSTEE_F))) || (dh->no_search_trustee & TRUSTEE_T) ) { if ((dh->f=opendir(dh->unixname)) == (DIR*)NULL) { seteuid(0); dh->f=opendir(dh->unixname); reseteuid(); } } if (NULL != dh->f) { dh->volume = nwpath->volume; dh->vol_options = nw_volumes[dh->volume].options; dh->dev = stb->st_dev; dh->inode = stb->st_ino; dh->timestamp = akttime; dh->sequence = 0; dh->dirpos = (off_t)0; if (dh->vol_options & VOL_OPTION_REMOUNT) { closedir(dh->f); dh->f = NULL; } } else { dh->inode = 0; dh->unixname[0] = '\0'; dh->vol_options = 0; dh->kpath = dh->unixname; rethandle = /* -0x9c */ -0xff; } return(rethandle); } static int free_dir_handle(int dhandle) { if (dhandle > 0 && --dhandle < anz_dirhandles) { DIR_HANDLE *dh=&(dir_handles[dhandle]); if (dh->f != (DIR*) NULL) { closedir(dh->f); dh->f = (DIR*)NULL; } dh->inode = 0; while (anz_dirhandles && !dir_handles[anz_dirhandles-1].inode) anz_dirhandles--; return(0); } return(-0x88); /* wrong dir_handle */ } void set_default_guid(void) { seteuid(0); setgroups(0, NULL); if (setegid(default_gid) < 0 || seteuid(default_uid) < 0) { errorp(1, "set_default_guid, !! SecurityAbort !!", "Cannot set default gid=%d and uid=%d" , default_gid, default_uid); exit(1); } act_gid = default_gid; act_uid = default_uid; act_umode_dir = default_umode_dir; act_umode_file = default_umode_file; xfree(act_grouplist); } void set_guid(int gid, int uid) { if ( gid < 0 || uid < 0 || seteuid(0) || setegid(gid) || seteuid(uid) ) { set_default_guid(); if (gid < 0 && uid < 0) { /* don't print error */ gid = act_gid; uid = act_uid; } } else if (act_gid != gid || act_uid != uid) { struct passwd *pw = getpwuid(uid); if (NULL != pw) { seteuid(0); initgroups(pw->pw_name, gid); } act_gid = gid; act_uid = uid; act_umode_dir = default_umode_dir; act_umode_file = default_umode_file; xfree(act_grouplist); if (seteuid(uid)) set_default_guid(); else { int k=getgroups(0, NULL); if (k > 0) { act_grouplist=(gid_t*)xmalloc((k+1) * sizeof(gid_t)); getgroups(k, act_grouplist+1); *act_grouplist=(gid_t)k; } } } XDPRINTF((5,0,"SET GID=%d, UID=%d %s", gid, uid, (gid==act_gid && uid == act_uid) ? "OK" : "failed")); } void reset_guid(void) { set_guid(act_gid, act_uid); } void reseteuid(void) { if (seteuid(act_uid)) reset_guid(); } int in_act_groups(gid_t gid) /* returns 1 if gid is member of act_grouplist else 0 */ { int k; gid_t *g; if (!act_grouplist) return(0); k=(int)*act_grouplist; g = act_grouplist; while (k--) { if (*(++g) == gid) return(1); } return(0); } /* pcz:01-Sep-00 */ int get_unix_access_rights(struct stat *stb, uint8 *unixname) /* returns F_OK, R_OK, W_OK, X_OK */ /* ----- old ----------------------*/ /* ORED with 0x10 if owner access */ /* ORED with 0x20 if group access */ /* ----- corrent-------------------*/ /* ORED with 0x20 if W_OK access */ /* --------------------------------*/ { int mode=0; uid_t ruid, euid, rgid; ruid=getuid(); euid=geteuid(); rgid=getgid(); setreuid(act_uid,0); setgid(act_gid); if (!access(unixname, F_OK)) { if (!access(unixname, R_OK)) mode |= R_OK; if (!access(unixname, W_OK)) /* mode |= W_OK; */ mode |= W_OK | 0x20; if (!access(unixname, X_OK)) mode |= X_OK; /* mode |= get_unix_eff_rights(stb) & ~(R_OK|W_OK|X_OK); */ } setgid(rgid); setreuid(ruid, euid); return(mode); } int get_unix_eff_rights(struct stat *stb) /* returns F_OK, R_OK, W_OK, X_OK */ /* ORED with 0x10 if owner access */ /* ORED with 0x20 if group access */ { int mode = 0; if (!act_uid) return(0x10 | R_OK | W_OK | X_OK) ; /* root */ else { if (act_uid == stb->st_uid) { mode |= 0x10; if (stb->st_mode & S_IXUSR) mode |= X_OK; if (stb->st_mode & S_IRUSR) mode |= R_OK; if (stb->st_mode & S_IWUSR) mode |= W_OK; } else if ( (act_gid == stb->st_gid) || in_act_groups(stb->st_gid) ) { mode |= 0x20; if (stb->st_mode & S_IXGRP) mode |= X_OK; if (stb->st_mode & S_IRGRP) mode |= R_OK; if (stb->st_mode & S_IWGRP) mode |= W_OK; } else { if (stb->st_mode & S_IXOTH) mode |= X_OK; if (stb->st_mode & S_IROTH) mode |= R_OK; if (stb->st_mode & S_IWOTH) mode |= W_OK; } } return(mode); } /* next routine is called after new login */ void set_nw_user(int gid, int uid, int id_flags, uint32 obj_id, uint8 *objname, int unxloginlen, uint8 *unxloginname, int grpcount, uint32 *grps) { uint8 unxlogin[20]; strmaxcpy(unxlogin, unxloginname, min(unxloginlen, sizeof(unxlogin)-1)); nwconn_set_program_title(objname); set_guid(gid, uid); act_obj_id = obj_id; act_id_flags = id_flags; XDPRINTF((5, 0, "actual obj_id is set to 0x%x", obj_id)); if ((act_id_flags&1) && obj_id != 1) { XDPRINTF((1, 0, "logged in user %s (%s) has supervisor privilegs", objname, unxlogin)); } nw_setup_vol_opts(act_gid, act_uid, act_umode_dir, act_umode_file, unxlogin); tru_init_trustees(grpcount, grps); } uint32 get_file_owner(struct stat *stb) /* returns nwuser creator of file */ { uint32 owner=1L; /* default Supervisor */ if (act_obj_id && stb && (stb->st_uid == act_uid)) owner=act_obj_id; XDPRINTF((5, 0, "get_file_owner owner=0x%x", owner)); return(owner); } static char *conn_get_nwpath_name(NW_PATH *p) /* for debugging */ { static char nwpathname[300]; char volname[100]; if (p->volume < 0 || p->volume >= used_nw_volumes) { slprintf(volname, sizeof(volname)-1, "<%d=NOT-OK>", (int)p->volume); } else xstrcpy(volname, (char*)nw_volumes[p->volume].sysname); slprintf(nwpathname, sizeof(nwpathname)-1, "%s:%s%s", volname, p->path, p->fn); return(nwpathname); } /* new from Andrew Sapozhnikov * added in 0.99.pl7, removes old x_str_match routine * Do not work for namespace routines, see namespace.c !! */ /* NW3.12/MSDOS-like filename matching. * * Wildcards '*' and '?' allowed. */ static int x_str_match(uint8 *s, uint8 *p, int soptions) { while (*p) { switch (*p) { case 0xbf: case '?': if (*s && *s != '.') s++; p++; break; #if 0 case 0xaa: case '*': while (*s && *s != '.') s++; while (*p && *p != '.' && *p != 0xae) p++; break; #else /* changed 27-May-98, 0.99.pl10 to handle '*' correct, * and to handle '*xy.xyz' in a `better` (non DOS) way. * now I know again why my old routine was so terrible ;-) */ case 0xaa: case '*': ++p; if (*p) { while (*s && *s != '.') { if (x_str_match(s, p, soptions)) return(1); else s++; } } else { if (*(p-1) == '*') /* last star '*' match everything */ return(1); else /* but 0xaa not */ while (*s && *s != '.') s++; } break; #endif case 0xae: case '.': if (*s) { if(*s != '.') return 0; else s++; } p++; break; default : if (! ((soptions & VOL_OPTION_IGNCASE) ? dfn_imatch(*s, *p) : (*s == *p)) ) return 0; p++; s++; } } return (*s ? 0 : 1); } int fn_dos_match(uint8 *s, uint8 *p, int options) { uint8 *ss=s; int len=0; int pf=0; uint8 p_buff[200]; uint8 *pp=p_buff; for (; *p; p++){ if (*p != 0xff) *pp++=*p; } *pp='\0'; p=p_buff; for (; *ss; ss++){ if (*ss == '.') { if (pf++) return(0); /* no 2. point */ len=0; } else { ++len; if ((pf && len > 3) || len > 8) return(0); if (!(options & VOL_OPTION_IGNCASE)){ if (options & VOL_OPTION_DOWNSHIFT){ /* only downshift chars */ if (*ss >= 'A' && *ss <= 'Z') return(0); } else { /* only upshift chars */ if (*ss >= 'a' && *ss <= 'z') return(0); } } } } return(x_str_match(s, p, options)); } typedef struct { int attrib; struct stat statb; uint8 *ubuf; /* userbuff */ } FUNC_SEARCH; static int func_search_entry(NW_PATH *nwpath, int attrib, int (*fs_func)(NW_PATH *nwpath, FUNC_SEARCH *fs), FUNC_SEARCH *fs) /* returns > 0 if OK < 1 if not ok or not found */ { struct dirent* dirbuff; DIR *f=NULL; int result=0; int okflag=0; char xkpath[256]; uint8 entry[256]; int volume = nwpath->volume; int soptions; FUNC_SEARCH fs_local; if (!fs) { fs = &fs_local; fs->ubuf = NULL; } fs->attrib = attrib; if (volume < 0 || volume >= used_nw_volumes) return(-1); /* something wrong */ else soptions = nw_volumes[volume].options; xstrcpy(entry, (char*)nwpath->fn); nwpath->fn[0] = '\0'; xstrcpy(xkpath, build_unix_name(nwpath, 1|2)); XDPRINTF((5,0,"func_search_entry attrib=0x%x path:%s:, xkpath:%s:, entry:%s:", attrib, nwpath->path, xkpath, entry)); if ( (!stat(xkpath, &(fs->statb))) && !tru_eff_rights_exists(volume, xkpath, &(fs->statb), TRUSTEE_F)) { if ((f=opendir(xkpath)) == (DIR*)NULL) { seteuid(0); f=opendir(xkpath); reseteuid(); } } if (f != (DIR*)NULL) { char *kpath=xkpath+strlen(xkpath); *kpath++ = '/'; while ((dirbuff = readdir(f)) != (struct dirent*)NULL){ okflag = 0; if (dirbuff->d_ino) { uint8 *name=(uint8*)(dirbuff->d_name); uint8 dname[256]; xstrcpy(dname, name); unix2doscharset(dname); okflag = (name[0] != '.' && ( (!strcmp((char*)dname, (char*)entry)) || fn_dos_match(dname, entry, soptions))); if (okflag) { *kpath = '\0'; strmaxcpy(kpath, (char*)name, sizeof(xkpath) - (int)(kpath-xkpath) -1 ); if (!s_stat(xkpath, &(fs->statb), NULL)) { okflag = ( ( ( (fs->statb.st_mode & S_IFMT) == S_IFDIR) && (attrib & 0x10)) || ( ( (fs->statb.st_mode & S_IFMT) != S_IFDIR) && !(attrib & 0x10))); if (okflag){ xstrcpy(nwpath->fn, (char*)dname); XDPRINTF((5,0,"FOUND=:%s: attrib=0x%x", nwpath->fn, fs->statb.st_mode)); result = (*fs_func)(nwpath, fs); if (result < 0) break; else result=1; } } else okflag = 0; } XDPRINTF((6,0, "NAME=:%s: OKFLAG %d", name, okflag)); } /* if */ } /* while */ closedir(f); } /* if */ return(result); } static int get_dir_entry(NW_PATH *nwpath, int *sequence, int attrib, struct stat *statb) /* returns 0 if OK and errcode if not OK */ { struct dirent* dirbuff; DIR *f=NULL; int okflag=-0xff; /* not found */ char xkpath[256]; uint8 entry[256]; int volume = nwpath->volume; int soptions; int akt_sequence=0; int no_search_trustee = 0; if (volume < 0 || volume >= used_nw_volumes) return(-0x98); /* something wrong */ else soptions = nw_volumes[volume].options; xstrcpy(entry, (char*)nwpath->fn); nwpath->fn[0] = '\0'; xstrcpy(xkpath, build_unix_name(nwpath, 1|2)); XDPRINTF((5,0,"get_dir_entry attrib=0x%x path:%s:, xkpath:%s:, entry:%s:", attrib, nwpath->path, xkpath, entry)); if ( (!stat(xkpath, statb)) && ( (!(no_search_trustee = tru_eff_rights_exists(volume, xkpath, statb, TRUSTEE_F))) || (no_search_trustee&TRUSTEE_T)) ) { if ((f=opendir(xkpath)) == (DIR*)NULL) { seteuid(0); f=opendir(xkpath); reseteuid(); } } if (f != (DIR*)NULL) { char *kpath=xkpath+strlen(xkpath); *kpath++ = '/'; if (*sequence == MAX_U16) *sequence = 0; while (akt_sequence++ < *sequence) { if (NULL == readdir(f)) { closedir(f); return(-0xff); } } while ((dirbuff = readdir(f)) != (struct dirent*)NULL){ okflag = -0xff; (*sequence)++; if (dirbuff->d_ino) { uint8 *name=(uint8*)(dirbuff->d_name); uint8 dname[256]; xstrcpy(dname, name); unix2doscharset(dname); okflag = ((name[0] != '.' && ( (!strcmp((char*)dname, (char*)entry)) || fn_dos_match(dname, entry, soptions)))) ? 0 : -0xff; if (!okflag) { *kpath = '\0'; strmaxcpy(kpath, (char*)name, sizeof(xkpath) - (int)(kpath-xkpath) -1); if (!s_stat(xkpath, statb, NULL)) { okflag = (( ( ( (statb->st_mode & S_IFMT) == S_IFDIR) && (attrib & 0x10)) || ( ( (statb->st_mode & S_IFMT) != S_IFDIR) && !(attrib & 0x10)))) ? 0 : -0xff; if (!okflag){ if ( (!no_search_trustee) || !tru_eff_rights_exists(volume, xkpath, statb, TRUSTEE_T)) { if (soptions & VOL_OPTION_IS_PIPE) { statb->st_size = 0x70000000|(statb->st_mtime&0xfffffff); } xstrcpy(nwpath->fn, (char*)dname); XDPRINTF((5,0,"FOUND=:%s: attrib=0x%x", nwpath->fn, statb->st_mode)); break; /* ready */ } else okflag = -0xff; } } else okflag = -0xff; } XDPRINTF((6,0, "NAME=:%s: OKFLAG %d", name, okflag)); } /* if */ } /* while */ closedir(f); } else okflag=-0x89; /* no search rights */ return(okflag); } static DIR *give_dh_f(DIR_HANDLE *dh) { if (!dh->f) { *(dh->kpath) = '\0'; seteuid(0); dh->f = opendir(dh->unixname); reseteuid(); } dh->timestamp=time(NULL); /* tnx to Andrew Sapozhnikov */ return(dh->f); } static void release_dh_f(DIR_HANDLE *dh, int expire) { if (dh->f && (dh->vol_options & VOL_OPTION_REMOUNT) ) { closedir(dh->f); dh->f = NULL; } if (expire) dh->timestamp-=EXPIRE_COST; /* tnx to Andrew Sapozhnikov */ } static int get_dh_entry(DIR_HANDLE *dh, uint8 *search, int size_search, int *sequence, int attrib, char *unixname, int size_unixname, struct stat *statb) /* returns 1 if OK and 0 if not OK */ { DIR *f = give_dh_f(dh); int okflag = 0; if (f != (DIR*)NULL) { struct dirent *dirbuff; uint8 entry[256]; xstrcpy(entry, search); if ( (uint16)*sequence == MAX_U16) *sequence = 0; if (*sequence < dh->sequence || ((long)dh->dirpos) < 0L) { dh->dirpos = (off_t)0; dh->sequence = 0; } SEEKDIR(f, dh->dirpos); if (dh->sequence != *sequence) { while (dh->sequence < *sequence) { if (NULL == readdir(f)) { dh->dirpos = TELLDIR(f); release_dh_f(dh, 1); return(0); } dh->sequence++; } dh->dirpos = TELLDIR(f); } XDPRINTF((5,0,"get_dh_entry seq=0x%x, attrib=0x%x path:%s:, entry:%s:", *sequence, attrib, dh->unixname, entry)); while ((dirbuff = readdir(f)) != (struct dirent*)NULL){ okflag = 0; dh->sequence++; if (dirbuff->d_ino) { uint8 *name=(uint8*)(dirbuff->d_name); uint8 dname[256]; xstrcpy(dname, name); unix2doscharset(dname); okflag = (name[0] != '.' && ( (!strcmp((char*)dname, (char*)entry)) || fn_dos_match(dname, entry, dh->vol_options))); if (okflag) { strmaxcpy(dh->kpath, (char*)name, sizeof(dh->unixname) - (int)(dh->kpath-dh->unixname) -1 ); XDPRINTF((5,0,"get_dh_entry Name=%s unixname=%s", name, dh->unixname)); if (!s_stat(dh->unixname, statb, NULL)) { okflag = ( (( (statb->st_mode & S_IFMT) == S_IFDIR) && (attrib & 0x10)) || (((statb->st_mode & S_IFMT) != S_IFDIR) && !(attrib & 0x10))); /* mst:15-Apr-00 */ if (okflag && dh->no_search_trustee && tru_eff_rights_exists(dh->volume, dh->unixname, statb, TRUSTEE_T)) okflag=0; if (okflag){ if (unixname) strmaxcpy(unixname, dh->unixname, size_unixname-1); strmaxcpy((char*)search, (char*)dname, size_search-1); break; /* ready */ } } else okflag = 0; } } /* if */ } /* while */ dh->kpath[0] = '\0'; *sequence = dh->sequence; dh->dirpos = TELLDIR(f); release_dh_f(dh, (dirbuff==NULL)); } /* if */ return(okflag); } static void conn_build_path_fn(uint8 *vol, uint8 *path, uint8 *fn, int *has_wild, uint8 *data, int len, int lenn) /* is called from build_path */ { uint8 *p = NULL; uint8 *p1 = path; *vol = '\0'; *has_wild = 0; /* no wild char */ while (len-- && *data){ if (*data == 0xae) *p1++ = '.'; else if (*data == 0xaa|| *data == '*' ) { /* *p1++ = '*'; */ *p1++ = *data; (*has_wild)++; } else if (*data == 0xbf|| *data == '?' ) { *p1++ = '?'; (*has_wild)++; } else if (*data == '/' || *data == '\\') { *p1++ = '/'; p = p1; } else if (*data == ':') { /* extract volume */ int len = (int)(p1 - path); memcpy(vol, path, len); vol[len] = '\0'; up_fn(vol); p1 = path; } else *p1++ = *data; data++; } *p1 = '\0'; if (fn != NULL) { /* if with filename */ if (p != NULL){ /* exist directory-path */ strmaxcpy((char*)fn, (char*)p, 255); *p = '\0'; } else { /* only filename */ strmaxcpy((char*)fn, (char*)path, 255); *path= '\0'; } } } static int build_path( NW_PATH *path, uint8 *data, int len, int only_dir) /* * fills path structure with the right values * if only_dir > 0, then the full path will be interpreted * as directory, in the other way, the last segment of path * will be interpreted as fn. * returns -0x98, if volume is wrong */ { uint8 vol[256]; if (len > 255) len = 255; conn_build_path_fn(vol, path->path, (only_dir) ? (uint8)NULL : path->fn, &(path->has_wild), data, len, sizeof(path->fn)); path->volume = -1; if (only_dir) path->fn[0] = '\0'; if (vol[0]) { /* there is a volume in path */ int j = used_nw_volumes; while (j--) { if (!strcmp((char*)nw_volumes[j].sysname, (char*)vol)) { path->volume = j; if (nw_volumes[j].options & VOL_OPTION_DOWNSHIFT) { down_fn(path->path); down_fn(path->fn); } else { up_fn(path->path); up_fn(path->fn); } break; } } if (path->volume < 0) return(-0x98); } return(0); } static int nw_path_directory_is_ok(NW_PATH *nwpath, struct stat *stbuff) /* returns UNIX inode of path */ { int result=0; if ((!act_obj_id) && !(entry8_flags & 1)) { if (nwpath->volume) result = -0x9c; /* wrong path, only volume 0 is OK */ else { char *p=nwpath->path; char pp[10]; while (*p=='/') ++p; strmaxcpy(pp, p, 6); up_fn(pp); p=pp+5; if (memcmp(pp, "LOGIN", 5) || (*p!='\0' && *p!='/') ) result=-0x9c; } } if (!result && !s_stat(build_unix_name(nwpath, 1 | 2 ), stbuff, NULL) && S_ISDIR(stbuff->st_mode)) return(stbuff->st_ino); else if (!result) result = -0x9c; /* wrong path */ XDPRINTF((4,0x10, "NW_PATH_OK failed:`%s`", conn_get_nwpath_name(nwpath))); return(result); } static int build_dir_name(NW_PATH *nwpath, /* gets complete path */ struct stat *stbuff, int dir_handle) /* search with dirhandle */ /* return -completition code or inode */ { uint8 searchpath[256]; uint8 *p=searchpath; uint8 *ppp=nwpath->path; int completition=0; xstrcpy(searchpath, (char*)ppp); /* save path */ if (nwpath->volume > -1) { /* absolute path */ *ppp= '\0'; } else { /* volume not kwown yet, I must get it about dir_handle */ if (dir_handle > 0 && --dir_handle < (int)used_dirs && dirs[dir_handle].inode){ nwpath->volume = dirs[dir_handle].volume; if (searchpath[0] == '/') { /* absolute path */ p++; *ppp = '\0'; } else { /* get path from dir_handle */ NW_VOL *v = &nw_volumes[nwpath->volume]; strmaxcpy((char*)ppp, (char*)dirs[dir_handle].path, sizeof(nwpath->path) - (int)(ppp-nwpath->path) -1 ); if (v->options & VOL_OPTION_IGNCASE) ppp += strlen(ppp); } } else return(-0x9b); /* wrong dir handle */ } if (*p) { uint8 *panf = nwpath->path; uint8 *p1 = panf+strlen((char*)panf); uint8 *a = p; uint8 w; int state = 0; while ((!completition) && (w = *p++) > 0){ if (!state){ XDPRINTF((5,0,"in build_dir_name path=:%s:", nwpath->path)); if (w == '.') state = 20; else if (w == '/') state = 30; else state++; } else if (state < 9){ if (w == '.') state = 10; else if (w == '/') state = 30; else state++; if (state == 9) completition= -0x9c; /* something wrong */ } else if (state < 14){ if (w == '.') return(-0x9c); else if (w == '/') state = 30; else state++; if (state == 14) completition= -0x9c; /* something wrong */ } else if (state == 20){ if (ppp > nwpath->path) ppp=nwpath->path; if (w == '/') state = 30; else if (w != '.') completition= -0x9c; /* something wrong */ } if (state == 30 || !*p) { /* now action */ uint8 *xpath=a; int len = (int)(p-a); if (len && state == 30) --len; /* '/' don not need it here */ a = p; if (len) { if (*xpath == '.') { uint8 *xp=xpath+1; if (*xp == '.') { while (*xp++ == '.' && completition > -1) { p1--; /* steht nun auf letztem Zeichen '/' od. ':' */ if (p1 < panf) completition = -0x9c ; /* wrong path, don't can go back any more */ else { while (p1 > panf && *(--p1) != '/');; if (p1 == panf) *p1='\0'; else *(++p1) = '\0'; } } } } else { memcpy(p1, xpath, len); p1 += len; *p1++ = '/'; *p1 = '\0'; } } /* if len */ state = 0; } } } if (!completition) { if (nwpath->volume > -1 && nwpath->volume < used_nw_volumes){ NW_VOL *v = &nw_volumes[nwpath->volume]; if (v->options & VOL_OPTION_DOWNSHIFT) { down_fn(ppp); down_fn(nwpath->fn); } else { up_fn(ppp); up_fn(nwpath->fn); } if (v->options & VOL_OPTION_IGNCASE) { uint8 unixname[1024]; /* should be enough */ uint8 *pp=unixname+v->unixnamlen; int offset = ppp - nwpath->path; int pathlen = strlen(nwpath->path); int fnlen = strlen(nwpath->fn); memcpy(unixname, v->unixname, v->unixnamlen); strmaxcpy(pp, nwpath->path, sizeof(unixname) - v->unixnamlen-1); if (fnlen) strmaxcpy(pp+pathlen, nwpath->fn, sizeof(unixname) - v->unixnamlen - pathlen-1 ); dos2unixcharset(pp); pp += offset; pathlen -= offset; mangle_dos_name(v, unixname, pp); unix2doscharset(pp); XDPRINTF((5, 0, "Mangled DOS/unixname=%s", unixname)); memcpy(ppp, pp, pathlen); if (fnlen) memcpy(nwpath->fn, pp+pathlen, fnlen); } } else return(-0x98); /* wrong volume */ completition = nw_path_directory_is_ok(nwpath, stbuff); } return(completition); } static int conn_get_kpl_path(NW_PATH *nwpath, struct stat *stbuff, int dirhandle, uint8 *data, int len, int only_dir) /* * if ok then the inode of dir will be returned * else a negativ errcode will be returned */ { int completition = build_path(nwpath, data, len, only_dir); XDPRINTF((5, 0, "compl=0x%x, conn_get_kpl_path %s", completition, conn_get_nwpath_name(nwpath))); if (!completition) completition = build_dir_name(nwpath, stbuff, dirhandle); return(completition); } int conn_get_full_path(int dirhandle, uint8 *data, int len, uint8 *fullpath, int size_fullpath) /* returns path in form VOLUME:PATH */ { NW_PATH nwpath; struct stat stbuff; int result = build_path(&nwpath, data, len, 0); fullpath[0]='\0'; if (!result) result = build_dir_name(&nwpath, &stbuff, dirhandle); if (result > -1) { uint8 *p=(*nwpath.path=='/') ? nwpath.path+1 : nwpath.path; int len = slprintf(fullpath, size_fullpath-1, "%s:%s", nw_volumes[nwpath.volume].sysname, p); if (len > 0) { if (nwpath.fn[0]) { if (*p) fullpath[len++]='/'; strmaxcpy(fullpath+len, nwpath.fn, size_fullpath - len -1); } result = len + strlen(nwpath.fn); } else result = -0x9c; /* wrong path */ } XDPRINTF((1, 0, "conn_get_full_path: result=%d,(0x%x),`%s`", result, result, fullpath)); return(result); } int conn_get_kpl_unxname(char *unixname, int size_unixname, int dirhandle, uint8 *data, int len) /* * gives the unixname of dirhandle + path * returns volumenumber, or < 0 if error */ { NW_PATH nwpath; struct stat stbuff; int completition = build_path(&nwpath, data, len, 0); if (!completition) completition = build_dir_name(&nwpath, &stbuff, dirhandle); if (completition > -1) { if (unixname) strmaxcpy(unixname, build_unix_name(&nwpath, 0), size_unixname-1); completition=nwpath.volume; } XDPRINTF((5, 0, "conn_get_kpl_unxname: completition=0x%x", completition)); return(completition); } void un_date_2_nw(time_t time, uint8 *d, int high_low) { struct tm *s_tm=localtime(&time); uint16 xdate=s_tm->tm_year - 80; xdate <<= 4; xdate |= s_tm->tm_mon+1; xdate <<= 5; xdate |= s_tm->tm_mday; if (high_low) { U16_TO_BE16(xdate, d); } else { U16_TO_16(xdate, d); } } void un_time_2_nw(time_t time, uint8 *d, int high_low) { struct tm *s_tm=localtime(&time); uint16 xdate=s_tm->tm_hour; xdate <<= 6; xdate |= s_tm->tm_min; xdate <<= 5; xdate |= (s_tm->tm_sec / 2); if (high_low) { U16_TO_BE16(xdate, d); } else { U16_TO_16(xdate, d); } } time_t nw_2_un_time(uint8 *d, uint8 *t) { uint16 xdate = GET_BE16(d); uint16 xtime = (t != (uint8*) NULL) ? GET_BE16(t) : 0; int year = (xdate >> 9) + 80; int month = (xdate >> 5) & 0x0F; int day = xdate & 0x1f; int hour = xtime >> 11; int minu = (xtime >> 5) & 0x3f; int sec = (xtime & 0x1f) << 1; /* Tnx to Csoma Csaba */ struct tm s_tm; s_tm.tm_year = year; s_tm.tm_mon = month-1; s_tm.tm_mday = day; s_tm.tm_hour = hour; s_tm.tm_min = minu; s_tm.tm_sec = sec; s_tm.tm_isdst = -1; return(mktime(&s_tm)); } static int get_file_attrib(NW_FILE_INFO *f, char *unixname, struct stat *stb, NW_PATH *nwpath) { uint32 dwattrib; strncpy((char*)f->name, (char*)nwpath->fn, sizeof(f->name)); f->attrib[0]=0; /* d->name could be too long */ up_fn(f->name); dwattrib = get_nw_attrib_dword(nwpath->volume, unixname, stb); U16_TO_16(dwattrib, f->attrib); un_date_2_nw(stb->st_mtime, f->create_date, 1); un_date_2_nw(stb->st_atime, f->acces_date, 1); un_date_2_nw(stb->st_mtime, f->modify_date, 1); un_time_2_nw(stb->st_mtime, f->modify_time, 1); U32_TO_BE32(stb->st_size, f->size); return(1); } static int get_dir_attrib(NW_DIR_INFO *d, char *unixname, struct stat *stb, NW_PATH *nwpath) { uint32 dwattrib; XDPRINTF((5,0, "get_dir_attrib of %s", conn_get_nwpath_name(nwpath))); strncpy((char*)d->name, (char*)nwpath->fn, sizeof(d->name)); d->attrib[0]=0; /* d->name could be too long */ up_fn(d->name); dwattrib = get_nw_attrib_dword(nwpath->volume, unixname, stb); U16_TO_16(dwattrib, d->attrib); un_date_2_nw(stb->st_mtime, d->create_date, 1); un_time_2_nw(stb->st_mtime, d->create_time, 1); U32_TO_BE32(get_file_owner(stb), d->owner_id); d->access_right_mask = 0; d->reserved = 0; U16_TO_BE16(0, d->next_search); return(1); } static int do_delete_file(NW_PATH *nwpath, FUNC_SEARCH *fs) { char unname[256]; xstrcpy(unname, build_unix_name(nwpath, 0)); XDPRINTF((5,0,"DELETE FILE unname:%s:", unname)); return(nw_unlink_node(nwpath->volume, unname, &(fs->statb))); } int nw_delete_files(int dir_handle, int searchattrib, uint8 *data, int len) { NW_PATH nwpath; struct stat stbuff; int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0); if (completition > -1) { completition = func_search_entry(&nwpath, searchattrib, do_delete_file, NULL); if (completition < 0) return(completition); else if (!completition) return(-0xff); } return(completition); } #if 1 /* new since 22-May-99, 0.99.pl16 */ /* corrected 03-Jun-99, 0.99.pl17 */ typedef struct { NW_PATH destpath; struct stat statbuf; } MV_FILES_STRUCT; static int do_mv_file(NW_PATH *nwpath, FUNC_SEARCH *fs) /* rename one File */ { char unsource[256]; int result=0; MV_FILES_STRUCT *nws=(MV_FILES_STRUCT*)fs->ubuf; struct stat statb; xstrcpy(unsource, build_unix_name(nwpath, 0)); if (stat(unsource, &statb) || tru_eff_rights_exists(nwpath->volume, unsource, &statb, TRUSTEE_W|TRUSTEE_M|TRUSTEE_R)) result=-0x8b; else if ( !S_ISDIR(fs->statb.st_mode) /* file */ && !(entry8_flags&0x80) && -1 == share_file(fs->statb.st_dev, fs->statb.st_ino, 0x10f, 2) ) result = -0x8a; /* NO Rename Privileges, file is shared open */ /* patch from Przemyslaw Czerpak */ if (!result) { /* sourcefile is ok, now try to move to destfile */ char undest[256]; char saved_fn[256]; uint8 *frompath = nwpath->fn; uint8 *topath = nws->destpath.fn; uint8 *otopath = saved_fn; uint8 c; /* we must save destpath, because perhaps we must modify it */ strmaxcpy(saved_fn, nws->destpath.fn, sizeof(saved_fn)-1); while ((0 != (c = *otopath++))) { switch (c) { case '?' : case 0xbf: if ( *frompath && *frompath != '.' && *frompath != 0xae ) *topath++ = *frompath++; break; case '.' : case 0xae: while (*frompath && *frompath != '.' && *frompath != 0xae ) frompath++; if (*frompath) frompath++; /* only append '.' if not at end */ if (*otopath) *topath++='.'; break; default: if (*frompath && *frompath != '.' && *frompath != 0xae) frompath++; *topath++=c; break; } /* switch */ } /* while */ *topath='\0'; xstrcpy(undest, build_unix_name(&nws->destpath, 0)); /* now restore destpath.fn */ xstrcpy(nws->destpath.fn, saved_fn); seteuid(0); if (entry8_flags & 0x4) /* new: 20-Nov-96 */ result = unx_mvfile_or_dir(unsource, undest); else result = unx_mvfile(unsource, undest); reseteuid(); switch (result) { case 0 : break; /* ok */ case EEXIST : result = -0x92; break; /* allready exist */ case EXDEV : result = -0x9a; break; /* cross device */ case EROFS : result = -0x8b; break; /* no rights */ default : result = -0xff; break; /* unknown error */ } } return(result); } int nw_mv_files(int searchattrib, int sourcedirhandle, uint8 *sourcedata, int sourcedatalen, int destdirhandle, uint8 *destdata, int destdatalen) { NW_PATH nwpath; struct stat stbuff; int completition = conn_get_kpl_path(&nwpath, &stbuff, sourcedirhandle, sourcedata, sourcedatalen, 0); if (completition > -1) { FUNC_SEARCH fs; MV_FILES_STRUCT mvs; completition=conn_get_kpl_path(&mvs.destpath, &mvs.statbuf, destdirhandle, destdata, destdatalen, 0); if (completition > -1) { char destpath[256]; completition=0; xstrcpy(destpath, build_unix_name(&mvs.destpath, 1)); if (tru_eff_rights_exists(mvs.destpath.volume, destpath, &mvs.statbuf, TRUSTEE_W)) completition=-0x8b; /* now destpath is tested to be writable */ } if (completition > -1) { fs.ubuf = (uint8*)&mvs; completition = func_search_entry(&nwpath, searchattrib, do_mv_file, &fs); if (completition < 0) return(completition); else if (!completition) return(-0xff); else return(0); } } return(completition); } #else /* old version (before 22-May-99, 0.99.pl15 ) */ /* "Resolve" string 'topath' (possible with wildcards '?') using * 'frompath' as source for substitution. Make changes directly in * 'topath'. Return new length of topath (equal or less than original value) * Routine from: Andrew Sapozhnikov */ static int apply_wildcards (uint8 *frompath, int flen, uint8 *topath, int tlen) { int i,tlen2; uint8 c,*topath2; for (i=flen; i > 0; i--) { c=frompath[i-1]; if (c == ':' || c == '\\' || c == '/') break; } frompath+=i; flen-=i; for (i=tlen; i > 0; i--) { c=topath[i-1]; if(c == ':' || c == '\\' || c == '/') break; } topath2=(topath+=i); tlen2=tlen-i; while (tlen2--) { switch (c=*topath2++) { case '?': case 0xbf: if (flen && *frompath != '.' && *frompath != 0xae) { *topath++ = *frompath++; flen--; } else tlen--; break; case '.': case 0xae: while (flen && *frompath != '.' && *frompath != 0xae) { frompath++; flen--; } if (flen) { frompath++; flen--; } *topath++=c; break; default: if (flen && *frompath != '.' && *frompath != 0xae) { frompath++; flen--; } *topath++=c; } } return tlen; } int mv_file(int qdirhandle, uint8 *q, int qlen, int zdirhandle, uint8 *z, int zlen) { NW_PATH quellpath; struct stat qstbuff; NW_PATH zielpath; struct stat zstbuff; int completition; zlen=apply_wildcards(q, qlen, z, zlen); completition=conn_get_kpl_path(&quellpath, &qstbuff, qdirhandle, q, qlen, 0); if (completition > -1) { char qfn[256]; xstrcpy(qfn, build_unix_name(&quellpath,0)); completition=conn_get_kpl_path(&zielpath, &zstbuff, zdirhandle, z, zlen, 0); if (completition > -1) { char zpath[256]; completition=0; xstrcpy(zpath, build_unix_name(&zielpath, 1)); if (stat(qfn, &qstbuff) || tru_eff_rights_exists(quellpath.volume, qfn, &qstbuff, TRUSTEE_W|TRUSTEE_M|TRUSTEE_R)) completition=-0x8b; else if (tru_eff_rights_exists(zielpath.volume, zpath, &zstbuff, TRUSTEE_W)) completition=-0x8b; } if (!completition){ char unziel[256]; xstrcpy(unziel, build_unix_name(&zielpath,0)); seteuid(0); if (entry8_flags & 0x4) /* new: 20-Nov-96 */ completition = unx_mvfile_or_dir(qfn, unziel); else completition = unx_mvfile(qfn, unziel); reseteuid(); switch (completition) { case 0 : break; case EEXIST : completition = -0x92; break; /* allready exist */ case EXDEV : completition = -0x9a; break; /* cross device */ case EROFS : completition = -0x8b; break; /* no rights */ default : completition = -0xff; } } } return(completition); } #endif static int do_set_file_info(NW_PATH *nwpath, FUNC_SEARCH *fs) { char unname[256]; int result=0; NW_FILE_INFO *f=(NW_FILE_INFO*)fs->ubuf; int voloptions = get_volume_options(nwpath->volume); struct stat statb; xstrcpy(unname, build_unix_name(nwpath, 0)); if (!stat(unname, &statb)) { if (S_ISFIFO(statb.st_mode) || (voloptions&VOL_OPTION_IS_PIPE)) return(0); /* do nothing but report OK */ if (tru_eff_rights_exists(nwpath->volume, unname, &statb, TRUSTEE_M)) result=-0x8c; /* no modify rights */ } else result=-0xff; if (!result) { struct utimbuf ut; ut.actime = ut.modtime = nw_2_un_time(f->modify_date, f->modify_time); result=set_nw_attrib_word(nwpath->volume, unname, &statb, (int)GET_16(f->attrib)); if (!result) { seteuid(0); if (utime(unname, &ut)) result= (-0x8c); /* no modify rights */ reseteuid(); } } XDPRINTF((5,0,"set_file_info result=0x%x, unname:%s:", unname, -result)); return(result); } static void free_dir_stuff(struct stat *stb, int complete) { NW_DIR *d=&(dirs[0]); int j = -1; if (complete) { while (++j < (int)used_dirs){ if ( d->dev == stb->st_dev && d->inode == stb->st_ino) d->inode = 0; d++; } j = -1; } while (++j < (int)anz_dirhandles){ DIR_HANDLE *dh=&(dir_handles[j]); if (dh && dh->dev == stb->st_dev && dh->inode == stb->st_ino) { if (complete) free_dir_handle(j+1); else if (dh->f) { /* only close directories */ /* needed to ask for null pointer, hint from Boris Popov, 21-Feb-99 */ closedir(dh->f); dh->f = (DIR*)NULL; } } } } int nw_set_file_information(int dir_handle, uint8 *data, int len, int searchattrib, NW_FILE_INFO *f) { NW_PATH nwpath; struct stat stbuff; int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0); if (completition > -1) { FUNC_SEARCH fs; fs.ubuf = (uint8*)f; completition = func_search_entry(&nwpath, searchattrib, do_set_file_info, &fs); if (completition < 0) return(completition); else if (!completition) return(-0xff); } return(completition); } int nw_set_file_attributes(int dir_handle, uint8 *data, int len, int attrib, int newattrib) { char unname[256]; struct stat stbuff; int completition=-0x9c; NW_PATH nwpath; #if PERSISTENT_SYMLINKS S_STATB stb; #endif build_path(&nwpath, data, len, 0); if (nwpath.fn[0] != '.') { /* Files with . at the beginning are not ok */ completition = build_dir_name(&nwpath, &stbuff, dir_handle); } if (completition < 0) return(completition); xstrcpy(unname, build_unix_name(&nwpath, 2)); XDPRINTF((5,0,"set file attrib 0x%x, unname:%s:", newattrib, unname)); if (!s_stat(unname, &stbuff, &stb)){ int result = set_nw_attrib_byte(nwpath.volume, unname, &stbuff, newattrib); return( (result != 0) ? -0x8c : 0); /* no modify rights */ } return(-0x9c); /* wrong path */ } static int nw_rmdir(uint8 *unname) { if (rmdir(unname)) { if (errno == /*EEXIST*/ ENOTEMPTY) return(-0xa0); /* directory not empty */ return(-0x8a); /* no privilegs */ } return(0); } int nw_unlink_node(int volume, uint8 *unname, struct stat *stb) { int result=-1; uint32 attrib=get_nw_attrib_dword(volume, unname, stb); /* first we look for attributes */ if (attrib & (FILE_ATTR_R|FILE_ATTR_DELETE_INH)) return(-0x8a); /* don't delete 'readonly' */ if (tru_eff_rights_exists(volume, unname, stb, TRUSTEE_E)) return(-0x8a); /* no delete rights */ if (S_ISDIR(stb->st_mode)) { /* directory */ free_dir_stuff(stb, 0); result=nw_rmdir(unname); if (result==-0x8a){ /* no privilegs */ seteuid(0); result=nw_rmdir(unname); reseteuid(); } if (!result) free_dir_stuff(stb, 1); } else { /* changed by: Ingmar Thiemann * because share_file() changed */ if (!(entry8_flags&0x10) && -1 == share_file(stb->st_dev, stb->st_ino, 0x10f, 2)) return(-0x8a); /* NO Delete Privileges, file is open */ if (0 != (result=unlink(unname))){ seteuid(0); result=unlink(unname) ? -0x8a : 0; reseteuid(); } } if (!result) { free_nw_ext_inode(volume, unname, stb->st_dev, stb->st_ino); } return(result); } int nw_creat_node(int volume, uint8 *unname, int mode) /* creat file or directory, depending on mode */ /* mode & 0x1 == directory */ /* mode & 0x2 == creat/trunc */ /* next is only for file creation, needed by some queue functions */ /* mode & 0x8 == ignore rights, try to open as root */ { struct stat stb; uint8 path[260]; uint8 *p=path+strlen(unname); xstrcpy(path, unname); while (p > path && *p != '/') --p; if (p > path) { *p='\0'; if (stat(path, &stb)) return(-0x9c); } else if (*p=='/') { *(p+1)='.'; *(p+2)='\0'; if (stat(path, &stb)) return(-0x9c); } else return(-0x9c); if (mode & 1) { /* directory */ int result=-0xff; if (!tru_eff_rights_exists(volume, path, &stb, TRUSTEE_C)){ result=mkdir(unname, 0777); if (result) { seteuid(0); if (0==(result=mkdir(unname, 0755))) chown(unname, act_uid, act_gid); reseteuid(); } if (result) result=-0xff; } else result=-0x84; /* no creat rights */ if (!result) { int umode_dir=get_volume_umode_dir(volume); if (umode_dir) { if (umode_dir == -1) /* we get parent dir */ umode_dir=stb.st_mode; seteuid(0); chmod(unname, umode_dir); reseteuid(); } } return(result); } else { /* file */ int fd=-1; struct stat stbuff; int exist; seteuid(0); exist=stat(unname, &stbuff) ? 0 : 1; reseteuid(); if (!(mode&0x8)) { /* we must test for access */ if (exist) { /* test for write rights */ if (get_nw_attrib_dword(volume, unname, &stbuff) & FILE_ATTR_R) return(-0x94); /* No write rights */ if (tru_eff_rights_exists(volume, unname, &stbuff, TRUSTEE_W)) return(-0x94); /* No write rights */ } else { /* test for creat rights */ if (tru_eff_rights_exists(volume, path, &stb, TRUSTEE_C)) return(-0x84); /* No creat rights */ } } if (mode & 2 || (exist && (mode&0x8)) ) { /* trunc */ if (0 > (fd=open(unname, O_CREAT|O_TRUNC|O_RDWR, 0666))) { seteuid(0); if (-1 < (fd=open(unname, O_CREAT|O_TRUNC|O_RDWR, 0600))) chown(unname, act_uid, act_gid); reseteuid(); } } else if (!exist) { if (0 > (fd = creat(unname, 0777))) { seteuid(0); if (-1 < (fd = creat(unname, 0751))) chown(unname, act_uid, act_gid); reseteuid(); } } if ( fd > -1 ) { int umode_file=get_volume_umode_file(volume); close(fd); if (umode_file > 0) chmod(unname, umode_file); return(0); } } return(-0xff); } int nw_utime_node(int volume, uint8 *unname, struct stat *stb, time_t t) { if (!tru_eff_rights_exists(volume, unname, stb, TRUSTEE_M)){ struct utimbuf ut; ut.actime = ut.modtime = t; if (!utime(unname, &ut)) return(0); seteuid(0); if (!utime(unname, &ut)) { reseteuid(); return(0); } reseteuid(); } return(-0x8c); /* no modify privileges */ } int nw_mk_rd_dir(int dir_handle, uint8 *data, int len, int mode) { NW_PATH nwpath; struct stat stbuff; int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, (mode) ? 0 : 1 ); if (completition > -1) { char unname[256]; xstrcpy(unname, build_unix_name(&nwpath, 2)); if (mode) { completition=nw_creat_node(nwpath.volume, unname, 1); } else { /* rmdir */ if (!stat(unname, &stbuff)) completition=nw_unlink_node(nwpath.volume, unname, &stbuff); else completition=-0x9c; } } return(completition); } int mv_dir(int dir_handle, uint8 *sourcedata, int sourcedatalen, uint8 *destdata, int destdatalen) { NW_PATH quellpath; struct stat qstbuff; NW_PATH zielpath; int completition=conn_get_kpl_path(&quellpath, &qstbuff, dir_handle, sourcedata, sourcedatalen, 0); if (completition > -1){ char qfn[256]; char zpath[256]; struct stat zstbuff; completition = 0; xstrcpy(qfn, build_unix_name(&quellpath,0)); memcpy(&zielpath, &quellpath, sizeof(NW_PATH)); strmaxcpy(zielpath.fn, destdata, destdatalen); /* patch from Sven Norinder :09-Nov-96 */ if (get_volume_options(zielpath.volume) & VOL_OPTION_DOWNSHIFT) down_fn(zielpath.fn); else up_fn(zielpath.fn); #if 0 /* this is not possible ---- */ completition=conn_get_kpl_path(&zielpath, &zstbuff, dir_handle, destdata, destdatalen, 0); /* ----------- because ----- */ /* for example the novell rendir.exe does something like this * 0x0,0xd,0xf,0x0,0x7,'T','M','P',':','\','I','I',0x2,'K','K' * no dirhandle, qpath = fullpath, zpath = only name */ #endif xstrcpy(zpath, build_unix_name(&zielpath, 1)); if (stat(qfn, &qstbuff) || tru_eff_rights_exists(quellpath.volume, qfn, &qstbuff, TRUSTEE_W|TRUSTEE_M|TRUSTEE_R)) completition=-0x8b; else if (stat(zpath, &zstbuff) || tru_eff_rights_exists(zielpath.volume, zpath, &zstbuff, TRUSTEE_W)) completition=-0x8b; if (completition > -1){ int result; char unziel[256]; xstrcpy(unziel, build_unix_name(&zielpath, 0)); seteuid(0); result = unx_mvdir((uint8 *)qfn, (uint8 *)unziel); reseteuid(); XDPRINTF((4,0, "rendir result=%d, '%s'->'%s'", result, qfn, unziel)); if (!result) completition = 0; else { if (result == EEXIST) completition=-0x92; /* allready exist */ else if (result == EXDEV) completition=-0x9a; /* cross devices */ else completition=-0x9c; /* wrong path */ } } } return(completition); } static int change_dir_entry( NW_DIR *dir, int volume, uint8 *path, int dev, ino_t inode, int driveletter, int is_temp, int new_entry, int task) { if (new_entry || (dir->inode && dir->is_temp != 2)) { int len; if (*path=='/' && *(path+1) != '\0') path++; len=strlen(path); if (dir->path) xfree(dir->path); dir->path=xmalloc(len+2); if (len) { memcpy(dir->path, path, len); if (dir->path[len-1] != '/') { *(dir->path + len) = '/'; ++len; } } else { *(dir->path) = '/'; ++len; } *(dir->path+len) = '\0'; dir->dev = dev; dir->inode = inode; dir->volume = (uint8) volume; dir->timestamp = time(NULL); if (driveletter > -1) { dir->drive = (uint8) driveletter; dir->task = (uint8)task; } else { if (task < (int)dir->task) dir->task = (uint8) task; } if (is_temp > -1) dir->is_temp = (uint8) is_temp; return(0); } else { if (!dir->inode) return(-0x9b); /* wrong handle */ else return(-0xfa); /* temp remap Error */ } } void nw_exit_connect(void) { if (connect_is_init) { init_file_module(-1); } #if WITH_NAME_SPACE_CALLS exit_name_space_module(); #endif } int nw_init_connect(void) /* May be called when ever you want */ { uint8 *login = (uint8*) "LOGIN/"; NW_PATH nwlogin; FILE *f= open_nw_ini(); if (f != (FILE*) NULL){ uint8 buff[256]; struct stat stbuff; int what; int k = MAX_NW_DIRS; NW_DIR *d = &(dirs[0]); int namspace_max_baseh=0; int namspace_max_searchh=0; xstrcpy(nwlogin.path, (char*)login); nwlogin.fn[0] = '\0'; nwlogin.volume = 0; while (k--) { if (connect_is_init) xfree(d->path); else d->path = NULL; d->volume = 0; d->inode = 0; d->is_temp = 0; d->drive = 0; d++; } init_file_module(-1); if (connect_is_init) { k = 0; while (k++ < anz_dirhandles) free_dir_handle(k); } else connect_is_init++; while (0 != (what = get_ini_entry(f, 0, buff, sizeof(buff)))) { if (what == 6) { /* version */ if (2 != sscanf((char*)buff, "%d %x", &tells_server_version, &server_version_flags)) server_version_flags=0; } else if (what == 8) { /* entry8_flags */ entry8_flags = hextoi((char*)buff); } else if (what == 9) { /* umode */ uint8 buf1[300], buf2[300]; if (2 == sscanf((char*)buff, "%300s %300s", buf1, buf2)) { default_umode_dir = octtoi(buf1); default_umode_file = octtoi(buf2); } } else if (what == 10) { /* GID */ default_gid = atoi((char*)buff); } else if (what == 11) { /* UID */ default_uid = atoi((char*)buff); } else if (what == 30) { /* Burstmodus */ int recvsize, sendsize; int i= sscanf((char*)buff, "%i %i", &recvsize, &sendsize); if (i>0){ max_burst_recv_size=recvsize; if (i>1) max_burst_send_size=sendsize; } } else if (what == 31) { /* entry31_flags */ entry31_flags = hextoi((char*)buff); } else if (50 == what) { init_nwfname(buff); } else if (63 == what) { /* MAX_DIR_BASE */ namspace_max_baseh=atoi(buff); } else if (68 == what) { /* USE_MMAP */ use_mmap=atoi(buff); } else if (80 == what) { namspace_max_searchh=atoi(buff); } else if (what == 103) { /* Debug */ get_debug_level(buff); } } /* while */ nw_init_volumes(f); fclose(f); #if WITH_NAME_SPACE_CALLS init_name_space_module(namspace_max_baseh, namspace_max_searchh); #endif if (used_nw_volumes < 1) { errorp(1, "No Volumes defined. Look at ini file entry 1, Abort !!", NULL); return(-1); } if (get_volume_options(0) & VOL_OPTION_DOWNSHIFT) down_fn(nwlogin.path); if (stat(build_unix_name(&nwlogin, 0), &stbuff)) { errorp(1, "Stat error LOGIN Directory, Abort !!", "UnixPath=`%s`, nwlogin.path=%s, nwlogin.fn=%s", build_unix_name(&nwlogin, 0), nwlogin.path, nwlogin.fn ); return(-1); } (void)change_dir_entry(&(dirs[0]), 0, nwlogin.path, stbuff.st_dev, stbuff.st_ino, 0, 0, 1, 0); /* first Handle must be known und must not be temp */ /* and has no Drive-Character */ used_dirs = 1; anz_dirhandles = 0; return(0); } else return(-1); } int nw_free_handles(int task) /* * if task== -1 then all is initialized * else the temp handles of the actual task * are deleted. I hope this is right. !?? */ { if (task == -1) return(nw_init_connect()); else { NW_DIR *d = &(dirs[0]); int k = used_dirs; while (k--) { if (d->is_temp && d->task == task) { /* only actual task */ xfree(d->path); d->volume = 0; d->inode = 0; d->is_temp = 0; d->drive = 0; } d++; } for (k=0; k < anz_dirhandles; k++){ DIR_HANDLE *dh=&(dir_handles[k]); if (dh->f) { closedir(dh->f); dh->f=NULL; } } init_file_module(task); } return(0); } int xinsert_new_dir(int volume, uint8 *path, int dev, int inode, int drive, int is_temp, int task) { int j = 0; int freehandle = 0; #if 0 time_t lowtime = time(NULL); int timedhandle = 0; #endif /* first look, whether drive is allready in use */ for (j = (used_dirs) ? 1 : 0; j < (int)used_dirs; j++) { NW_DIR *d = &(dirs[j]); if (!d->inode) freehandle = j+1; #if 0 } else if (d->is_temp && d->timestamp < lowtime) { timedhandle = j+1; lowtime = d->timestamp; } #endif } if (!freehandle && used_dirs < MAX_NW_DIRS) freehandle = ++used_dirs; #if 0 if (!freehandle) freehandle = timedhandle; #endif if (freehandle){ (void)change_dir_entry(&(dirs[freehandle-1]), volume, path, dev, inode, drive, is_temp, 1, task); while (used_dirs > freehandle && !dirs[used_dirs-1].inode) used_dirs--; return(freehandle); } else return(-0x9d); /* no dir Handles */ } static int insert_new_dir(NW_PATH *nwpath, int dev, int inode, int drive, int is_temp, int task) { return(xinsert_new_dir(nwpath->volume, nwpath->path, dev, inode, drive, is_temp, task)); } int nw_search(uint8 *info, uint32 *fileowner, int dirhandle, int searchsequence, int search_attrib, uint8 *data, int len) { NW_PATH nwpath; struct stat stbuff; int completition = conn_get_kpl_path(&nwpath, &stbuff, dirhandle, data, len, 0); XDPRINTF((5,0,"nw_search path:%s:, fn:%s:, completition:0x%x", nwpath.path, nwpath.fn, completition)); if (completition > -1) { struct stat stbuff; completition=get_dir_entry(&nwpath, &searchsequence, search_attrib, &stbuff); if (!completition) { char unixname[300]; xstrcpy(unixname, build_unix_name(&nwpath, 0)); if ( S_ISDIR(stbuff.st_mode) ) { get_dir_attrib((NW_DIR_INFO*)info, unixname, &stbuff, &nwpath); } else { get_file_attrib((NW_FILE_INFO*)info, unixname, &stbuff, &nwpath); } if (fileowner) *fileowner = get_file_owner(&stbuff); return(searchsequence); } } return(completition); } int nw_dir_get_vol_path(int dirhandle, uint8 *path) /* returns volume or error ( < 0) */ { int result; NW_DIR *dir = (dirhandle > 0 && dirhandle <= used_dirs) ? &(dirs[dirhandle-1]) : NULL; if (dir && dir->inode) { int llen = strlen(dir->path); uint8 *p = path+llen; result = dir->volume; memcpy(path, dir->path, llen+1); if (llen && *(p-1) == '/') *(p-1) = '\0'; if (result < 0) result = -0x98; /* wrong volume */ } else result = -0x9b; return(result); } int nw_dir_search(uint8 *info, int dirhandle, int searchsequence, int search_attrib, uint8 *data, int len) { NW_PATH nwpath; int completition=-0x9c; build_path(&nwpath, data, len, 0); if (dirhandle > 0 && --dirhandle < anz_dirhandles){ DIR_HANDLE *dh = &(dir_handles[dirhandle]); char unixname[300]; struct stat stbuff; if (dh->vol_options & VOL_OPTION_DOWNSHIFT) { down_fn(nwpath.fn); } else { up_fn(nwpath.fn); } nwpath.volume=dh->volume; if (get_dh_entry(dh, nwpath.fn, sizeof(nwpath.fn), &searchsequence, search_attrib, unixname, sizeof(unixname), &stbuff)){ if ( S_ISDIR(stbuff.st_mode) ) { get_dir_attrib((NW_DIR_INFO*)info, unixname, &stbuff, &nwpath); } else { if (dh->vol_options & VOL_OPTION_IS_PIPE) stbuff.st_size = 0x70000000|(stbuff.st_mtime&0xfffffff); get_file_attrib((NW_FILE_INFO*)info, unixname, &stbuff, &nwpath); } return(searchsequence); } else return(-0xff); /* not found */ } else return(completition); /* wrong path */ } int nw_alloc_dir_handle( int dir_handle, /* source directory handle */ uint8 *data, /* source path */ int len, /* pathlen */ int driveletter, /* A .. Z normal */ int is_temphandle, /* temp handle = 1 */ /* special temp handle = 2 */ int task, /* process task */ int *eff_rights) { NW_PATH nwpath; struct stat stbuff; int inode=conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 1); if (inode > -1) { uint8 unixname[257]; xstrcpy(unixname, build_unix_name(&nwpath, 0)); inode = insert_new_dir(&nwpath, stbuff.st_dev, stbuff.st_ino, driveletter, is_temphandle, task); *eff_rights=tru_get_eff_rights(nwpath.volume, unixname, &stbuff); } XDPRINTF((4,0,"Allocate %shandle:%s, Qhandle=%d, drive=%d, Task=%d, result=0x%x", (is_temphandle) ? "Temp" : "Perm", conn_get_nwpath_name(&nwpath), dir_handle, driveletter, task, inode)); return(inode); } int nw_open_dir_handle( int dir_handle, uint8 *data, /* extra path */ int len, /* len of DATA */ int *volume, /* Volume */ int *dir_id, int *searchsequence) /* * Routine returns handle to use in searchroutines. * RETURN=errcode ( <0 ) or eff. ACCES Rights */ { NW_PATH nwpath; struct stat stbuff; int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 1); if (completition > -1) { XDPRINTF((5,0,"NW_OPEN_DIR: completition = 0x%x; nwpath= %s", (int)completition, conn_get_nwpath_name(&nwpath) )); completition = new_dir_handle(&stbuff, &nwpath); if (completition > -1) { struct stat stb; DIR_HANDLE *dh = &(dir_handles[completition-1]); s_stat(dh->unixname, &stb, NULL); *volume = dh->volume; *dir_id = completition; *searchsequence = MAX_U16; completition = tru_get_eff_rights(dh->volume, dh->unixname, &stb); } XDPRINTF((5,0,"NW_OPEN_DIR_2: completition = 0x%x", completition)); } else { XDPRINTF((4,0,"NW_OPEN_DIR failed: completition = -0x%x", -completition)); } return(completition); } int nw_free_dir_handle(int dir_handle, int task) { if (dir_handle && --dir_handle < (int)used_dirs) { NW_DIR *d=&(dirs[dir_handle]); XDPRINTF((4,0,"free dhandle:%d, task=%d, d->inode=0x%x, used_dirs=%d", dir_handle+1, task, d->inode, used_dirs)); if (!d->inode #if 0 || d->task != task #endif ) return(-0x9b); /* wrong handle */ else { d->inode = 0; xfree(d->path); } return(0); } else return(-0x9b); /* wrong handle */ } int alter_dir_handle(int targetdir, int volume, uint8 *path, int dev, int inode, int task) /* targetdir will be changed */ { if (targetdir > 0 && --targetdir < used_dirs && dirs[targetdir].is_temp != 2) { /* do not change special temphandles */ XDPRINTF((5,0,"Change dhandle:%d(%d) -> '%d:%s'", targetdir+1, task, volume, path)); return(change_dir_entry(&dirs[targetdir], volume, path, dev, inode, -1, -1, 0, task)); /* here the existing handle is only modified */ } else return(-0x9b); /* BAD DIR Handle */ } int nw_set_dir_handle(int targetdir, int dir_handle, uint8 *data, int len, int task) /* targetdirs gets path of dirhandle + data */ { NW_PATH nwpath; struct stat stbuff; int inode = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 1); if (inode > -1) inode = alter_dir_handle(targetdir, nwpath.volume, nwpath.path, stbuff.st_dev, stbuff.st_ino, task); return(inode); /* invalid PATH */ } int nw_get_directory_path(int dir_handle, uint8 *name, int size_name) { int result = -0x9b; name[0] = '\0'; if (dir_handle > 0 && --dir_handle < (int)used_dirs && dirs[dir_handle].inode) { int volume = dirs[dir_handle].volume; if (volume > -1 && volume < used_nw_volumes){ result = slprintf((char*)name, size_name-1, "%s:%s", nw_volumes[volume].sysname, dirs[dir_handle].path); if (result > 0) { if (name[result-1] == '/') name[--result] = '\0'; up_fn(name); } else result= -0x9c; /* wrong path */ } else result = -0x98; } XDPRINTF((5,0,"nw_get_directory_path:%s: Handle=%d, result=0x%x", name, dir_handle+1, result)); return(result); } int nw_get_vol_number(int dir_handle) /* Get Volume Nummmer with Handle */ { int result = -0x9b; /* wrong handle */ if (dir_handle > 0 && --dir_handle < (int)used_dirs && dirs[dir_handle].inode ) { result = dirs[dir_handle].volume; if (result < 0 || result >= used_nw_volumes) result = -0x98; /* wrong volume */ } XDPRINTF((5,0,"nw_get_vol_number:0x%x: von Handle=%d", result, dir_handle+1)); return(result); } int nw_get_eff_dir_rights(int dir_handle, uint8 *data, int len, int modus) /* modus 0=only_dir, 1=dirs and files */ { char unname[256]; struct stat stbuff; NW_PATH nwpath; int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0); if (completition < 0) return(completition); xstrcpy(unname, build_unix_name(&nwpath, 0)); if (s_stat(unname, &stbuff, NULL) || (!modus && !S_ISDIR(stbuff.st_mode)) ) { completition = -0x9c; } else completition=tru_get_eff_rights(nwpath.volume, unname, &stbuff); return(completition); } int nw_creat_open_file(int dir_handle, uint8 *data, int len, NW_FILE_INFO *info, int attrib, int access, int creatmode, int task) /* * creatmode: 0 = open | 1 = creat | 2 = creatnew & 4 == save handle * attrib ?? * access: 0x1=read, 0x2=write */ { NW_PATH nwpath; struct stat stbuff; int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0); if (completition > -1) { char unixname[300]; xstrcpy(unixname, build_unix_name(&nwpath, 0)); completition=file_creat_open(nwpath.volume, (uint8*)unixname, &stbuff, attrib, access, creatmode, task); if (completition > -1) get_file_attrib(info, unixname, &stbuff, &nwpath); } return(completition); } static int s_nw_scan_dir_info(int dir_handle, uint8 *data, int len, uint8 *subnr, uint8 *subname, uint8 *subdatetime, uint8 *owner, uint8 *wild) { int volume; int searchsequence; int dir_id; int rights = nw_open_dir_handle(dir_handle, data, len, &volume, &dir_id, &searchsequence); if (rights > -1) { DIR_HANDLE *dh = &(dir_handles[dir_id-1]); struct stat stbuff; uint16 dirsequence = GET_BE16(subnr); uint16 aktsequence = 0; uint8 dirname[256]; if (!dirsequence) dirsequence++; if (dh->vol_options & VOL_OPTION_DOWNSHIFT) { down_fn(wild); } else { up_fn(wild); } xstrcpy(dirname, (char*)wild); XDPRINTF((5,0,"SCAN_DIR: rights = 0x%x, subnr = %d", (int)rights, (int)GET_BE16(subnr))); if (*dirname) { char unixname[300]; while ( get_dh_entry( dh, dirname, sizeof(dirname), &searchsequence, 0x10, unixname, sizeof(unixname), &stbuff) ) { XDPRINTF((5,0,"SCAN_DIR: von %s, found %s:", dh->unixname, dirname)); if (++aktsequence == dirsequence) { /* actual found */ U16_TO_BE16(aktsequence, subnr); up_fn(dirname); strncpy((char*)subname, (char*)dirname, 16); U32_TO_BE32(get_file_owner(&stbuff), owner); un_date_2_nw(stbuff.st_mtime, subdatetime, 1); un_time_2_nw(stbuff.st_mtime, subdatetime+2, 1); return(tru_get_inherited_mask(volume, unixname, &stbuff)); } xstrcpy(dirname, (char*)wild); } /* while */ } else { *(dh->kpath) = '.'; *(dh->kpath+1) = '\0'; if (!s_stat(dh->unixname, &stbuff, NULL)) { U16_TO_BE16(1, subnr); memset(subname, 0, 16); U32_TO_BE32(get_file_owner(&stbuff), owner); un_date_2_nw(stbuff.st_mtime, subdatetime, 1); un_time_2_nw(stbuff.st_mtime, subdatetime+2, 1); return(tru_get_inherited_mask(volume, dh->unixname, &stbuff)); } } /* return(-0x9c); NO MORE INFO */ return(-0xff); } return(rights); } int nw_scan_dir_info(int dir_handle, uint8 *data, int len, uint8 *subnr, uint8 *subname, uint8 *subdatetime, uint8 *owner) { int k = len; uint8 *p = data+len; uint8 dirname[256]; while (k) { uint8 c = *--p; if (c == '/' || c == '\\' || c == ':') { p++; break; } --k; } if (len && k < len) { strmaxcpy(dirname, p, len-k); len = k; } else dirname[0] = '\0'; XDPRINTF((7, 0, "nw_scan_dir_info, dirname=`%s`, len=%d, k=%d", dirname, len , k)); return(s_nw_scan_dir_info(dir_handle, data, len, subnr, subname, subdatetime, owner, dirname)); } void get_dos_file_attrib(NW_DOS_FILE_INFO *f, struct stat *stb, int volume, uint8 *path, char *unixname) { uint8 spath[14]; uint32 nw_owner=get_file_owner(stb); f->namlen=min(strlen((char*)path), 12); strmaxcpy(spath, path, 12); up_fn(spath); strncpy((char*)f->name, (char*)spath, f->namlen); U32_TO_32(get_nw_attrib_dword(volume, unixname, stb), f->attributes); U16_TO_16(tru_get_inherited_mask(volume, unixname, stb), f->inherited_rights_mask); un_date_2_nw(stb->st_mtime, f->created.date, 0); un_time_2_nw(stb->st_mtime, f->created.time, 0); U32_TO_BE32(nw_owner, f->created.id); un_date_2_nw(stb->st_mtime, f->updated.date, 0); un_time_2_nw(stb->st_mtime, f->updated.time, 0); U32_TO_BE32(nw_owner, f->updated.id); un_date_2_nw(stb->st_atime, f->last_access_date, 0); U32_TO_32(stb->st_size, f->size); } void get_dos_dir_attrib(NW_DOS_DIR_INFO *f, struct stat *stb, int volume, uint8 *path, char *unixname) { uint8 spath[14]; f->namlen=min(strlen((char*)path), 12); strmaxcpy(spath, path, 12); up_fn(spath); strncpy((char*)f->name, (char*)spath, f->namlen); U32_TO_32(get_nw_attrib_dword(volume, unixname, stb), f->attributes); U16_TO_16(tru_get_inherited_mask(volume, unixname, stb), f->inherited_rights_mask); un_date_2_nw(stb->st_mtime, f->created.date,0); un_time_2_nw(stb->st_mtime, f->created.time,0); U32_TO_BE32(get_file_owner(stb), f->created.id); un_date_2_nw(stb->st_mtime, f->modify_date, 0); un_time_2_nw(stb->st_mtime, f->modify_time, 0); U32_TO_BE32(MAX_U32, f->max_space); } int nw_scan_a_directory(uint8 *rdata, int dirhandle, uint8 *data, int len, int searchattrib, uint32 searchbeg) /* 32 bit */ { NW_PATH nwpath; struct stat stbuff; int completition = conn_get_kpl_path(&nwpath, &stbuff, dirhandle, data, len, 0); XDPRINTF((5,0,"nw_scan_a_directory path:%s:, fn:%s:, completition:0x%x", nwpath.path, nwpath.fn, completition)); if (completition > -1) { int searchsequence = (searchbeg == MAX_U32) ? MAX_U16 : searchbeg; completition=get_dir_entry(&nwpath, &searchsequence, searchattrib, &stbuff); if (!completition) { char unixname[300]; NW_SCAN_DIR_INFO *scif = (NW_SCAN_DIR_INFO*)rdata; xstrcpy(unixname, build_unix_name(&nwpath, 0)); memset(rdata, 0, sizeof(NW_SCAN_DIR_INFO)); U32_TO_BE32((uint32)searchsequence, scif->searchsequence); XDPRINTF((5,0, "nw_scan_a_directory = %s, uid=%d, gid=%d", conn_get_nwpath_name(&nwpath), stbuff.st_uid, stbuff.st_gid)); if ( S_ISDIR(stbuff.st_mode)) { get_dos_dir_attrib(&(scif->u.d), &stbuff, nwpath.volume, nwpath.fn, unixname); } else { get_dos_file_attrib(&(scif->u.f), &stbuff, nwpath.volume, nwpath.fn, unixname); } return(sizeof(NW_SCAN_DIR_INFO)); } } return(completition); /* wrong path */ } int nw_scan_a_root_dir(uint8 *rdata, int dirhandle) { NW_PATH nwpath; struct stat stbuff; uint8 data[2]; int completition = conn_get_kpl_path(&nwpath, &stbuff, dirhandle, data, 0, 1); XDPRINTF((5,0,"nw_scan_a_root_directory_2 path:%s:, fn:%s:, completition:0x%x", nwpath.path, nwpath.fn, completition)); if (completition > -1) { char unixname[300]; xstrcpy(unixname, build_unix_name(&nwpath, 2)); if (!s_stat(unixname, &stbuff, NULL)) { NW_DOS_DIR_INFO *d=(NW_DOS_DIR_INFO*)rdata; memset(rdata, 0, sizeof(NW_DOS_DIR_INFO)); get_dos_dir_attrib(d, &stbuff, nwpath.volume, nwpath.fn, unixname); return(sizeof(NW_DOS_DIR_INFO)); } else return(-0xff); /* not found */ } else return(completition); /* wrong path */ } int nw_set_a_directory_entry(int dirhandle, uint8 *data, int len, int searchattrib, uint32 searchbeg, NW_SET_DIR_INFO *f) { NW_PATH nwpath; struct stat stbuff; int completition = conn_get_kpl_path(&nwpath, &stbuff, dirhandle, data, len, 0); XDPRINTF((5,0,"nw_set_a_directory_entry path:%s:, fn:%s:, completition:0x%x", nwpath.path, nwpath.fn, completition)); if (completition > -1) { int searchsequence = MAX_U16; /* (searchbeg == MAX_U32) ? MAX_U16 : searchbeg; */ completition=get_dir_entry(&nwpath, &searchsequence, searchattrib, &stbuff); if (!completition) { char unixname[300]; uint32 change_mask=GET_32(f->change_bits); xstrcpy(unixname,build_unix_name(&nwpath, 0)); if (change_mask & 0x2) { completition=set_nw_attrib_dword(nwpath.volume, unixname, &stbuff, GET_32(f->u.f.attributes)); } if (S_ISDIR(stbuff.st_mode)) { if (change_mask & 0x1000) { int result=tru_set_inherited_mask(nwpath.volume, unixname, &stbuff, GET_16(f->u.d.inherited_rights_mask)); if (result) completition=result; } } else { if (change_mask & 0x1000) { int result=tru_set_inherited_mask(nwpath.volume, unixname, &stbuff, GET_16(f->u.f.inherited_rights_mask)); if (result) completition=result; } } } } return(completition); } static int my_match(uint8 *s, uint8 *p) { int len=0; int dot=0; for (; *s && *p; s++,p++) { if (len == 12) return(0); if (*s == '.') { if (dot) return(0); dot++; } else if (dot) { if (dot++ > 3) return(0); } else if (len == 8) return(0); if (!ufn_imatch(*s, *p)) return(0); ++len; } return( ((!*s) && (*p=='/' || *p == '\0')) ? len : 0); } static int get_match(uint8 *unixname, uint8 *p) { DIR *d; uint8 *pp; #if 0 uint8 *p1; int inode=0; #endif if (!p || !*p) return(1); *p = '\0'; pp=p+1; while (*pp == '/') ++pp; #if 0 p1=strchr(pp, '/'); if (!p1) p1=pp+strlen(pp); if (p1 > pp+4 && *(p1-4) == '.' && *(p1-3) == '_' && *(p1-2) == '_' && *(p1-1) == '_' ) { *(p1-4) = '\0'; inode=atoi(pp); *(p1-4) = '.'; } #endif seteuid(0); d=opendir(unixname); reseteuid(); if (NULL != d) { struct dirent *dirbuff; XDPRINTF((10, 0, "opendir OK unixname='%s' pp='%s'", unixname, pp)); *p = '/'; while ((dirbuff = readdir(d)) != (struct dirent*)NULL){ int len; if (dirbuff->d_ino) { XDPRINTF((10, 0, "get match found d_name='%s'", dirbuff->d_name)); if ( #if 0 (dirbuff->d_ino ==inode) || #endif 0 != (len=my_match(dirbuff->d_name, pp))) { memcpy(pp, dirbuff->d_name, len); XDPRINTF((10, 0, "get match, match OK")); closedir(d); return(get_match(unixname, pp+len)); } } } closedir(d); } else { XDPRINTF((3, 0, "DOS get_match opendir failed unixname='%s'", unixname)); *p='/'; } return(0); } void mangle_dos_name(NW_VOL *vol, uint8 *unixname, uint8 *pp) { struct stat stb; if (!s_stat(unixname, &stb, NULL)) /* path is ok I hope */ return; get_match(unixname, pp-1); } int nw_add_trustee(int dir_handle, uint8 *data, int len, uint32 id, int trustee, int extended) /* extended 0=add trustee to dir, 1= add ext trustee to dirs and files */ { char unname[256]; struct stat stbuff; NW_PATH nwpath; int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0); if (result < 0) return(result); xstrcpy(unname, build_unix_name(&nwpath, 0)); if (s_stat(unname, &stbuff, NULL) || (!extended && !S_ISDIR(stbuff.st_mode)) ) { result = -0x9c; } else { NW_OIC nwoic; nwoic.id = id; nwoic.trustee = trustee; result=tru_add_trustee_set(nwpath.volume, unname, &stbuff, 1, &nwoic); } return(result); } int nw_del_trustee(int dir_handle, uint8 *data, int len, uint32 id, int extended) /* extended 0=del trustee from dir, 1= del ext trustee from dirs and files */ { char unname[256]; struct stat stbuff; NW_PATH nwpath; int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0); if (result < 0) return(result); xstrcpy(unname, build_unix_name(&nwpath, 0)); if (s_stat(unname, &stbuff, NULL) || (!extended && !S_ISDIR(stbuff.st_mode)) ) { result = -0x9c; } else { result=tru_del_trustee(nwpath.volume, unname, &stbuff, id); } return(result); } int nw_set_dir_info(int dir_handle, uint8 *data, int len, uint32 owner_id, int max_rights, uint8 *creationdate, uint8 *creationtime) { char unname[256]; struct stat stbuff; NW_PATH nwpath; int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len,0); if (result < 0) return(result); xstrcpy(unname, build_unix_name(&nwpath, 0)); if (s_stat(unname, &stbuff, NULL) || !S_ISDIR(stbuff.st_mode)) { result = -0x9c; } else { result=nw_utime_node(nwpath.volume, unname, &stbuff, nw_2_un_time(creationdate, creationtime)); if (!result) result=tru_set_inherited_mask(nwpath.volume, unname, &stbuff, max_rights); } return(result); } int nw_scan_user_trustee(int volume, int *sequence, uint32 id, int *access_mask, uint8 *path) { uint8 volname[100]; int result = nw_get_volume_name(volume, volname, sizeof(volname)); if (result > 0) { if (*sequence==-1 || *sequence==0xffff) *sequence=0; result=get_volume_user_trustee(volume, id, 0, sequence, access_mask, path); } return(result); } int nw_scan_for_trustee( int dir_handle, int sequence, uint8 *path, int len, int max_entries, uint32 *ids, int *trustees, int extended) { char unname[256]; struct stat stbuff; NW_PATH nwpath; int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, path, len, (extended) ? 0 : 1); if (result < 0) return(result); xstrcpy(unname, build_unix_name(&nwpath, 0)); if (s_stat(unname, &stbuff, NULL) || (!extended && !S_ISDIR(stbuff.st_mode)) ) { result = -0x9c; } else { result=tru_get_trustee_set(nwpath.volume, unname, &stbuff, sequence, max_entries, ids, trustees); } return(result); } /* quick and dirty hack for 0.99.pl18, 25-Sep-99 */ int nw_log_file(int lock_flag, int timeout, int dir_handle, int len, char *data) /* * lock_flag * -1 = remove lock * -2 = remove lock + log * 0 = log * 1 = lock exclusive * 3 = shared lock */ { NW_PATH nwpath; struct stat stbuff; int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0); if (completition > -1) { char unixname[300]; xstrcpy(unixname, build_unix_name(&nwpath, 0)); seteuid(0); completition = stat(unixname, &stbuff); reseteuid(); if (!completition) { if (lock_flag < 0) { /* remove lock */ if (lock_flag != -1) completition = share_set_file_add_rm(lock_flag, stbuff.st_dev, stbuff.st_ino); if (!completition) completition = share_file(stbuff.st_dev, stbuff.st_ino, 0x300, 0) ? -0xff : 0; } else if (lock_flag == 0 || lock_flag == 1 || lock_flag == 3) { completition = share_set_file_add_rm(lock_flag, stbuff.st_dev, stbuff.st_ino); if ((!completition) && lock_flag) /* add lock */ completition = share_file(stbuff.st_dev, stbuff.st_ino, lock_flag << 8, 1) ? -0xfe : 0; } else completition = -0xfb; } else completition = -0xff; /* not exist, errorcode TODO ! */ } return(completition); }