Check-in [e9fcc6d8f5]
Overview
SHA1:e9fcc6d8f52f28a19bad96be870994ef91b05e5a
Date: 2015-03-19 16:09:20
User: rkeene
Comment:Allow administrators to provide additional/replaced permissions for files, fixed suidRoot setting
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | folders | manifest
Tags And Properties
Context
2015-03-20
01:46
[0ab26b4975] Updated to lowercase permissions read from the database, for security (user: rkeene, tags: trunk)
2015-03-19
16:09
[e9fcc6d8f5] Allow administrators to provide additional/replaced permissions for files, fixed suidRoot setting (user: rkeene, tags: trunk)
15:43
[9be4aa6a4a] Updated to indicate local files are not world-accessible (good idea ?) (user: rkeene, tags: trunk)
Changes

Modified appfsd.c from [3e9adabf49] to [fe7e6328bd].

   139    139   	unsigned long long inode;
   140    140   	union {
   141    141   		struct {
   142    142   			int childcount;
   143    143   		} dir;
   144    144   		struct {
   145    145   			int executable;
   146         -			int suid;
          146  +			int suidRoot;
   147    147   			int worldaccessible;
   148    148   			off_t size;
   149    149   		} file;
   150    150   		struct {
   151    151   			off_t size;
   152    152   			char source[256];
   153    153   		} symlink;
................................................................................
   932    932   				}
   933    933   
   934    934   				break;
   935    935   			case 'f': /* file */
   936    936   				pathinfo->type = APPFS_PATHTYPE_FILE;
   937    937   				pathinfo->typeinfo.file.size = 0;
   938    938   				pathinfo->typeinfo.file.executable = 0;
   939         -				pathinfo->typeinfo.file.suid = 0;
          939  +				pathinfo->typeinfo.file.suidRoot = 0;
   940    940   				pathinfo->typeinfo.file.worldaccessible = 0;
   941    941   
   942    942   				Tcl_DictObjGet(interp, attrs_dict, attr_key_size, &attr_value);
   943    943   				if (attr_value != NULL) {
   944    944   					tcl_ret = Tcl_GetWideIntFromObj(NULL, attr_value, &attr_value_wide);
   945    945   					if (tcl_ret == TCL_OK) {
   946    946   						pathinfo->typeinfo.file.size = attr_value_wide;
................................................................................
   953    953   					for (attr_value_str_i = &attr_value_str[0]; *attr_value_str_i != '\0'; attr_value_str_i++) {
   954    954   						switch (*attr_value_str_i) {
   955    955   							case 'x':
   956    956   								pathinfo->typeinfo.file.executable = 1;
   957    957   
   958    958   								break;
   959    959   							case 'U':
   960         -								pathinfo->typeinfo.file.suid = 1;
          960  +								pathinfo->typeinfo.file.suidRoot = 1;
   961    961   
   962    962   								break;
   963    963   							case '-':
   964    964   								pathinfo->typeinfo.file.worldaccessible = 1;
   965    965   
   966    966   								break;
   967    967   						}
................................................................................
  1148   1148   	memcpy(buf, pathinfo.typeinfo.symlink.source, strlen(pathinfo.typeinfo.symlink.source) + 1);
  1149   1149   
  1150   1150   	return(0);
  1151   1151   }
  1152   1152   
  1153   1153   static int appfs_fuse_getattr(const char *path, struct stat *stbuf) {
  1154   1154   	struct appfs_pathinfo pathinfo;
         1155  +	int changeOwnerToUserIfPackaged;
  1155   1156   	int retval;
  1156   1157   
  1157   1158   	retval = 0;
  1158   1159   
  1159   1160   	APPFS_DEBUG("Enter (path = %s, ...)", path);
  1160   1161   
  1161   1162   #if (defined(DEBUG) && defined(APPFS_EXIT_PATH)) || defined(APPFS_EXIT_PATH_ENABLE_MAJOR_SECURITY_HOLE)
................................................................................
  1186   1187   
  1187   1188   	stbuf->st_mtime = pathinfo.time;
  1188   1189   	stbuf->st_ctime = pathinfo.time;
  1189   1190   	stbuf->st_atime = pathinfo.time;
  1190   1191   	stbuf->st_ino   = pathinfo.inode;
  1191   1192   	stbuf->st_mode  = 0;
  1192   1193   
         1194  +	changeOwnerToUserIfPackaged = 1;
         1195  +
  1193   1196   	switch (pathinfo.type) {
  1194   1197   		case APPFS_PATHTYPE_DIRECTORY:
  1195   1198   			stbuf->st_mode = S_IFDIR | 0555;
  1196   1199   			stbuf->st_nlink = 2 + pathinfo.typeinfo.dir.childcount;
  1197   1200   			break;
  1198   1201   		case APPFS_PATHTYPE_FILE:
         1202  +			stbuf->st_mode = S_IFREG | 0444;
         1203  +
  1199   1204   			if (pathinfo.typeinfo.file.executable) {
  1200         -				stbuf->st_mode = S_IFREG | 0555;
  1201         -			} else {
  1202         -				stbuf->st_mode = S_IFREG | 0444;
         1205  +				stbuf->st_mode |= 0111;
  1203   1206   			}
  1204   1207   
  1205         -			if (pathinfo.typeinfo.file.suid) {
  1206         -				stbuf->st_mode = S_IFREG | 04000;
         1208  +			if (pathinfo.typeinfo.file.suidRoot) {
         1209  +				changeOwnerToUserIfPackaged = 0;
         1210  +
         1211  +				stbuf->st_mode |= 04000;
  1207   1212   			}
  1208   1213   
  1209   1214   			if (pathinfo.typeinfo.file.worldaccessible) {
  1210   1215   				stbuf->st_mode &= ~077;
  1211   1216   			}
  1212   1217   
  1213   1218   			stbuf->st_nlink = 1;
................................................................................
  1235   1240   			break;
  1236   1241   		case APPFS_PATHTYPE_INVALID:
  1237   1242   			retval = -EIO;
  1238   1243   
  1239   1244   			break;
  1240   1245   	}
  1241   1246   
  1242         -	if (pathinfo.packaged) {
         1247  +	if (pathinfo.packaged && changeOwnerToUserIfPackaged) {
  1243   1248   		stbuf->st_uid   = appfs_get_fsuid();
  1244   1249   		stbuf->st_gid   = appfs_get_fsgid();
  1245   1250   		stbuf->st_mode |= 0200;
  1246   1251   	}
  1247   1252   
  1248   1253   	return(retval);
  1249   1254   }
................................................................................
  2006   2011   	 ** Add FUSE arguments which we always supply
  2007   2012   	 **/
  2008   2013   	fuse_opt_add_arg(args, "-odefault_permissions,fsname=appfs,subtype=appfsd,use_ino,kernel_cache,entry_timeout=0,attr_timeout=0,big_writes,intr,hard_remove");
  2009   2014   
  2010   2015   	if (getuid() == 0) {
  2011   2016   		fuse_opt_parse(args, NULL, NULL, NULL);
  2012   2017   		fuse_opt_add_arg(args, "-oallow_other");
         2018  +
         2019  +		/*
         2020  +		 * This should generally be avoided, but if there are security
         2021  +		 * concerns suid can be disabled completely on the commandline
         2022  +		 */
         2023  +		fuse_opt_parse(args, NULL, NULL, NULL);
         2024  +		fuse_opt_add_arg(args, "-osuid");
  2013   2025   	}
  2014   2026   
  2015   2027   	while ((ch = getopt(argc, argv, "dfshvo:")) != -1) {
  2016   2028   		switch (ch) {
  2017   2029   			case 'v':
  2018   2030   				/* Ignored */
  2019   2031   				break;

Modified appfsd.tcl from [c5b01df3b2] to [ca14ca67ab].

    36     36   		return "http://$hostname/appfs/$method/$hash"
    37     37   	}
    38     38   
    39     39   	# User-replaceable function get the home directory of the current user
    40     40   	proc get_homedir {} {
    41     41   		return [::appfsd::get_homedir]
    42     42   	}
           43  +
           44  +	# User-replacable function to update permissions
           45  +	proc change_perms {file perms} {
           46  +		if {[info exists ::appfs::user::add_perms($file)]} {
           47  +			append perms $::appfs::user::add_perms($file)
           48  +		}
           49  +
           50  +		return $perms
           51  +	}
    43     52   }
    44     53   
    45     54   namespace eval ::appfs {
    46     55   	variable cachedir "/tmp/appfs-cache"
    47     56   	variable ttl 3600
    48     57   	variable nttl 60
    49     58   	variable trusted_cas [list]
................................................................................
   751    760   							"directory" {
   752    761   								set retval(type) "directory"
   753    762   								set retval(childcount) [llength [getchildren $path]]
   754    763   							}
   755    764   							"file" {
   756    765   								set retval(type) "file"
   757    766   								set retval(size) $localpathinfo(size)
          767  +
          768  +								# Once the user writes to a file, all its other
          769  +								# attributes (such as suid) are lost
          770  +
   758    771   								_as_user {
   759    772   									if {[file executable $localpath]} {
   760    773   										set retval(perms) "x-"
   761    774   									} else {
   762    775   										set retval(perms) "-"
   763    776   									}
   764    777   								}
................................................................................
   789    802   						set file [lindex $work end]
   790    803   
   791    804   						if {$directory == "" && $file == ""} {
   792    805   							array set retval [list type directory]
   793    806   						}
   794    807   
   795    808   						::appfs::db eval {SELECT type, time, source, size, perms FROM files WHERE package_sha1 = $pathinfo(package_sha1) AND file_directory = $directory AND file_name = $file;} retval {}
          809  +
          810  +						# Allow an administrator to supply additional permissions to remote files
          811  +						if {[info exists retval(perms)]} {
          812  +							set retval(perms) [::appfs::user::change_perms $path $retval(perms)]
          813  +						}
   796    814   
   797    815   						if {[info exists retval(type)] && $retval(type) == "directory"} {
   798    816   							set retval(childcount) [llength [getchildren $path]]
   799    817   						}
   800    818   
   801    819   						unset -nocomplain retval(*)
   802    820   					}