int chmod_main(const char *controller, const char *cgroup, const char *file, struct ucred p, struct ucred r, int mode) { char rcgpath[MAXPATHLEN]; nih_local char *path = NULL; if (!sane_cgroup(cgroup)) { nih_error("%s: unsafe cgroup", __func__); return -1; } if (file && ( strchr(file, '/') || strchr(file, '\\')) ) { nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, "invalid file"); return -1; } // Get r's current cgroup in rcgpath if (!compute_pid_cgroup(r.pid, controller, "", rcgpath, NULL)) { nih_error("%s: Could not determine the requested cgroup", __func__); return -1; } path = NIH_MUST( nih_sprintf(NULL, "%s/%s", rcgpath, cgroup) ); if (file && strlen(file)) NIH_MUST( nih_strcat_sprintf(&path, NULL, "/%s", file) ); if (realpath_escapes(path, rcgpath)) { nih_error("%s: Invalid path %s", __func__, path); return -1; } // is r allowed to descend under the parent dir? if (!may_access(r.pid, r.uid, r.gid, path, O_RDONLY)) { nih_error("%s: pid %d (uid %u gid %u) may not read under %s", __func__, r.pid, r.uid, r.gid, path); return -1; } // does r have privilege over the cgroup dir? if (!may_access(r.pid, r.uid, r.gid, path, O_RDWR)) { nih_error("%s: Pid %d may not chmod %s\n", __func__, r.pid, path); return -1; } // go ahead and chmod it. if (!chmod_cgroup_path(path, mode)) { nih_error("%s: Failed to change mode on %s to %d", __func__, path, mode); return -1; } return 0; }
static void get_active_controllers(void) { int i; nih_local char **list = cgm_list_controllers(); if (!list) { mysyslog(LOG_NOTICE, "unable to detect controllers"); ctrl_list = NIH_MUST( nih_strdup(NULL, "all") ); return; } for (i = 0; list[i]; i++) { if (strcmp(list[i], "name=systemd") == 0) continue; NIH_MUST( nih_strcat_sprintf(&ctrl_list, NULL, "%s%s", ctrl_list ? "," : "", list[i]) ); } }
/** * session_from_dbus: * @parent: parent, * @message: D-Bus message. * * Create a new session, based on the specified D-Bus message. * * Return new Session, or NULL on error. **/ Session * session_from_dbus (const void *parent, NihDBusMessage *message) { const char *sender; DBusError dbus_error; unsigned long unix_user; unsigned long unix_process_id; char root[PATH_MAX]; Session *session; struct passwd *pwd; nih_local char *conf_path = NULL; nih_assert (message != NULL); /* Handle explicit command-line request and alternative request * method (primarily for test framework) to disable session support. */ if (disable_sessions || getenv ("UPSTART_NO_SESSIONS")) return NULL; session_init (); /* Ask D-Bus nicely for the origin uid and/or pid of the caller; * sadly we can't ask the bus daemon for the origin pid, so that * one will just have to stay user-session only. */ dbus_error_init (&dbus_error); sender = dbus_message_get_sender (message->message); if (sender) { unix_user = dbus_bus_get_unix_user (message->connection, sender, &dbus_error); if (unix_user == (unsigned long)-1) { dbus_error_free (&dbus_error); unix_user = 0; } unix_process_id = 0; } else { if (! dbus_connection_get_unix_user (message->connection, &unix_user)) unix_process_id = 0; if (! dbus_connection_get_unix_process_id (message->connection, &unix_process_id)) unix_process_id = 0; } /* If we retrieved a process id, look up the root path for it; * if it's just '/' don't worry so much about it. */ if (unix_process_id) { nih_local char *symlink = NULL; ssize_t len; symlink = NIH_MUST (nih_sprintf (NULL, "/proc/%lu/root", unix_process_id)); len = readlink (symlink, root, sizeof root); if (len < 0) return NULL; root[len] = '\0'; if (! strcmp (root, "/")) { unix_process_id = 0; if (! unix_user) return NULL; } } else if (! unix_user) { /* No process id or user id found, return the NULL session */ return NULL; } if (unix_user) { pwd = getpwuid (unix_user); if (! pwd || ! pwd->pw_dir) { nih_error ("%lu: %s: %s", unix_user, _("Unable to lookup home directory"), strerror (errno)); return NULL; } NIH_MUST (nih_strcat_sprintf (&conf_path, NULL, "%s/%s", pwd->pw_dir, USERCONFDIR)); } /* Now find in the existing Sessions list */ NIH_LIST_FOREACH_SAFE (sessions, iter) { Session *session = (Session *)iter; if (unix_process_id) { if (! session->chroot) continue; /* ignore sessions relating to other chroots */ if (strcmp (session->chroot, root)) continue; } /* ignore sessions relating to other users */ if (unix_user != session->user) continue; /* Found a user with the same uid but different * conf_dir to the existing session user. Either the * original user has been deleted and a new user created * with the same uid, or the original users home * directory has changed since they first started * running jobs. Whatever the reason, we (can only) honour * the new value. * * Since multiple users with the same uid are considered * to be "the same user", invalidate the old path, * allowing the correct new path to be set below. * * Note that there may be a possibility of trouble if * the scenario relates to a deleted user and that original * user still has jobs running. However, if that were the * case, those jobs would likely fail anyway since they * would have no working directory due to the original * users home directory being deleted/changed/made inaccessible. */ if (unix_user && conf_path && session->conf_path && strcmp (conf_path, session->conf_path)) { nih_free (session->conf_path); session->conf_path = NULL; } if (! session->conf_path) session_create_conf_source (session); return session; }
void test_strcat_sprintf (void) { char *str, *ret; TEST_FUNCTION ("test_strcat_sprintf"); /* Check that we can extend a string with a formatted string, * resulting in the original string being modified and the new * pointer stored in the argument and returned. */ TEST_FEATURE ("with original string"); TEST_ALLOC_FAIL { char *tmp; TEST_ALLOC_SAFE { str = nih_strdup (NULL, "this"); } tmp = str; ret = nih_strcat_sprintf (&str, NULL, " %s a test %d", "is", 54321); if (test_alloc_failed) { TEST_EQ_P (ret, NULL); TEST_EQ_P (str, tmp); TEST_EQ_STR (str, "this"); nih_free (str); continue; } TEST_NE (ret, NULL); TEST_EQ_P (ret, str); TEST_ALLOC_SIZE (str, 21); TEST_EQ_STR (str, "this is a test 54321"); nih_free (str); } /* Check that when no string is passed, this behaves as sprintf. */ TEST_FEATURE ("with NULL"); TEST_ALLOC_FAIL { str = NULL; ret = nih_strcat_sprintf (&str, NULL, "%s a test %d", "is", 54321); if (test_alloc_failed) { TEST_EQ_P (ret, NULL); TEST_EQ_P (str, NULL); continue; } TEST_NE (ret, NULL); TEST_EQ_P (ret, str); TEST_ALLOC_SIZE (str, 15); TEST_EQ_STR (str, "is a test 54321"); nih_free (str); } }