--- a/usr/src/cmd/rad/mod/zoneadmin/mod_zoneadmin.c Tue Mar 15 10:02:32 2011 -0400
+++ b/usr/src/cmd/rad/mod/zoneadmin/mod_zoneadmin.c Tue Mar 15 15:29:02 2011 -0400
@@ -48,18 +48,52 @@
static conerr_t fd_to_token(int fd, data_t **token, data_t **error);
-static int has_auth(const char *zonename);
+static conerr_t forkexec(const char **argv, data_t **error);
static conerr_t make_error(data_t *errval, data_t **error);
static conerr_t token_to_fd(data_t *arg, int *fd, data_t **error);
+static conerr_t validate_zone(const char *zone, const int valid_states[],
+ data_t **error);
+
/*
* Static data
*/
static rad_modinfo_t modinfo = { "zoneadmin", "zone connectivity" };
+static const int VALID_STATES_BOOT[] = {
+ ZONE_STATE_INSTALLED,
+ ZONE_STATE_READY,
+ ZONE_STATE_SHUTTING_DOWN,
+ ZONE_STATE_DOWN,
+ -1
+};
+
+static const int VALID_STATES_HALT[] = {
+ ZONE_STATE_INSTALLED,
+ ZONE_STATE_READY,
+ ZONE_STATE_RUNNING,
+ ZONE_STATE_SHUTTING_DOWN,
+ -1
+};
+
+static const int VALID_STATES_HALT_GRACEFUL[] = {
+ ZONE_STATE_RUNNING,
+ -1
+};
+
+static const int VALID_STATES_OPEN_RAD[] = {
+ ZONE_STATE_RUNNING,
+ -1
+};
+
+static const int VALID_STATES_REBOOT[] = {
+ ZONE_STATE_RUNNING,
+ -1
+};
+
/*
* Extern functions
*/
@@ -104,6 +138,29 @@
/* ARGSUSED */
conerr_t
+api_ZoneAdmin_invoke_boot(rad_instance_t *inst, adr_method_t *meth,
+ data_t **ret, data_t **args, int count, data_t **error)
+{
+ const char *zone = data_to_string(args[0]);
+
+ conerr_t err = validate_zone(zone, VALID_STATES_BOOT, error);
+ if (err != ce_ok) {
+ return (err);
+ }
+
+ const char *argv[] = {
+ "/usr/bin/pfexec",
+ "/usr/sbin/zoneadm",
+ "-z", zone,
+ "boot",
+ NULL
+ };
+
+ return (forkexec(argv, error));
+}
+
+/* ARGSUSED */
+conerr_t
api_ZoneAdmin_invoke_close(rad_instance_t *inst, adr_method_t *meth,
data_t **ret, data_t **args, int count, data_t **error)
{
@@ -186,10 +243,10 @@
const char *zone = data_to_string(args[0]);
boolean_t graceful = data_to_boolean(args[1]);
- zone_state_t zstate;
- if (getzoneidbyname(zone) == GLOBAL_ZONEID ||
- zone_get_state((char *)zone, &zstate) != Z_OK) {
- return (make_error(&e__ZoneAdminErrorCode_INVALID_ZONE, error));
+ conerr_t err = validate_zone(zone, graceful ?
+ VALID_STATES_HALT_GRACEFUL : VALID_STATES_HALT, error);
+ if (err != ce_ok) {
+ return (err);
}
const char **argv;
@@ -216,17 +273,7 @@
argv = cmd;
}
- int status;
- if (rad_forkexec(argv, &status, B_TRUE) == -1) {
- return (ce_system);
- }
-
- if (status != 0) {
- return (make_error(&e__ZoneAdminErrorCode_COMMAND_FAILED,
- error));
- }
-
- return (ce_ok);
+ return (forkexec(argv, error));
}
/* ARGSUSED */
@@ -235,8 +282,10 @@
data_t **ret, data_t **args, int count, data_t **error)
{
const char *zone = data_to_string(args[0]);
- if (!has_auth(zone)) {
- return (ce_priv);
+
+ conerr_t err = validate_zone(zone, NULL, error);
+ if (err != ce_ok) {
+ return (err);
}
int fdm;
@@ -272,17 +321,17 @@
(void) closefrom(3);
const char *argv[] = {
- "/usr/bin/pfexec",
- "/usr/sbin/zlogin",
- "-CE", zone,
- NULL
+ "/usr/bin/pfexec",
+ "/usr/sbin/zlogin",
+ "-CE", zone,
+ NULL
};
(void) execv(argv[0], (char *const *)argv);
_exit(1);
}
- conerr_t err = fd_to_token(fdm, ret, error);
+ err = fd_to_token(fdm, ret, error);
if (err != ce_ok) {
(void) close(fdm);
return (err);
@@ -299,8 +348,9 @@
const char *zone = data_to_string(args[0]);
const char *user = args[1] == NULL ? NULL : data_to_string(args[1]);
- if (!has_auth(zone)) {
- return (ce_priv);
+ conerr_t err = validate_zone(zone, VALID_STATES_OPEN_RAD, error);
+ if (err != ce_ok) {
+ return (err);
}
int fd[2];
@@ -336,23 +386,23 @@
*/
if (user == NULL) {
const char *cmd[] = {
- "/usr/bin/pfexec",
- "/usr/sbin/zlogin",
- "-ES", zone,
- "/usr/lib/rad/radpipe",
- "-u",
- NULL
+ "/usr/bin/pfexec",
+ "/usr/sbin/zlogin",
+ "-ES", zone,
+ "/usr/lib/rad/radpipe",
+ "-u",
+ NULL
};
argv = cmd;
} else {
const char *cmd[] = {
- "/usr/bin/pfexec",
- "/usr/sbin/zlogin",
- "-ES", zone,
- "/usr/bin/su",
- user,
- "-c", "/usr/lib/rad/radpipe",
- NULL
+ "/usr/bin/pfexec",
+ "/usr/sbin/zlogin",
+ "-ES", zone,
+ "/usr/bin/su",
+ user,
+ "-c", "/usr/lib/rad/radpipe",
+ NULL
};
argv = cmd;
}
@@ -363,7 +413,7 @@
(void) close(fd[1]);
- conerr_t err = fd_to_token(fd[0], ret, error);
+ err = fd_to_token(fd[0], ret, error);
if (err != ce_ok) {
(void) close(fd[0]);
return (err);
@@ -411,6 +461,29 @@
/* ARGSUSED */
conerr_t
+api_ZoneAdmin_invoke_reboot(rad_instance_t *inst, adr_method_t *meth,
+ data_t **ret, data_t **args, int count, data_t **error)
+{
+ const char *zone = data_to_string(args[0]);
+
+ conerr_t err = validate_zone(zone, VALID_STATES_REBOOT, error);
+ if (err != ce_ok) {
+ return (err);
+ }
+
+ const char *argv[] = {
+ "/usr/bin/pfexec",
+ "/usr/sbin/zoneadm",
+ "-z", zone,
+ "reboot",
+ NULL
+ };
+
+ return (forkexec(argv, error));
+}
+
+/* ARGSUSED */
+conerr_t
api_ZoneAdmin_invoke_write(rad_instance_t *inst, adr_method_t *meth,
data_t **ret, data_t **args, int count, data_t **error)
{
@@ -447,13 +520,20 @@
return (*token == NULL ? ce_nomem : ce_ok);
}
-static int
-has_auth(const char *zonename)
+static conerr_t
+forkexec(const char **argv, data_t **error)
{
- char authname[MAXAUTHS];
- (void) snprintf(authname, MAXAUTHS, "%s%s%s",
- ZONE_MANAGE_AUTH, KV_OBJECT, zonename);
- return (chkauthattr(authname, cuserid(NULL)));
+ int status;
+ if (rad_forkexec(argv, &status, B_TRUE) == -1) {
+ return (ce_system);
+ }
+
+ if (status != 0) {
+ return (make_error(&e__ZoneAdminErrorCode_COMMAND_FAILED,
+ error));
+ }
+
+ return (ce_ok);
}
static conerr_t
@@ -486,3 +566,46 @@
return (ce_ok);
}
+
+static conerr_t
+validate_zone(const char *zone, const int valid_states[], data_t **error)
+{
+ /* Ensure ngz */
+ zone_state_t zstate;
+ if (getzoneidbyname(zone) == GLOBAL_ZONEID ||
+ zone_get_state((char *)zone, &zstate) != Z_OK) {
+ return (make_error(&e__ZoneAdminErrorCode_INVALID_ZONE, error));
+ }
+
+ /* Ensure auth */
+ char authname[MAXAUTHS];
+ (void) snprintf(authname, MAXAUTHS, "%s%s%s", ZONE_MANAGE_AUTH,
+ KV_OBJECT, zone);
+ if (!chkauthattr(authname, cuserid(NULL))) {
+ return (ce_priv);
+ }
+
+ /*
+ * Ensure valid state
+ *
+ * There is no guarantee the state won't change between when testing it
+ * here and when the requested operation is executed, but this will
+ * validate the common case.
+ */
+ if (valid_states != NULL) {
+ zone_state_t zstate;
+ if (zone_get_state((char *)zone, &zstate) != Z_OK) {
+ return (ce_system);
+ }
+
+ for (int i = 0; valid_states[i] != zstate; i++) {
+ if (valid_states[i] < 0) {
+ return (make_error(
+ &e__ZoneAdminErrorCode_INVALID_ZONE_STATE,
+ error));
+ }
+ }
+ }
+
+ return (ce_ok);
+}