Commit 4c56daf6 authored by Leigh Stoller's avatar Leigh Stoller

Add "gid" slot to the images table for changing permission scheme from

only pid, to pid/gid like most other things in the testbed. Also add a
"global" slot to denote images that are globally available to all
projects (system images). The older "shared" attribute is now used to
denote images that are shared within a project (available to all
subgroups in the project). The migration path for existing DBs is
given in the migrate file. Be sure to run those commands on an
existing testbed or things will break!

www/newimageid, www/newimageid_ez: A bunch of changes for
shared/global attributes. Added a group menu to the form so users can
create images in subgroups. Beefed up the Java code that constructs
the path name to use the gid, shared, and global attributes of the
form to give the user the best possible path that we can. Improved the
pathname checking code so that we do not allow just any old path in
case the user elects to disregard the path we carefully constructed
for them. Also check the proj/group membership, and setup defaults for
users that have permission in just one pid/gid to create images.

libdb.in: Changed permission check in TBImageIDAccessCheck() to
reflect shared/global attribute changes.

os_load: Get rid of test that checked path of the image. The path
checking is done in the web interface anyway, so why duplicate in 4
places. Other minor changes reflecting shared->global name change.
Also note that images can come from the group directory now.

create_image: Get rid of test that checked path of the image. The path
checking is done in the web interface anyway, so why duplicate in 4
places. Also note that images can come from the group directory now.

www/dbdefs: Changed permission check in TBImageIDAccessCheck() to
reflect shared/global attribute changes.

www/showimageid_list, www/showstuff: Minor global/shared attribute
changes.

www/menu: Change osids/imageids pointer to point to the image list,
not the osid list. This is more reasonable for mere users who have
access to the EZ form, and thus never really need to concern
themselves with osids.

