Roxen.git / server / modules / filesystems / filesystem.pike

version» Context lines:

Roxen.git/server/modules/filesystems/filesystem.pike:1:   // This is a roxen module. Copyright © 1996 - 2000, Roxen IS.      // This is a virtual "file-system".   // It will be located somewhere in the name-space of the server.   // Also inherited by some of the other filesystems.      inherit "module";   inherit "socket";    - constant cvs_version= "$Id: filesystem.pike,v 1.103 2001/08/13 18:18:48 per Exp $"; + constant cvs_version= "$Id: filesystem.pike,v 1.104 2001/08/15 16:42:53 grubba Exp $";   constant thread_safe=1;      #include <module.h>   #include <roxen.h>   #include <stat.h>   #include <request_trace.h>         //<locale-token project="mod_filesystem">LOCALE</locale-token>   #define LOCALE(X,Y) _DEF_LOCALE("mod_filesystem",X,Y)
Roxen.git/server/modules/filesystems/filesystem.pike:25:   #else   # define FILESYSTEM_WERR(X)   #endif      #ifdef QUOTA_DEBUG   # define QUOTA_WERR(X) werror("QUOTA: "+X+"\n")   #else   # define QUOTA_WERR(X)   #endif    + #if constant(system.normalize_path) + #define NORMALIZE_PATH(X) system.normalize_path(X) + #else /* !constant(system.normalize_path) */ + #define NORMALIZE_PATH(X) (X) + #endif /* constant(system.normalize_path) */ +    constant module_type = MODULE_LOCATION;   LocaleString module_name = LOCALE(51,"File systems: Normal File system");   LocaleString module_doc =   LOCALE(2,"This is the basic file system module that makes it possible "    "to mount a directory structure in the virtual file system of "    "your site.");   constant module_unique = 0;      int redirects, accesses, errors, dirlists;   int puts, deletes, mkdirs, moves, chmods;
Roxen.git/server/modules/filesystems/filesystem.pike:165:       defvar("internal_files", ({}), LOCALE(43,"Internal files"), TYPE_STRING_LIST,    LOCALE(44,"A list of glob patterns that matches files which should be "    "considered internal. Internal files cannot be requested "    "directly from a browser, won't show up in directory listings "    "and can never be uploaded, moved or deleted by a browser."    "They can only be accessed internally, e.g. with the RXML tags"    " <tt>&lt;insert&gt;</tt> and <tt>&lt;use&gt;</tt>."));   }    - string path, mountpoint, charset, path_encoding; + string path, mountpoint, charset, path_encoding, normalized_path;   int stat_cache, dotfiles, access_as_user, no_symlinks, tilde;   array(string) internal_files;      void start()   {    tilde = query("tilde");    charset = query("charset");    path_encoding = query("path_encoding");    no_symlinks = query("no_symlinks");    access_as_user = query("access_as_user");    dotfiles = query(".files");    path = query("searchpath");    mountpoint = query("mountpoint");    stat_cache = query("stat_cache");    internal_files = query("internal_files"); -  + #if constant(system.normalize_path) +  if (catch { +  if ((<'/','\\'>)[path[-1]]) { +  normalized_path = system.normalize_path(path + "."); +  } else { +  normalized_path = system.normalize_path(path); +  } + #ifdef __NT__ +  normalized_path += "\\"; + #else /* !__NT__ */ +  normalized_path += "/"; + #endif /* __NT__ */ +  }) { +  report_error(LOCALE(0, "Path verification of %s failed.\n"), mountpoint); +  normalized_path = path; +  } + #else /* !constant(system.normalize_path) */ +  normalized_path = path; + #endif /* constant(system.normalize_path) */    FILESYSTEM_WERR("Online at "+query("mountpoint")+" (path="+path+")");    cache_expire("stat_cache");   }      string query_location()   {    return mountpoint;   }      
Roxen.git/server/modules/filesystems/filesystem.pike:224:    /* No security currently in this function */    fs = file_stat(decode_path(f));    privs = 0;    if(!stat_cache) return fs;    cache_set("stat_cache", f, ({fs}));    return fs;   }      string real_file( string f, RequestID id )   { -  if(stat_file( f, id )) -  return path + f; +  if(stat_file( f, id )) { +  catch { +  return NORMALIZE_PATH(decode_path(path + f)); +  };    } -  + }      int dir_filter_function(string f, RequestID id)   {    if(f[0]=='.' && !dotfiles) return 0;    if(!tilde && Roxen.backup_extension(f)) return 0;    return 1;   }      array(string) list_lock_files() {    return query("nobrowse");
Roxen.git/server/modules/filesystems/filesystem.pike:252:       FILESYSTEM_WERR("find_dir for \""+f+"\"" +    (id->misc->internal_get ? " (internal)" : ""));       object privs;       if (((int)id->misc->uid) && ((int)id->misc->gid) && access_as_user )    // NB: Root-access is prevented.    privs=Privs("Getting dir", (int)id->misc->uid, (int)id->misc->gid );    -  if(!(dir = get_dir( decode_path(path + f) ))) { +  if (catch { +  f = NORMALIZE_PATH(decode_path(path + f)); +  } || !(dir = get_dir(f))) {    privs = 0;    return 0;    }    privs = 0;       if(!query("dir"))    // Access to this dir is allowed.    if(! has_value(dir, ".www_browsable"))    {    errors++;
Roxen.git/server/modules/filesystems/filesystem.pike:383:   {    if( path_encoding != "iso-8859-1" )    p = Locale.Charset.encoder( path_encoding )->feed( p )->drain();   #ifndef __NT__    if( String.width( p ) != 8 )    p = string_to_utf8( p );   #else    while( strlen(p) && p[-1] == '/' )    p = p[..strlen(p)-2];   #endif - #if constant( system.normalize_path ) -  p = system.normalize_path( p ); - #endif +     return p;   }         int _file_size(string X, RequestID id)   {    Stat fs;    if( stat_cache )    {    array(Stat) cached_fs;
Roxen.git/server/modules/filesystems/filesystem.pike:445:    int size;    string tmp;    string oldf = f;       FILESYSTEM_WERR("Request for \""+f+"\"" +    (id->misc->internal_get ? " (internal)" : ""));       /* only used for the quota system, thus rather unessesary to do for    each request....    */ - #define URI combine_path(mountpoint + "/" + f, ".") + #define URI combine_path(mountpoint + "/" + oldf, ".")    -  f = path + f; +  string norm_f;    - // #ifdef __NT__ // fixed in decode_path - // if(f[-1]=='/') f = f[..strlen(f)-2]; - // #endif +  catch { +  /* NOTE: NORMALIZE_PATH() may throw errors. */ +  f = norm_f = NORMALIZE_PATH(f = decode_path(path + f)); + #if constant(system.normalize_path) +  if (!has_prefix(norm_f, normalized_path)) { +  errors++; +  report_error(LOCALE(0, "Path verification of %O failed.\n"), oldf); +  TRACE_LEAVE(""); +  TRACE_LEAVE("Permission denied."); +  return http_low_answer(403, "<h2>File exists, but access forbidden " +  "by user</h2>"); +  } +  +  id->not_query = mountpoint + replace(norm_f[sizeof(normalized_path)..], +  "\\", "/"); + #endif /* constant(system.normalize_path) */ +  }; +     size = _file_size( f, id );       /*    * FIXME: Should probably move path-info extraction here.    * /grubba 1998-08-26    */       switch(id->method)    {    case "GET":
Roxen.git/server/modules/filesystems/filesystem.pike:478:    case 3:    case 4:    TRACE_LEAVE("No file");    return 0; /* Is no-file */       case 2:    TRACE_LEAVE("Is directory");    return -1; /* Is dir */       default: -  if( f[ -1 ] == '/' ) /* Trying to access file with '/' appended */ +  if( oldf[ -1 ] == '/' || /* Trying to access file with '/' appended */ +  !norm_f) { /* Or a file that is not normalizable. */    return 0; -  +  }       if(!id->misc->internal_get)    {    if (!dotfiles    && sizeof (tmp = (id->not_query/"/")[-1])    && tmp[0] == '.')    {    TRACE_LEAVE("Is .-file");    return 0;    }
Roxen.git/server/modules/filesystems/filesystem.pike:506:       TRACE_ENTER("Opening file \"" + f + "\"", 0);       object privs;    if (access_as_user &&    ((int)id->misc->uid) && ((int)id->misc->gid))    // NB: Root-access is prevented.    privs=Privs("Getting file", (int)id->misc->uid, (int)id->misc->gid );       o = Stdio.File( ); -  f = decode_path( f ); -  if(!o->open(f, "r" )) o = 0; +  if(!o->open(norm_f, "r" )) o = 0;    privs = 0;       if(!o || (no_symlinks && (contains_symlinks(path, oldf))))    {    errors++;    report_error(LOCALE(45,"Open of %s failed. Permission denied.\n"),f);       TRACE_LEAVE("");    TRACE_LEAVE("Permission denied.");    return http_low_answer(403, "<h2>File exists, but access forbidden "    "by user</h2>");    }    -  id->realfile = f; +  id->realfile = norm_f;    TRACE_LEAVE("");    accesses++;    TRACE_LEAVE("Normal return");    if( charset != "iso-8859-1" )    {    if( id->misc->set_output_charset )    id->misc->set_output_charset( charset, 2 );    id->misc->input_charset = charset;    }    return o;
Roxen.git/server/modules/filesystems/filesystem.pike:549:    TRACE_LEAVE("MKDIR disallowed (since PUT is disallowed)");    return 0;    }       if (FILTER_INTERNAL_FILE (f, id)) {    id->misc->error_code = 405;    TRACE_LEAVE("MKDIR disallowed (since the dir name matches internal file glob)");    return 0;    }    +  if (size) { +  TRACE_LEAVE("MKDIR failed. Directory name already exists. "); +  return 0; +  } +     if(query("check_auth") && (!id->conf->authenticate( id ) ) ) {    TRACE_LEAVE("MKDIR: Permission denied");    return Roxen.http_auth_required("foo",    "<h1>Permission to 'MKDIR' denied</h1>");    }    mkdirs++;    object privs;       if (((int)id->misc->uid) && ((int)id->misc->gid)) {    // NB: Root-access is prevented.    privs=Privs("Creating directory",    (int)id->misc->uid, (int)id->misc->gid );    }       if (query("no_symlinks") && (contains_symlinks(path, oldf))) {    privs = 0;    errors++; -  report_error(LOCALE(46,"Creation of %s failed. Permission denied.\n"),f); +  report_error(LOCALE(46,"Creation of %s failed. Permission denied.\n"), +  oldf);    TRACE_LEAVE("MKDIR: Contains symlinks. Permission denied");    return http_low_answer(403, "<h2>Permission denied.</h2>");    }    -  int code = mkdir( decode_path(f) ); +  int code = mkdir(f);    privs = 0;       TRACE_ENTER("MKDIR: Accepted", 0);       if (code) {    chmod(f, 0777 & ~(id->misc->umask || 022));    TRACE_LEAVE("MKDIR: Success");    TRACE_LEAVE("Success");    return Roxen.http_string_answer("Ok");    } else {
Roxen.git/server/modules/filesystems/filesystem.pike:635:    }       if (query("no_symlinks") && (contains_symlinks(path, oldf))) {    privs = 0;    errors++;    report_error(LOCALE(46,"Creation of %s failed. Permission denied.\n"),f);    TRACE_LEAVE("PUT: Contains symlinks. Permission denied");    return http_low_answer(403, "<h2>Permission denied.</h2>");    }    -  rm( decode_path(f) ); -  mkdirhier( decode_path(f) ); +  rm(f); +  mkdirhier(f);       if (id->misc->quota_obj) { -  QUOTA_WERR("Checking if the file already exists."); +  QUOTA_WERR("Checking if the file already existed.");    if (size > 0) {    QUOTA_WERR("Deallocating " + size + "bytes.");    id->misc->quota_obj->deallocate(URI, size);    } -  if (size) { -  QUOTA_WERR("Deleting old file."); -  rm(f); +     } -  } +     -  object to = open(decode_path(f), "wct"); +  object to = open(f, "wct");    privs = 0;       TRACE_ENTER("PUT: Accepted", 0);       /* Clear the stat-cache for this file */    if (stat_cache) {    cache_set("stat_cache", f, 0);    }       if(!to)    {    id->misc->error_code = 403;    TRACE_LEAVE("PUT: Open failed");    TRACE_LEAVE("Failure");    return 0;    }       // FIXME: Race-condition. -  chmod(decode_path(f), 0666 & ~(id->misc->umask || 022)); +  chmod(f, 0666 & ~(id->misc->umask || 022));       putting[id->my_fd] = id->misc->len;    if(id->data && strlen(id->data))    {    // FIXME: What if sizeof(id->data) > id->misc->len ?    if (id->misc->len > 0) {    putting[id->my_fd] -= strlen(id->data);    }    int bytes = to->write( id->data );    if (id->misc->quota_obj) {
Roxen.git/server/modules/filesystems/filesystem.pike:741:    privs=Privs("CHMODing file", (int)id->misc->uid, (int)id->misc->gid );    }       if (query("no_symlinks") && (contains_symlinks(path, oldf))) {    privs = 0;    errors++;    TRACE_LEAVE("CHMOD: Contains symlinks. Permission denied");    return http_low_answer(403, "<h2>Permission denied.</h2>");    }    -  array err = catch(chmod(decode_path(f), id->misc->mode & 0777)); +  array err = catch(chmod(f, id->misc->mode & 0777));    privs = 0;       chmods++;       TRACE_ENTER("CHMOD: Accepted", 0);       if (stat_cache) {    cache_set("stat_cache", f, 0);    }   
Roxen.git/server/modules/filesystems/filesystem.pike:823:       if (query("no_symlinks") &&    ((contains_symlinks(path, oldf)) ||    (contains_symlinks(path, id->misc->move_from)))) {    privs = 0;    errors++;    TRACE_LEAVE("MV: Contains symlinks. Permission denied");    return http_low_answer(403, "<h2>Permission denied.</h2>");    }    -  code = mv(decode_path(movefrom), decode_path(f)); +  code = mv(movefrom, f);    privs = 0;       moves++;       TRACE_ENTER("MV: Accepted", 0);       /* Clear the stat-cache for this file */    if (stat_cache) {    cache_set("stat_cache", movefrom, 0);    cache_set("stat_cache", f, 0);
Roxen.git/server/modules/filesystems/filesystem.pike:925:       if (query("no_symlinks") &&    ((contains_symlinks(path, f)) ||    (contains_symlinks(path, moveto)))) {    privs = 0;    errors++;    TRACE_LEAVE("MOVE: Contains symlinks. Permission denied");    return http_low_answer(403, "<h2>Permission denied.</h2>");    }    -  code = mv(decode_path(f), decode_path(moveto)); +  code = mv(f, decode_path(moveto));    privs = 0;       TRACE_ENTER("MOVE: Accepted", 0);       moves++;       /* Clear the stat-cache for this file */    if (stat_cache) {    cache_set("stat_cache", moveto, 0);    cache_set("stat_cache", f, 0);
Roxen.git/server/modules/filesystems/filesystem.pike:989:    if (((int)id->misc->uid) && ((int)id->misc->gid)) {    // NB: Root-access is prevented.    privs=Privs("Deleting file", id->misc->uid, id->misc->gid );    }       /* Clear the stat-cache for this file */    if (stat_cache) {    cache_set("stat_cache", f, 0);    }    -  if(!rm(decode_path(f))) +  if(!rm(f))    {    privs = 0;    id->misc->error_code = 405;    TRACE_LEAVE("DELETE: Failed");    return 0;    }    privs = 0;    deletes++;       if (id->misc->quota_obj && (size > 0)) {