f41b982009-05-07Martin Stjernholm // This is a roxen module. Copyright © 1996 - 2009, Roxen IS.
57f45e1996-11-27Per Hedbor 
fd0b6f1996-12-02Per Hedbor // User filesystem. Uses the userdatabase (and thus the system passwd
57f45e1996-11-27Per Hedbor // database) to find the home-dir of users, and then looks in a // specified directory in that directory for the files requested. // Normaly mounted under /~, but / or /users/ would work equally well. // / is quite useful for IPPs, enabling them to have URLs like // http://www.hostname.of.provider/customer/.
a749f51999-12-28Martin Nilsson // #define USERFS_DEBUG #ifdef USERFS_DEBUG # define USERFS_WERR(X) werror("USERFS: "+X+"\n") #else # define USERFS_WERR(X) #endif
6682b91997-08-31Peter Bortas 
b1fca01996-11-12Per Hedbor #include <module.h>
48fa361997-04-05Per Hedbor 
f0d6942001-01-29Per Hedbor //<locale-token project="mod_userfs">_</locale-token> #define _(X,Y) _DEF_LOCALE("mod_userfs",X,Y) // end of the locale related stuff
a974861998-07-21Johan Schön inherit "filesystem" : filesystem;
b1fca01996-11-12Per Hedbor 
0917d32013-03-04Anders Johansson constant cvs_version="$Id$";
ddb7062000-02-10Martin Nilsson constant module_type = MODULE_LOCATION;
17013c2001-05-16Per Hedbor LocaleString module_name = _(1,"File systems: User file system");
f0d6942001-01-29Per Hedbor LocaleString module_doc =
6150972001-01-29Per Hedbor _(2,"A file system that gives access to files in the users' home\n"
f0d6942001-01-29Per Hedbor "directories. The users and home directories are found through the\n" "current authentication module. The files from the home directories are\n" "mounted either in the virtual file system of the site or as sites of\n" "their own. So on one server the user Anne's files might be mounted on\n" "<tt>http://domain.com/home/anne/</tt> while another server might give\n" "Anne a web site of her own at <tt>http://anne.domain.com/</tt>.\n");
ddb7062000-02-10Martin Nilsson constant module_unique = 0;
aaef2a1997-03-02Henrik Grubbström (Grubba) 
fbc99b2017-10-20Henrik Grubbström (Grubba) // NB: MySQL 4.1 and later prefix hashes from their internal // password hashing function with a single "*". cf [bug 7834].
ed540b2001-01-13Martin Nilsson #define BAD_PASSWORD(us) (query("only_password") && \
fbc99b2017-10-20Henrik Grubbström (Grubba)  ((us[1] == "") || \ ((us[1][0] == '*') && (us[1][-1] == '*'))))
699dae1998-10-13Henrik Grubbström (Grubba) 
b1fca01996-11-12Per Hedbor int uid_was_zero() { return !(getuid() == 0); // Somewhat misnamed function.. :-) }
7217cd1998-03-01Per Hedbor int hide_searchpath() {
ed540b2001-01-13Martin Nilsson  return query("homedir");
7217cd1998-03-01Per Hedbor } int hide_pdir() {
ed540b2001-01-13Martin Nilsson  return !query("homedir");
7217cd1998-03-01Per Hedbor }
b1fca01996-11-12Per Hedbor void create() {
a974861998-07-21Johan Schön  filesystem::create();
b1fca01996-11-12Per Hedbor  killvar("searchpath");
6150972001-01-29Per Hedbor  defvar("searchpath", "NONE", _(3,"Search path"), TYPE_DIR|VAR_INITIAL,
f0d6942001-01-29Per Hedbor  (0,"This is where the module will find the files in the real " "file system"),
7217cd1998-03-01Per Hedbor  0, hide_searchpath);
edaaab2001-06-09Henrik Grubbström (Grubba)  set("mountpoint", "/~");
a749f51999-12-28Martin Nilsson 
6150972001-01-29Per Hedbor  defvar("only_password", 1, _(4,"Password users only"),
b04ec82000-01-31Per Hedbor  TYPE_FLAG|VAR_INITIAL,
6150972001-01-29Per Hedbor  _(5,"Mount only home directories for users with valid passwords."));
0e929f1998-10-08Henrik Grubbström (Grubba) 
6150972001-01-29Per Hedbor  defvar("user_listing", 0, _(6,"Enable userlisting"), TYPE_FLAG|VAR_INITIAL, _(7,"If set a listing of all users will be shown when you access the "
f0d6942001-01-29Per Hedbor  "mount point."));
a749f51999-12-28Martin Nilsson  defvar("banish_list", ({ "root", "daemon", "bin", "sys", "admin", "lp", "smtp", "uucp", "nuucp", "listen", "nobody", "noaccess", "ftp", "news",
9704572014-08-07Martin Karlgren  "postmaster", ".htaccess", "401.inc", "404.inc", "favicon.ico" }), _(8,"Banish list"),
4cf67b2000-04-06Mattias Wingstedt  TYPE_STRING_LIST,
6150972001-01-29Per Hedbor  _(9,"This is a list of users who's home directories will not be "
f0d6942001-01-29Per Hedbor  "mounted."));
6150972001-01-29Per Hedbor  defvar("own", 0, _(10,"Only owned files"), TYPE_FLAG, _(11,"If set, only files actually owned by the user will be sent "
f0d6942001-01-29Per Hedbor  "from her home directory. This prohibits users from making " "confidental files available by symlinking to them. On the other " "hand it also makes it harder for user to cooperate on projects."));
6150972001-01-29Per Hedbor  defvar("virtual_hosting", 0, _(12,"Virtual user hosting"),
f0d6942001-01-29Per Hedbor  TYPE_FLAG|VAR_INITIAL,
6150972001-01-29Per Hedbor  _(13,"If set, each user will get her own site. You access the user's "
4cf67b2000-04-06Mattias Wingstedt  "with " "<br><tt>http://&lt;user&gt;.domain.com/&lt;mountpoint&gt;</tt> " "<br>instead of " "<br><tt>http://domain.com/&lt;mountpoint&gt;&lt;user&gt;</tt>. " "<p>This means that you normally set the mount point to '/'. " "<p>You need to set up CNAME entries in DNS for all users, or a " "regexp CNAME that matches all users, to get this to "
f0d6942001-01-29Per Hedbor  "work."));
8afe021998-07-02David Hedbor 
6150972001-01-29Per Hedbor  defvar("useuserid", 1, _(14,"Run user scripts as the owner of the script"),
9b9f701997-08-12Per Hedbor  TYPE_FLAG|VAR_MORE,
6150972001-01-29Per Hedbor  _(15,"If set, users' CGI and Pike scripts will be run as the user whos"
f0d6942001-01-29Per Hedbor  " home directory the file was found in. This only works if the " " server was started as root."),
b1fca01996-11-12Per Hedbor  0, uid_was_zero);
a749f51999-12-28Martin Nilsson 
6150972001-01-29Per Hedbor  defvar("pdir", "html/", _(16,"Public directory"),
b04ec82000-01-31Per Hedbor  TYPE_STRING|VAR_INITIAL,
6150972001-01-29Per Hedbor  _(17,"This is the directory in the home directory of the users which "
4cf67b2000-04-06Mattias Wingstedt  "contains the files that will be shown on the web. " "If the module is mounted on <tt>/home/</tt>, the file " "<tt>/home/anne/test.html</tt> is accessed and the home direcory " "of Anne is <tt>/export/users/anne/</tt> the module will fetch "
f0d6942001-01-29Per Hedbor  "the file <tt>/export/users/anne/&lt;Public dir&gt;/test.html</tt>."),
7217cd1998-03-01Per Hedbor  0, hide_pdir);
6150972001-01-29Per Hedbor  defvar("homedir" ,1,_(18,"Look in users homedir"), TYPE_FLAG|VAR_INITIAL, _(19,"If set, the module will look for the files in the user's home "
4cf67b2000-04-06Mattias Wingstedt  "directory, according to the <i>Public directory</i> variable. " "Otherwise the files are fetched from a directory with the same " "name as the user in the directory configured in the "
f0d6942001-01-29Per Hedbor  "<i>Search path</i> variable." ));
b1fca01996-11-12Per Hedbor }
dea2e81998-03-11Henrik Grubbström (Grubba) multiset banish_list;
7217cd1998-03-01Per Hedbor mapping dude_ok;
8afe021998-07-02David Hedbor multiset banish_reported = (<>);
8a581c1998-05-27Henrik Grubbström (Grubba) 
b1fca01996-11-12Per Hedbor void start() {
a974861998-07-21Johan Schön  filesystem::start();
7217cd1998-03-01Per Hedbor  // We fix all file names to be absolute before passing them to // filesystem.pike
6682b91997-08-31Peter Bortas  path="";
fd05972005-10-19Marcus Wellhardh  normalized_path="";
ed540b2001-01-13Martin Nilsson  banish_list = mkmultiset(query("banish_list"));
ab420a2016-07-26Henrik Grubbström (Grubba)  USERFS_WERR(sprintf("start: banish_list: %O\n", banish_list));
7217cd1998-03-01Per Hedbor  dude_ok = ([]);
b1fca01996-11-12Per Hedbor  // This is needed to override the inherited filesystem module start(). }
9704572014-08-07Martin Karlgren protected int on_banish_list (string u) { if (banish_list[u]) { if(!banish_reported[u]) { banish_reported[u] = 1; USERFS_WERR(sprintf("User %s banished...\n", u)); } return 1; } return 0; }
fc40392008-08-15Martin Stjernholm protected array(string) find_user(string f, RequestID id)
b1fca01996-11-12Per Hedbor {
22d1521998-07-19Henrik Grubbström (Grubba)  string of = f; string u;
b1fca01996-11-12Per Hedbor 
ed540b2001-01-13Martin Nilsson  if(query("virtual_hosting")) {
f3d32f2000-11-13Per Hedbor  NOCACHE();
22d1521998-07-19Henrik Grubbström (Grubba)  if(id->misc->host) { string host = (id->misc->host / ":")[0]; if(search(host, ".") != -1) {
8afe021998-07-02David Hedbor  sscanf(host, "%s.%*s", u);
22d1521998-07-19Henrik Grubbström (Grubba)  } else {
8afe021998-07-02David Hedbor  u = host;
22d1521998-07-19Henrik Grubbström (Grubba)  }
8afe021998-07-02David Hedbor  } } else {
38f0a21998-07-22Henrik Grubbström (Grubba)  if((<"", "/", ".">)[f])
22f09c2000-03-21Johan Sundström  return ({ 0, 0 });
38f0a21998-07-22Henrik Grubbström (Grubba) 
9588651998-07-15Henrik Grubbström (Grubba)  switch(sscanf(f, "%*[/]%s/%s", u, f)) {
22d1521998-07-19Henrik Grubbström (Grubba)  case 1: sscanf(f, "%*[/]%s", u); f = ""; break;
9588651998-07-15Henrik Grubbström (Grubba)  default: u=""; // FALL_THROUGH case 2: f = ""; // FALL_THROUGH case 3: break;
44f0501998-07-05Henrik Grubbström (Grubba)  }
b1fca01996-11-12Per Hedbor  }
22d1521998-07-19Henrik Grubbström (Grubba) 
22f09c2000-03-21Johan Sundström  USERFS_WERR(sprintf("find_user(%O) => u:%O, f:%O", of, u, f));
22d1521998-07-19Henrik Grubbström (Grubba) 
22f09c2000-03-21Johan Sundström  return ({ u, f });
22d1521998-07-19Henrik Grubbström (Grubba) }
d772c02016-03-22Henrik Grubbström (Grubba) protected string low_real_path(string f, RequestID id)
22d1521998-07-19Henrik Grubbström (Grubba) {
d772c02016-03-22Henrik Grubbström (Grubba)  string norm_f;
22f09c2000-03-21Johan Sundström 
d772c02016-03-22Henrik Grubbström (Grubba)  [string u, string rel_f] = find_user(f, id);
f0d6942001-01-29Per Hedbor 
ed0cca2016-03-22Henrik Grubbström (Grubba)  if(!u || on_banish_list(u)) {
d772c02016-03-22Henrik Grubbström (Grubba)  return 0; }
9704572014-08-07Martin Karlgren 
d772c02016-03-22Henrik Grubbström (Grubba)  string dir; if (!(dir = dude_ok[u])) { array(string) us = id->conf->userinfo( u, id );
22f09c2000-03-21Johan Sundström  USERFS_WERR(sprintf("checking out %O: %O", u, us)); if(!us || BAD_PASSWORD(us) || banish_list[u]) { // No user, or access denied.
4d04f82000-03-21Martin Nilsson  USERFS_WERR(sprintf("Bad password: %O? Banished? %O", (us?BAD_PASSWORD(us):1), banish_list[u]));
22f09c2000-03-21Johan Sundström  return 0; }
d772c02016-03-22Henrik Grubbström (Grubba)  if(query("homedir"))
22f09c2000-03-21Johan Sundström  {
d772c02016-03-22Henrik Grubbström (Grubba)  if(us[5][-1] != '/') dir = us[ 5 ] + "/" + encode_path(query("pdir")); else dir = us[ 5 ] + encode_path(query("pdir")); } else dir = encode_path(query("searchpath") + u + "/"); dude_ok[u] = dir; }
0417391997-05-16Wilhelm Köhler 
d772c02016-03-22Henrik Grubbström (Grubba)  // For the benefit of the PHP4 module. Will set the DOCUMENT_ROOT // environment variable to this instead of the path to /. id->misc->user_document_root = dir; norm_f = dir + encode_path(rel_f);
7217cd1998-03-01Per Hedbor 
d772c02016-03-22Henrik Grubbström (Grubba)  return norm_f; }
dea2e81998-03-11Henrik Grubbström (Grubba) 
d772c02016-03-22Henrik Grubbström (Grubba) int|mapping|Stdio.File find_file(string f, RequestID id) { string u;
dea2e81998-03-11Henrik Grubbström (Grubba) 
d772c02016-03-22Henrik Grubbström (Grubba)  USERFS_WERR(sprintf("find_file(%O)", f)); [u, string rel_f] = find_user(f, id); if(!u) return -1; string norm_f = real_path(f, id); if (!norm_f) {
230a3c2016-08-12Henrik Grubbström (Grubba)  return 0;
22f09c2000-03-21Johan Sundström  }
d772c02016-03-22Henrik Grubbström (Grubba)  array(string) us; Stdio.Stat stat; if(query("own") || query("useuserid"))
22f09c2000-03-21Johan Sundström  {
d772c02016-03-22Henrik Grubbström (Grubba)  us = id->conf->userinfo( u, id );
22f09c2000-03-21Johan Sundström  if(!us) {
d772c02016-03-22Henrik Grubbström (Grubba)  USERFS_WERR(sprintf("No userinfo for %O!", u)); return 0;
22f09c2000-03-21Johan Sundström  }
12c2461998-03-05Henrik Grubbström (Grubba) 
d772c02016-03-22Henrik Grubbström (Grubba)  stat = file_stat(norm_f);
12c2461998-03-05Henrik Grubbström (Grubba) 
d772c02016-03-22Henrik Grubbström (Grubba)  if (!stat) { USERFS_WERR("File not found."); return 0; } if (stat[5] == (int)us[2]) { if(query("useuserid")) id->misc->is_user = norm_f; } else if (query("own")) { USERFS_WERR("File not owned by user.");
22f09c2000-03-21Johan Sundström  return 0;
b1fca01996-11-12Per Hedbor  } }
22f09c2000-03-21Johan Sundström 
6fe1242011-01-26Marcus Wellhardh  USERFS_WERR(sprintf("Forwarding request to inherited filesystem."));
22f09c2000-03-21Johan Sundström  return filesystem::find_file( f, id );
b1fca01996-11-12Per Hedbor }
22f09c2000-03-21Johan Sundström string real_file(string f, RequestID id)
b1fca01996-11-12Per Hedbor {
a749f51999-12-28Martin Nilsson  USERFS_WERR(sprintf("real_file(%O, X)", f));
b1fca01996-11-12Per Hedbor 
d772c02016-03-22Henrik Grubbström (Grubba)  return ::real_file(f, id);
b1fca01996-11-12Per Hedbor }
22f09c2000-03-21Johan Sundström mapping|array find_dir(string f, RequestID id)
b1fca01996-11-12Per Hedbor {
a749f51999-12-28Martin Nilsson  USERFS_WERR(sprintf("find_dir(%O, X)", f));
b1fca01996-11-12Per Hedbor 
d772c02016-03-22Henrik Grubbström (Grubba)  if (f == "" || f == "/") {
ed540b2001-01-13Martin Nilsson  if (query("user_listing")) {
0e929f1998-10-08Henrik Grubbström (Grubba)  array l;
22f09c2000-03-21Johan Sundström  l = id->conf->userlist(id);
38f0a21998-07-22Henrik Grubbström (Grubba) 
ed540b2001-01-13Martin Nilsson  if(l) return(l - query("banish_list"));
0e929f1998-10-08Henrik Grubbström (Grubba)  }
22d1521998-07-19Henrik Grubbström (Grubba)  return 0;
b1fca01996-11-12Per Hedbor  }
22d1521998-07-19Henrik Grubbström (Grubba) 
d772c02016-03-22Henrik Grubbström (Grubba)  return filesystem::find_dir(f, id);
b1fca01996-11-12Per Hedbor }
d772c02016-03-22Henrik Grubbström (Grubba) Stdio.Stat stat_file(string f, RequestID id)
b1fca01996-11-12Per Hedbor {
22f09c2000-03-21Johan Sundström  USERFS_WERR(sprintf("stat_file(%O)", f));
b1fca01996-11-12Per Hedbor 
d772c02016-03-22Henrik Grubbström (Grubba)  string norm_f = real_path(f, id);
b6c51c1998-07-07Henrik Grubbström (Grubba) 
d772c02016-03-22Henrik Grubbström (Grubba)  if (!norm_f) {
e72dd12016-07-26Henrik Grubbström (Grubba)  if ((f - "/") == "") return Stdio.Stat(({ 0, -2, 0, 0, 0, 0, 0 })); return 0;
38f0a21998-07-22Henrik Grubbström (Grubba)  }
b1fca01996-11-12Per Hedbor 
d772c02016-03-22Henrik Grubbström (Grubba)  Stdio.Stat st = file_stat(norm_f); if(!st) return 0; if(query("own")) { [string u, string rel_f] = find_user(f, id); if (!u) return 0; array(string) us = id->conf->userinfo(u, id); if (!us || ((int)us[2] != st[-2])) return 0;
b1fca01996-11-12Per Hedbor  }
d772c02016-03-22Henrik Grubbström (Grubba)  return st;
b1fca01996-11-12Per Hedbor }
17013c2001-05-16Per Hedbor  string query_name() { return "UserFS "+query("mountpoint")+" from "+ (query("homedir")?"~*/"+query("pdir"):query("searchpath")); }
2172e12000-08-01Johan Sundström  string status() {
f0d6942001-01-29Per Hedbor  if(sizeof(my_configuration()->user_databases()) == 0) return "<font color='&usr.warncolor;'>"+
17013c2001-05-16Per Hedbor  _(20,"You need at least one user database module in this virtual server " "to resolve your users' homedirectories.")+
f0d6942001-01-29Per Hedbor  "</font>";
2172e12000-08-01Johan Sundström } mapping query_action_buttons() {
f0d6942001-01-29Per Hedbor  if(sizeof(my_configuration()->user_databases()) == 0)
6150972001-01-29Per Hedbor  return ([ _(21,"Add system user database module to server")
2172e12000-08-01Johan Sundström  : add_standard_userdb ]); return ([]); } void add_standard_userdb() {
f0d6942001-01-29Per Hedbor  module_dependencies(my_configuration(), ({ "userdb_system" }) );
2172e12000-08-01Johan Sundström }