www/editimageid: Add proper pathname checking. There were no checks at
all before!
parent 52396569
......@@ -842,19 +842,22 @@ sub TBImageIDAccessCheck($$$)
# No GIDs yet.
#
my $query_result =
DBQueryFatal("SELECT pid,shared FROM images WHERE imageid='$imageid'");
DBQueryFatal("SELECT pid,gid,shared,global FROM images ".
"WHERE imageid='$imageid'");
if ($query_result->numrows == 0) {
return 0;
}
my @row = $query_result->fetchrow_array();
my $pid = $row[0];
my $shared = $row[1];
my $gid = $row[1];
my $shared = $row[2];
my $global = $row[3];
#
# Global ImageIDs can be read by anyone.
#
if ($shared) {
if ($global) {
if ($access_type == TB_IMAGEID_READINFO) {
return 1;
}
......@@ -866,12 +869,18 @@ sub TBImageIDAccessCheck($$$)
#
if ($access_type == TB_IMAGEID_READINFO) {
$mintrust = PROJMEMBERTRUST_USER;
#
# Shared imageids are readable by anyone in the project.
#
if ($shared) {
$gid = $pid;
}
}
else {
$mintrust = PROJMEMBERTRUST_LOCALROOT;
}
return TBMinTrust(TBProjTrust($uid, $pid), $mintrust);
return TBMinTrust(TBGrpTrust($uid, $pid, $gid), $mintrust);
}
#
......
......@@ -303,6 +303,7 @@ CREATE TABLE iface_counters (
CREATE TABLE images (
imagename varchar(30) NOT NULL default '',
pid varchar(12) NOT NULL default '',
gid varchar(12) NOT NULL default '',
imageid varchar(45) NOT NULL default '',
creator varchar(8) default NULL,
created datetime default NULL,
......@@ -320,10 +321,12 @@ CREATE TABLE images (
load_busy tinyint(4) NOT NULL default '0',
ezid tinyint(4) NOT NULL default '0',
shared tinyint(4) NOT NULL default '0',
global tinyint(4) NOT NULL default '0',
updated datetime default NULL,
max_concurrent int(11) default NULL,
PRIMARY KEY (imagename,pid),
KEY imageid (imageid)
KEY gid (gid)
) TYPE=MyISAM;
--
......
......@@ -104,3 +104,16 @@ last_net_act,last_cpu_act,last_ext_act);
user_pubkeys_new to user_pubkeys;
drop table user_pubkeys_old;
1.120: Add gid slot to images table for per-subgroup image support
Also add global global flag, to replace shared flag. Global
means testbed wide, while shared means within a project. To
migrate an existing DB, just need to set pid=gid,global=shared
for all existing images, and then set shared=0.
alter table images add gid varchar(12) NOT NULL default '' after pid;
alter table images add INDEX (gid);
alter table images add global tinyint(4) NOT NULL default '0' \
after shared;
update images set gid=pid,global=shared;
update images set shared=0;
......@@ -196,7 +196,6 @@ foreach my $node (@nodes) {
my $loadlen = $imageid_row{'loadlength'};
my $imagepath = $imageid_row{'path'};
my $defosid = $imageid_row{'default_osid'};
my $shared = $imageid_row{'shared'};
my $max_concurrent = $imageid_row{'max_concurrent'};
# Check for a few errors early!
......@@ -248,15 +247,6 @@ foreach my $node (@nodes) {
if ($loadpart) { $diskpart = "wd0:s${loadpart}"; }
else {$diskpart = "wd0"; }
# For now, all testbed default images come from boss and all pid specific
# images come from ops:/proj.
if (! $shared && $mereuser) {
if (! ($imagepath =~ /^\/proj\//)) {
die("*** $0:\n".
" Your image must reside in /proj\n");
}
}
print STDOUT "Changing default OS for $node to $defosid\n";
if (!$TESTMODE) {
system("$osselect -m PXEBOOT $node");
......@@ -444,7 +434,7 @@ sub dolisting() {
$query_result =
DBQueryFatal("select distinct i.* from images as i ".
"left join group_membership as g on g.pid=i.pid ".
"where g.uid='$me' or i.shared ".
"where g.uid='$me' or i.global ".
"order by i.pid,i.imageid");
} else {
$query_result =
......
......@@ -32,7 +32,6 @@ my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my $BOSSNODE = "@BOSSNODE@";
my $PROJROOT = "/proj";
my $TFTPDIR = "/tftpboot";
#
......@@ -170,9 +169,8 @@ if ($mereuser &&
}
#
# Make sure that the filename is a /proj/$pid filename and a directory that
# exists and is writeable for the user. We test this by creating the file.
# Its going to get wiped anyway.
# Make sure that the directory exists and is writeable for the user.
# We test this by creating the file. Its going to get wiped anyway.
#
my $filename = $imageid_row{'path'};
......@@ -184,9 +182,6 @@ else {
fatal("Bad filename: $filename");
}
if (! ($filename =~ /^$PROJROOT\/$pid\/.*/)) {
fatal("File $filename for must reside someplace in $PROJROOT/$pid\n");
}
open(FILE, "> $filename") or
fatal("Could not create $filename: $!");
close(FILE) or
......
......@@ -721,23 +721,23 @@ function TBImageIDAccessCheck($uid, $imageid, $access_type)
return 1;
}
#
# No GIDs yet.
#
$query_result =
DBQueryFatal("SELECT pid,shared FROM images WHERE imageid='$imageid'");
DBQueryFatal("SELECT pid,gid,shared,global FROM images ".
"WHERE imageid='$imageid'");
if (mysql_num_rows($query_result) == 0) {
return 0;
}
$row = mysql_fetch_array($query_result);
$shared = $row[shared];
$global = $row["global"];
$pid = $row[pid];
$gid = $row[gid];
#
# Global ImageIDs can be read by anyone but written by Admins only.
#
if ($shared) {
if ($global) {
if ($access_type == $TB_IMAGEID_READINFO) {
return 1;
}
......@@ -749,12 +749,17 @@ function TBImageIDAccessCheck($uid, $imageid, $access_type)
#
if ($access_type == $TB_IMAGEID_READINFO) {
$mintrust = $TBDB_TRUST_USER;
#
# Shared imageids are readable by anyone in the project.
#
if ($shared)
$gid = $pid;
}
else {
$mintrust = $TBDB_TRUST_LOCALROOT;
}
return TBMinTrust(TBProjTrust($uid, $pid), $mintrust);
return TBMinTrust(TBGrpTrust($uid, $pid, $gid), $mintrust);
}
#
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
......@@ -38,6 +38,16 @@ if (!TBImageIDAccessCheck($uid, $imageid, $TB_IMAGEID_MODIFYINFO)) {
USERERROR("You do not have permission to access ImageID $imageid!", 1);
}
#
# Need the gid for path checking.
#
$query_result =
DBQueryFatal("select * from images where imageid='$imageid'");
$row = mysql_fetch_array($query_result);
$gid = $row['gid'];
$pid = $row['pid'];
$shared = $row['shared'];
#
# Sanitize values and create string pieces.
#
......@@ -60,11 +70,24 @@ else {
}
if (isset($path) && strcmp($path, "")) {
$foo = addslashes($path);
if (strcmp($path, $foo)) {
if (! ereg("^[-_a-zA-Z0-9\/\.+]+$", $path)) {
USERERROR("The path must not contain special characters!", 1);
}
if (!$isadmin) {
$pdef = "";
if (!$shared && strcmp($gid, $pid)) {
$pdef = "/groups/" . $pid . "/" . $gid . "/";
}
else {
$pdef = "/proj/" . $pid . "/images/";
}
if (strpos($path, $pdef) === false) {
USERERROR("Invalid path! Must reside in /proj or /groups.", 1);
}
}
$path = "'$path'";
}
else {
......
......@@ -201,8 +201,8 @@ function WRITESIDEBAR() {
$TBBASE, "showexp_list.php3");
WRITESIDEBARBUTTON("Begin an Experiment",
$TBBASE, "beginexp.php3");
WRITESIDEBARBUTTON("OSIDs and ImageIDs",
$TBBASE, "showosid_list.php3");
WRITESIDEBARBUTTON("ImageIDs and OSIDs",
$TBBASE, "showimageid_list.php3");
WRITESIDEBARBUTTON("Update User Information",
$TBBASE, "moduserinfo.php3");
WRITESIDEBARBUTTON("Node Reservation Status",
......
......@@ -130,21 +130,53 @@ function SPITFORM($formfields, $errors)
echo "<SCRIPT LANGUAGE=JavaScript>
function SetPrefix(theform)
{
var idx = theform['formfields[pid]'].selectedIndex;
var pid = theform['formfields[pid]'].options[idx].value;
if (pid == '') {
theform['formfields[path]'].value = '/proj/';
var pidx = theform['formfields[pid]'].selectedIndex;
var pid = theform['formfields[pid]'].options[pidx].value;
var gidx = theform['formfields[gid]'].selectedIndex;
var gid = theform['formfields[gid]'].options[gidx].value;
var shared = theform['formfields[shared]'].checked;
\n";
if ($isadmin)
echo "var global = theform['formfields[global]'].checked;";
else
echo "var global = 0;";
echo "if (pid == '') {
theform['formfields[path]'].value = '/proj';
}
else if (theform['formfields[imagename]'].value == '') {
theform['formfields[imagename]'].defaultValue = '';
theform['formfields[path]'].value =
'/proj/' + pid + '/images/';
if (global) {
theform['formfields[path]'].value =
'/usr/testbed/images/';
}
else if (gid == '' || gid == pid || shared) {
theform['formfields[path]'].value =
'/proj/' + pid + '/images/';
}
else {
theform['formfields[path]'].value =
'/groups/' + pid + '/' + gid + '/';
}
}
else if (theform['formfields[imagename]'].value != '') {
theform['formfields[path]'].value =
'/proj/' + pid + '/images/' +
theform['formfields[imagename]'].value + '.ndz';
var filename = theform['formfields[imagename]'].value +
'.ndz';
if (global) {
theform['formfields[path]'].value =
'/usr/testbed/images/' + filename;
}
else if (gid == '' || gid == pid || shared) {
theform['formfields[path]'].value =
'/proj/' + pid + '/images/' + filename;
}
else {
theform['formfields[path]'].value =
'/groups/' + pid + '/' + gid + '/' +
filename;
}
}
}
</SCRIPT>\n";
......@@ -179,6 +211,38 @@ function SPITFORM($formfields, $errors)
echo " </td>
</tr>\n";
#
# Select a group
#
echo "<tr>
<td >Group:</td>
<td><select name=\"formfields[gid]\"
onChange='SetPrefix(idform);'>
<option value=''>Default Group </option>\n";
reset($projlist);
while (list($project, $grouplist) = each($projlist)) {
for ($i = 0; $i < count($grouplist); $i++) {
$group = $grouplist[$i];
if (strcmp($project, $group)) {
$selected = "";
if (isset($formfields[gid]) &&
isset($formfields[pid]) &&
strcmp($formfields[pid], $project) == 0 &&
strcmp($formfields[gid], $group) == 0)
$selected = "selected";
echo "<option $selected value=\"$group\">
$project/$group</option>\n";
}
}
}
echo " </select>
</td>
</tr>\n";
#
# Image Name:
#
......@@ -311,20 +375,41 @@ function SPITFORM($formfields, $errors)
</td>
</tr>\n";
#
# Shared?
#
echo "<tr>
<td>Shared?:<br>
(available to all subgroups)</td>
<td class=left>
<input type=checkbox
onClick='SetPrefix(idform);'
name=\"formfields[shared]\"
value=Yep";
if (isset($formfields[shared]) &&
strcmp($formfields[shared], "Yep") == 0)
echo " checked";
echo " > Yes
</td>
</tr>\n";
if ($isadmin) {
#
# Shared?
# Global?
#
echo "<tr>
<td>Shared?:<br>
<td>Global?:<br>
(available to all projects)</td>
<td class=left>
<input type=checkbox
name=\"formfields[shared]\"
onClick='SetPrefix(idform);'
name=\"formfields[global]\"
value=Yep";
if (isset($formfields[shared]) &&
strcmp($formfields[shared], "Yep") == 0)
if (isset($formfields["global"]) &&
strcmp($formfields["global"], "Yep") == 0)
echo " checked";
echo " > Yes
......@@ -395,6 +480,32 @@ if (! $submit) {
$defaults = array();
$defaults[loadpart] = "X";
$defaults[path] = "/proj/";
#
# For users that are in one project and one subgroup, it is usually
# the case that they should use the subgroup, and since they also tend
# to be in the clueless portion of our users, give them some help.
#
if (count($projlist) == 1) {
list($project, $grouplist) = each($projlist);
if (count($grouplist) <= 2) {
$defaults[pid] = $project;
if (count($grouplist) == 1 || strcmp($project, $grouplist[0]))
$group = $grouplist[0];
else {
$group = $grouplist[1];
}
$defaults[gid] = $group;
if (!strcmp($project, $group))
$defaults[path] = "/proj/$project/images/";
else
$defaults[path] = "/groups/$project/$group/";
}
reset($projlist);
}
SPITFORM($defaults, 0);
PAGEFOOTER();
return;
......@@ -526,6 +637,26 @@ else {
$errors["Boot OS"] = "Invalid; Must be one of the partitions";
}
#
# Only admin types can set the global bit for an image. Ignore silently.
#
$global = 0;
if ($isadmin &&
isset($formfields["global"]) &&
strcmp($formfields["global"], "Yep") == 0) {
$global = 1;
}
$shared = 0;
if (isset($formfields[shared]) &&
strcmp($formfields[shared], "Yep") == 0) {
$shared = 1;
}
# Does not make sense to do this.
if ($global && $shared) {
$errors["Global"] = "Image declared both shared and global";
}
#
# The path must not contain illegal chars and it must be more than
# the original /proj/$pid we gave the user. We allow admins to specify
......@@ -538,14 +669,20 @@ if (!isset($formfields[path]) ||
elseif (! ereg("^[-_a-zA-Z0-9\/\.+]+$", $formfields[path])) {
$errors["Path"] = "Contains invalid characters";
}
else {
$pdef = "/proj/$formfields[pid]/";
if (strcmp($formfields[path], "$pdef") == 0) {
$errors["Path"] = "Incomplete Path";
elseif (! $isadmin) {
$pdef = "";
if (!$shared &&
isset($formfields[gid]) &&
strcmp($formfields[gid], "") &&
strcmp($formfields[gid], $formfields[pid])) {
$pdef = "/groups/" . $formfields[pid] . "/" . $formfields[gid] . "/";
}
else {
$pdef = "/proj/" . $formfields[pid] . "/images/";
}
elseif (!$isadmin &&
strcmp(substr($formfields[path], 0, strlen($pdef)), $pdef)) {
if (strpos($formfields[path], $pdef) === false) {
$errors["Path"] = "Invalid Path";
}
}
......@@ -589,16 +726,6 @@ if (isset($formfields[node]) &&
$node = $formfields[node];
}
#
# If any errors, respit the form with the current values and the
# error messages displayed. Iterate until happy.
#
if (count($errors)) {
SPITFORM($formfields, $errors);
PAGEFOOTER();
return;
}
#
# Only admins have this option. Always on for mereusers, but default off
# for admins.
......@@ -612,14 +739,13 @@ if (! $isadmin ||
}
#
# Only admin types can set the shared bit for an image. Ignore silently.
#
$shared = 0;
if ($isadmin &&
isset($formfields[shared]) &&
strcmp($formfields[shared], "Yep") == 0) {
$shared = 1;
# If any errors, respit the form with the current values and the
# error messages displayed. Iterate until happy.
#
if (count($errors)) {
SPITFORM($formfields, $errors);
PAGEFOOTER();
return;
}
#
......@@ -627,11 +753,15 @@ if ($isadmin &&
#
$description = addslashes($formfields[description]);
$pid = $formfields[pid];
$gid = $formfields[gid];
$imagename = $formfields[imagename];
$loadpart = $formfields[loadpart];
$loadlength = $formfields[loadlength];
$default_osid= $formfields[default_osid];
$path = $formfields[path];
if (!isset($gid) || !strcmp($gid, "")) {
$gid = $pid;
}
#
# And insert the record!
......@@ -733,12 +863,12 @@ $query_result =
DBQueryFatal("INSERT INTO images ".
"(imagename, imageid, description, loadpart, loadlength, ".
" part1_osid, part2_osid, part3_osid, part4_osid, ".
" default_osid, path, pid, shared, creator, created) ".
" default_osid, path, pid, shared,global, creator, created) ".
"VALUES ".
" ('$imagename', '$imageid', '$description', $loadpart, ".
" $loadlength, ".
" $part1_osid, $part2_osid, $part3_osid, $part4_osid, ".
" '$default_osid', '$path', '$pid', $shared, ".
" '$default_osid', '$path', '$pid', $shared, $global, ".
" '$uid', now())");
if (!$isadmin || $makedefault) {
......@@ -790,7 +920,7 @@ if (isset($node)) {
#
# Grab the unix GID for running script.
#
TBGroupUnixInfo($pid, $pid, $unix_gid, $unix_name);
TBGroupUnixInfo($pid, $gid, $unix_gid, $unix_name);
echo "<br>
Creating image using node '$node' ...
......
This diff is collapsed.
......@@ -44,10 +44,18 @@ if ($isadmin) {
$query_result = DBQueryFatal("SELECT * FROM images as i order by $order");
}
else {
#
# User is allowed to view the list of all global images, and all images
# in his project. Include images in the subgroups too, since its okay
# for the all project members to see the descriptors. They need proper
# permission to use/modify the image/descriptor of course, but that is
# checked in the pages that do that stuff. In other words, ignore the
# shared flag in the descriptors.
#
$query_result =
DBQueryFatal("select distinct i.* from images as i ".
"left join group_membership as g on g.pid=i.pid ".
"where g.uid='$uid' or i.shared order by $order");
"where g.uid='$uid' or i.global order by $order");
}
SUBPAGESTART();
......
......@@ -893,6 +893,7 @@ function SHOWIMAGEID($imageid, $edit, $isadmin = 0) {
$imagename = $row[imagename];
$pid = $row[pid];
$gid = $row[gid];
$description = stripslashes($row[description]);
$loadpart = $row[loadpart];
$loadlength = $row[loadlength];
......@@ -904,6 +905,7 @@ function SHOWIMAGEID($imageid, $edit, $isadmin = 0) {
$path = $row[path];
$loadaddr = $row[load_address];
$shared = $row[shared];
$globalid = $row["global"];
$creator = $row[creator];
$created = $row[created];
......@@ -949,6 +951,12 @@ function SHOWIMAGEID($imageid, $edit, $isadmin = 0) {
<a href='showproject.php3?pid=$pid'>$pid</a></td>
</tr>\n";
echo "<tr>
<td>Group: </td>
<td class=\"left\">
<a href='showgroup.php3?pid=$pid&gid=$gid'>$gid</a></td>
</tr>\n";
echo "<tr>
<td>Creator: </td>
<td class=left>$creator</td>
......@@ -1076,6 +1084,18 @@ function SHOWIMAGEID($imageid, $edit, $isadmin = 0) {
echo " </td>
</tr>\n";
echo "<tr>
<td>Global?: </td>
<td class=left>\n";
if ($globalid)
echo "Yes";
else
echo "No";
echo " </td>
</tr>\n";
echo "<tr>
<td>Internal ID: </td>
<td class=left>$imageid</td>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment