diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/actions.h | 78 | ||||
-rw-r--r-- | src/common/force.c | 405 | ||||
-rw-r--r-- | src/common/force.h | 85 | ||||
-rw-r--r-- | src/common/security-mac.h | 30 | ||||
-rw-r--r-- | src/common/selinux.c | 156 |
5 files changed, 754 insertions, 0 deletions
diff --git a/src/common/actions.h b/src/common/actions.h new file mode 100644 index 0000000..a78f329 --- /dev/null +++ b/src/common/actions.h @@ -0,0 +1,78 @@ +/* + * dpkg - main program for package management + * actions.h - command action definition list + * + * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk> + * Copyright © 2006, 2008-2016 Guillem Jover <guillem@debian.org> + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef DPKG_ACTIONS_H +#define DPKG_ACTIONS_H + +enum action { + act_unset, + + act_unpack, + act_configure, + act_install, + act_triggers, + act_remove, + act_purge, + act_verify, + act_commandfd, + + act_status, + act_listpackages, + act_listfiles, + act_searchfiles, + act_controlpath, + act_controllist, + act_controlshow, + + act_cmpversions, + + act_arch_add, + act_arch_remove, + act_printarch, + act_printforeignarches, + + act_assert_feature, + + act_validate_pkgname, + act_validate_trigname, + act_validate_archname, + act_validate_version, + + act_audit, + act_unpackchk, + act_predeppackage, + + act_getselections, + act_setselections, + act_clearselections, + + act_avail, + act_printavail, + act_avclear, + act_avreplace, + act_avmerge, + act_forgetold, + + act_help, + act_version, +}; + +#endif /* DPKG_ACTIONS_H */ diff --git a/src/common/force.c b/src/common/force.c new file mode 100644 index 0000000..c4401f0 --- /dev/null +++ b/src/common/force.c @@ -0,0 +1,405 @@ +/* + * dpkg - main program for package management + * force.c - force operation support + * + * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk> + * Copyright © 2006-2019 Guillem Jover <guillem@debian.org> + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <errno.h> +#include <string.h> +#include <stdbool.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> + +#include <dpkg/macros.h> +#include <dpkg/i18n.h> +#include <dpkg/dpkg.h> +#include <dpkg/dpkg-db.h> +#include <dpkg/options.h> + +#include "force.h" + +static int force_mask; +static int force_flags; + +enum forcetype { + FORCETYPE_DISABLED, + FORCETYPE_ENABLED, + FORCETYPE_DAMAGE, +}; + +static const char * +forcetype_str(enum forcetype type) +{ + switch (type) { + case FORCETYPE_DISABLED: + return " "; + case FORCETYPE_ENABLED: + return "[*]"; + case FORCETYPE_DAMAGE: + return "[!]"; + default: + internerr("unknown force type '%d'", type); + } +} + +static const struct forceinfo { + const char *name; + int flag; + char type; + const char *desc; +} forceinfos[] = { + { + "all", + FORCE_ALL, + FORCETYPE_DAMAGE, + N_("Set all force options"), + }, { + "security-mac", + FORCE_SECURITY_MAC, + FORCETYPE_ENABLED, + N_("Use MAC based security if available"), + }, { + "downgrade", + FORCE_DOWNGRADE, + FORCETYPE_ENABLED, + N_("Replace a package with a lower version"), + }, { + "configure-any", + FORCE_CONFIGURE_ANY, + FORCETYPE_DISABLED, + N_("Configure any package which may help this one"), + }, { + "hold", + FORCE_HOLD, + FORCETYPE_DISABLED, + N_("Install or remove incidental packages even when on hold"), + }, { + "not-root", + FORCE_NON_ROOT, + FORCETYPE_DISABLED, + N_("Try to (de)install things even when not root"), + }, { + "bad-path", + FORCE_BAD_PATH, + FORCETYPE_DISABLED, + N_("PATH is missing important programs, problems likely"), + }, { + "bad-verify", + FORCE_BAD_VERIFY, + FORCETYPE_DISABLED, + N_("Install a package even if it fails authenticity check"), + }, { + "bad-version", + FORCE_BAD_VERSION, + FORCETYPE_DISABLED, + N_("Process even packages with wrong versions"), + }, { + "statoverride-add", + FORCE_STATOVERRIDE_ADD, + FORCETYPE_DISABLED, + N_("Overwrite an existing stat override when adding it"), + }, { + "statoverride-remove", + FORCE_STATOVERRIDE_DEL, + FORCETYPE_DISABLED, + N_("Ignore a missing stat override when removing it"), + }, { + "overwrite", + FORCE_OVERWRITE, + FORCETYPE_DISABLED, + N_("Overwrite a file from one package with another"), + }, { + "overwrite-diverted", + FORCE_OVERWRITE_DIVERTED, + FORCETYPE_DISABLED, + N_("Overwrite a diverted file with an undiverted version"), + }, { + "overwrite-dir", + FORCE_OVERWRITE_DIR, + FORCETYPE_DAMAGE, + N_("Overwrite one package's directory with another's file"), + }, { + "unsafe-io", + FORCE_UNSAFE_IO, + FORCETYPE_DAMAGE, + N_("Do not perform safe I/O operations when unpacking"), + }, { + "script-chrootless", + FORCE_SCRIPT_CHROOTLESS, + FORCETYPE_DAMAGE, + N_("Do not chroot into maintainer script environment"), + }, { + "confnew", + FORCE_CONFF_NEW, + FORCETYPE_DAMAGE, + N_("Always use the new config files, don't prompt"), + }, { + "confold", + FORCE_CONFF_OLD, + FORCETYPE_DAMAGE, + N_("Always use the old config files, don't prompt"), + }, { + "confdef", + FORCE_CONFF_DEF, + FORCETYPE_DAMAGE, + N_("Use the default option for new config files if one\n" + "is available, don't prompt. If no default can be found,\n" + "you will be prompted unless one of the confold or\n" + "confnew options is also given"), + }, { + "confmiss", + FORCE_CONFF_MISS, + FORCETYPE_DAMAGE, + N_("Always install missing config files"), + }, { + "confask", + FORCE_CONFF_ASK, + FORCETYPE_DAMAGE, + N_("Offer to replace config files with no new versions"), + }, { + "architecture", + FORCE_ARCHITECTURE, + FORCETYPE_DAMAGE, + N_("Process even packages with wrong or no architecture"), + }, { + "breaks", + FORCE_BREAKS, + FORCETYPE_DAMAGE, + N_("Install even if it would break another package"), + }, { + "conflicts", + FORCE_CONFLICTS, + FORCETYPE_DAMAGE, + N_("Allow installation of conflicting packages"), + }, { + "depends", + FORCE_DEPENDS, + FORCETYPE_DAMAGE, + N_("Turn all dependency problems into warnings"), + }, { + "depends-version", + FORCE_DEPENDS_VERSION, + FORCETYPE_DAMAGE, + N_("Turn dependency version problems into warnings"), + }, { + "remove-reinstreq", + FORCE_REMOVE_REINSTREQ, + FORCETYPE_DAMAGE, + N_("Remove packages which require installation"), + }, { + "remove-protected", + FORCE_REMOVE_PROTECTED, + FORCETYPE_DAMAGE, + N_("Remove a protected package"), + }, { + "remove-essential", + FORCE_REMOVE_ESSENTIAL, + FORCETYPE_DAMAGE, + N_("Remove an essential package"), + }, { + NULL + } +}; + +bool +in_force(int flags) +{ + return (flags & force_flags) == flags; +} + +void +set_force(int flags) +{ + force_flags |= flags; +} + +void +reset_force(int flags) +{ + force_flags &= ~flags; +} + +char * +get_force_string(void) +{ + const struct forceinfo *fip; + struct varbuf vb = VARBUF_INIT; + + for (fip = forceinfos; fip->name; fip++) { + if ((enum force_flags)fip->flag == FORCE_ALL || + (fip->flag & force_mask) != fip->flag || + !in_force(fip->flag)) + continue; + + if (vb.used) + varbuf_add_char(&vb, ','); + varbuf_add_str(&vb, fip->name); + } + varbuf_end_str(&vb); + + return varbuf_detach(&vb); +} + +static inline void +print_forceinfo_line(int type, const char *name, const char *desc) +{ + printf(" %s %-18s %s\n", forcetype_str(type), name, desc); +} + +static void +print_forceinfo(const struct forceinfo *fi) +{ + char *desc, *line; + + desc = m_strdup(gettext(fi->desc)); + + line = strtok(desc, "\n"); + print_forceinfo_line(fi->type, fi->name, line); + while ((line = strtok(NULL, "\n"))) + print_forceinfo_line(FORCETYPE_DISABLED, "", line); + + free(desc); +} + +void +parse_force(const char *value, bool set) +{ + const struct forceinfo *fip; + + if (strcmp(value, "help") == 0) { + char *force_string = get_force_string(); + + printf(_( +"%s forcing options - control behavior when problems found:\n" +" warn but continue: --force-<thing>,<thing>,...\n" +" stop with error: --refuse-<thing>,<thing>,... | --no-force-<thing>,...\n" +" Forcing things:\n"), dpkg_get_progname()); + + for (fip = forceinfos; fip->name; fip++) + if ((enum force_flags)fip->flag == FORCE_ALL || + (fip->flag & force_mask) == fip->flag) + print_forceinfo(fip); + + printf(_( +"\n" +"WARNING - use of options marked [!] can seriously damage your installation.\n" +"Forcing options marked [*] are enabled by default.\n")); + m_output(stdout, _("<standard output>")); + + printf(_( +"\n" +"Currently enabled options:\n" +" %s\n"), force_string); + + free(force_string); + + exit(0); + } + + for (;;) { + const char *comma; + size_t l; + + comma = strchrnul(value, ','); + l = (size_t)(comma - value); + for (fip = forceinfos; fip->name; fip++) + if (strncmp(fip->name, value, l) == 0 && + strlen(fip->name) == l) + break; + + if (!fip->name) { + badusage(_("unknown force/refuse option '%.*s'"), + (int)min(l, 250), value); + } else if (fip->flag) { + if (set) + set_force(fip->flag); + else + reset_force(fip->flag); + } else { + warning(_("obsolete force/refuse option '%s'"), + fip->name); + } + + if (*comma == '\0') + break; + value = ++comma; + } +} + +void +set_force_default(int mask) +{ + const char *force_env; + const struct forceinfo *fip; + + force_mask = mask; + + /* If we get passed force options from the environment, do not + * initialize from the built-in defaults. */ + force_env = getenv("DPKG_FORCE"); + if (force_env != NULL) { + if (force_env[0] != '\0') + parse_force(force_env, 1); + return; + } + + for (fip = forceinfos; fip->name; fip++) + if (fip->type == FORCETYPE_ENABLED) + set_force(fip->flag); +} + +void +set_force_option(const struct cmdinfo *cip, const char *value) +{ + bool set = cip->arg_int; + + parse_force(value, set); +} + +void +reset_force_option(const struct cmdinfo *cip, const char *value) +{ + reset_force(cip->arg_int); +} + +void +forcibleerr(int forceflag, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + if (in_force(forceflag)) { + warning(_("overriding problem because --force enabled:")); + warningv(fmt, args); + } else { + ohshitv(fmt, args); + } + va_end(args); +} + +int +forcible_nonroot_error(int rc) +{ + if (in_force(FORCE_NON_ROOT) && errno == EPERM) + return 0; + return rc; +} diff --git a/src/common/force.h b/src/common/force.h new file mode 100644 index 0000000..c232c7f --- /dev/null +++ b/src/common/force.h @@ -0,0 +1,85 @@ +/* + * dpkg - main program for package management + * force.h - forced operation support + * + * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk> + * Copyright © 2006, 2008-2019 Guillem Jover <guillem@debian.org> + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef DPKG_FORCE_H +#define DPKG_FORCE_H + +#include <dpkg/dpkg.h> +#include <dpkg/options.h> + +enum DPKG_ATTR_ENUM_FLAGS force_flags { + FORCE_ARCHITECTURE = DPKG_BIT(0), + FORCE_BAD_PATH = DPKG_BIT(1), + FORCE_BAD_VERIFY = DPKG_BIT(2), + FORCE_BAD_VERSION = DPKG_BIT(3), + FORCE_BREAKS = DPKG_BIT(4), + FORCE_CONFF_ASK = DPKG_BIT(5), + FORCE_CONFF_DEF = DPKG_BIT(6), + FORCE_CONFF_MISS = DPKG_BIT(7), + FORCE_CONFF_NEW = DPKG_BIT(8), + FORCE_CONFF_OLD = DPKG_BIT(9), + FORCE_CONFIGURE_ANY = DPKG_BIT(10), + FORCE_CONFLICTS = DPKG_BIT(11), + FORCE_DEPENDS = DPKG_BIT(12), + FORCE_DEPENDS_VERSION = DPKG_BIT(13), + FORCE_DOWNGRADE = DPKG_BIT(14), + FORCE_HOLD = DPKG_BIT(15), + FORCE_NON_ROOT = DPKG_BIT(16), + FORCE_OVERWRITE = DPKG_BIT(17), + FORCE_OVERWRITE_DIR = DPKG_BIT(18), + FORCE_OVERWRITE_DIVERTED = DPKG_BIT(19), + FORCE_REMOVE_ESSENTIAL = DPKG_BIT(20), + FORCE_REMOVE_REINSTREQ = DPKG_BIT(21), + FORCE_SCRIPT_CHROOTLESS = DPKG_BIT(22), + FORCE_UNSAFE_IO = DPKG_BIT(23), + FORCE_STATOVERRIDE_ADD = DPKG_BIT(24), + FORCE_STATOVERRIDE_DEL = DPKG_BIT(25), + FORCE_SECURITY_MAC = DPKG_BIT(26), + FORCE_REMOVE_PROTECTED = DPKG_BIT(27), + FORCE_ALL = 0xffffffff, +}; + +bool +in_force(int flags); +void +set_force(int flags); +void +reset_force(int flags); + +char * +get_force_string(void); + +void +parse_force(const char *value, bool set); + +void +set_force_default(int mask); +void +set_force_option(const struct cmdinfo *cip, const char *value); +void +reset_force_option(const struct cmdinfo *cip, const char *value); + +void +forcibleerr(int forceflag, const char *format, ...) DPKG_ATTR_PRINTF(2); +int +forcible_nonroot_error(int rc); + +#endif /* DPKG_FORCE_H */ diff --git a/src/common/security-mac.h b/src/common/security-mac.h new file mode 100644 index 0000000..637c6f7 --- /dev/null +++ b/src/common/security-mac.h @@ -0,0 +1,30 @@ +/* + * dpkg - main program for package management + * security-mac.h - MAC-based security support + * + * Copyright © 2015 Guillem Jover <guillem@debian.org> + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef DPKG_SECURITY_MAC_H +#define DPKG_SECURITY_MAC_H + +#include <sys/stat.h> + +void dpkg_selabel_load(void); +void dpkg_selabel_set_context(const char *matchpath, const char *path, mode_t mode); +void dpkg_selabel_close(void); + +#endif /* DPKG_SECURITY_MAC_H */ diff --git a/src/common/selinux.c b/src/common/selinux.c new file mode 100644 index 0000000..b5d29d8 --- /dev/null +++ b/src/common/selinux.c @@ -0,0 +1,156 @@ +/* + * dpkg - main program for package management + * selinux.c - SELinux support + * + * Copyright © 2007-2015 Guillem Jover <guillem@debian.org> + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> +#include <unistd.h> + +#include <dpkg/i18n.h> +#include <dpkg/dpkg.h> +#include <dpkg/dpkg-db.h> + +#ifdef WITH_LIBSELINUX +#include <selinux/selinux.h> +#include <selinux/avc.h> +#include <selinux/label.h> +#endif + +#include "force.h" +#include "security-mac.h" + +#ifdef WITH_LIBSELINUX +static struct selabel_handle *sehandle; +#endif + +#ifdef WITH_LIBSELINUX +static int DPKG_ATTR_PRINTF(2) +log_callback(int type, const char *fmt, ...) +{ + va_list ap; + char *msg; + + switch (type) { + case SELINUX_ERROR: + case SELINUX_WARNING: + case SELINUX_AVC: + break; + default: + return 0; + } + + va_start(ap, fmt); + m_vasprintf(&msg, fmt, ap); + va_end(ap); + + warning("selinux: %s", msg); + free(msg); + + return 0; +} +#endif + +void +dpkg_selabel_load(void) +{ +#ifdef WITH_LIBSELINUX + static int selinux_enabled = -1; + + if (selinux_enabled < 0) { + int rc; + + /* Set selinux_enabled if it is not already set (singleton). */ + selinux_enabled = (in_force(FORCE_SECURITY_MAC) && + is_selinux_enabled() > 0); + if (!selinux_enabled) + return; + + /* Open the SELinux status notification channel, with fallback + * enabled for older kernels. */ + rc = selinux_status_open(1); + if (rc < 0) + ohshit(_("cannot open security status notification channel")); + + selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) { + .func_log = log_callback, + }); + } else if (selinux_enabled && selinux_status_updated()) { + /* The SELinux policy got updated in the kernel, usually after + * upgrading the package shipping it, we need to reload. */ + selabel_close(sehandle); + } else { + /* SELinux is either disabled or it does not need a reload. */ + return; + } + + sehandle = selabel_open(SELABEL_CTX_FILE, NULL, 0); + if (sehandle == NULL && security_getenforce() == 1) + ohshite(_("cannot get security labeling handle")); +#endif +} + +void +dpkg_selabel_set_context(const char *matchpath, const char *path, mode_t mode) +{ +#ifdef WITH_LIBSELINUX + char *scontext = NULL; + int ret; + + /* If SELinux is not enabled just do nothing. */ + if (sehandle == NULL) + return; + + /* + * We use the _raw function variants here so that no translation + * happens from computer to human readable forms, to avoid issues + * when mcstransd has disappeared during the unpack process. + */ + + /* Do nothing if we can't figure out what the context is, or if it has + * no context; in which case the default context shall be applied. */ + ret = selabel_lookup_raw(sehandle, &scontext, matchpath, mode & S_IFMT); + if (ret == -1 || (ret == 0 && scontext == NULL)) + return; + + ret = lsetfilecon_raw(path, scontext); + if (ret < 0 && errno != ENOTSUP) + ohshite(_("cannot set security context for file object '%s'"), + path); + + freecon(scontext); +#endif /* WITH_LIBSELINUX */ +} + +void +dpkg_selabel_close(void) +{ +#ifdef WITH_LIBSELINUX + if (sehandle == NULL) + return; + + selinux_status_close(); + selabel_close(sehandle); + sehandle = NULL; +#endif +} |