/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (c) 2015, Eric Koegel * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include "ck-sysdeps.h" static void become_user (uid_t uid) { int res; struct passwd *pwent; errno = 0; pwent = getpwuid (uid); if (pwent == NULL) { g_warning ("Unable to lookup UID: %s", g_strerror (errno)); exit (1); } /* set the group */ errno = 0; res = setegid (pwent->pw_gid); if (res == -1) { g_warning ("Error performing setegid: %s", g_strerror (errno)); exit (1); } /* become the user */ errno = 0; res = seteuid (uid); if (res == -1) { g_warning ("Error performing seteuid: %s", g_strerror (errno)); exit (1); } } static int unlink_cb (const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { int ret = ftwbuf->level > 0 ? remove (fpath) : 0; if (ret) { g_error ("Failed to remove %s, reason was: %s", fpath, strerror(errno)); errno = 0; } return ret; } static int remove_dest_dir (const gchar *dest) { int ret; if ((ret = nftw(dest, unlink_cb, 64, FTW_DEPTH | FTW_PHYS))) { return ret; } errno = 0; ret = seteuid (getuid ()); if (ret == -1) { g_warning ("Error performing seteuid: %s", g_strerror (errno)); exit (1); } ret = remove (dest); if (ret) { g_error ("Failed to remove %s, reason was: %s", dest, strerror (errno)); errno = 0; } return ret; } int main (int argc, char **argv) { GOptionContext *context; gboolean ret; GError *error; static int user_id = -1; static gchar *dest = NULL; static GOptionEntry entries [] = { { "uid", 0, 0, G_OPTION_ARG_INT, &user_id, N_("User ID"), NULL }, { "dest", 0, 0, G_OPTION_ARG_STRING, &dest, N_("Destination to remove"), NULL }, { NULL } }; /* Setup for i18n */ setlocale(LC_ALL, ""); #ifdef ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif /* For now at least restrict this to root */ if (getuid () != 0) { g_warning (_("You must be root to run this program")); exit (1); } context = g_option_context_new (NULL); g_option_context_add_main_entries (context, entries, NULL); error = NULL; ret = g_option_context_parse (context, &argc, &argv, &error); g_option_context_free (context); if (! ret) { g_warning ("%s", error->message); g_error_free (error); exit (1); } /* Ensure we have a dest and that it starts with the correct prefix * so we don't remove something important. */ if (dest == NULL || !g_str_has_prefix (dest, RUNDIR "/user/")) { g_warning ("Invalid Dest"); exit (1); } become_user (user_id); return remove_dest_dir (dest) == 0 ? 0 : 1; }