Add proof-of-concept sys-user eclass for installing users/groups.
authorMichael Orlitzky <michael@orlitzky.com>
Sun, 29 Jan 2017 02:23:24 +0000 (21:23 -0500)
committerMichael Orlitzky <michael@orlitzky.com>
Sun, 29 Jan 2017 02:23:24 +0000 (21:23 -0500)
eclass/sys-user.eclass [new file with mode: 0644]
profiles/categories [new file with mode: 0644]
sys-group/tcpdump/Manifest [new file with mode: 0644]
sys-group/tcpdump/metadata.xml [new file with mode: 0644]
sys-group/tcpdump/tcpdump-0.ebuild [new file with mode: 0644]
sys-user/tcpdump/Manifest [new file with mode: 0644]
sys-user/tcpdump/metadata.xml [new file with mode: 0644]
sys-user/tcpdump/tcpdump-0.ebuild [new file with mode: 0644]

diff --git a/eclass/sys-user.eclass b/eclass/sys-user.eclass
new file mode 100644 (file)
index 0000000..65b731f
--- /dev/null
@@ -0,0 +1,236 @@
+# Copyright 1999-2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+# @ECLASS: sys-user.eclass
+# @MAINTAINER:
+# Michael Orlitzky <mjo@gentoo.org>
+# @BLURB: handle installation and removal of system users.
+# @DESCRIPTION:
+# This eclass does most of the work for the sys-user/ packages that
+# supply system user accounts.
+
+inherit user
+
+EXPORT_FUNCTIONS src_unpack src_prepare src_configure src_compile src_install src_test pkg_preinst pkg_postinst pkg_prerm
+
+# This is hard-coded to the package name. If you want a different
+# username, use a different package name. This is a nice way to prevent
+# different people from claiming the same username.
+SYS_USER_NAME="${PN}"
+
+# @ECLASS-VARIABLE: SYS_USER_GROUPS
+# @DESCRIPTION:
+# etc.
+: ${SYS_USER_GROUPS:=${PN}}
+
+# @ECLASS-VARIABLE: SYS_USER_UID
+# @DESCRIPTION:
+# etc. (use -1 to get next available using user.eclass)
+: ${SYS_USER_UID:=-1}
+
+# In many cases, if the UID of a user changes, packages depending on it
+# will want to rebuild. We always use SLOT=0, because you can't install
+# the same user twice. Then we use the UID as our subslot so that
+# subslot deps can be used to rebuild packages when our UID changes.
+SLOT="0/${SYS_USER_UID}"
+
+# @ECLASS-VARIABLE: SYS_USER_HOME
+# @DESCRIPTION:
+# etc. (use -1 to get user.eclass default)
+: ${SYS_USER_HOME:=-1}
+
+# @ECLASS-VARIABLE: SYS_USER_SHELL
+# @DESCRIPTION:
+# etc. (use -1 to get user.eclass default)
+: ${SYS_USER_SHELL:=-1}
+
+case ${EAPI} in
+       6) ;;
+       *)
+               die "${ECLASS} is not compatible with EAPI=${EAPI}"
+esac
+
+# Depend on any groups we might need.
+for _group in ${SYS_USER_GROUPS}; do
+       DEPEND+=" sys-group/${_group} "
+       RDEPEND+=" sys-group/${_group}:= "
+done
+unset _group
+
+S="${WORKDIR}"
+
+sys-user_src_unpack() { :; }
+sys-user_src_prepare() { :; }
+sys-user_src_configure() { :; }
+sys-user_src_compile() { :; }
+sys-user_src_test() { :; }
+
+sys-user_next_uid() {
+       local euid;
+       for (( euid = 101; euid <= 999; euid++ )); do
+               [[ -z $(egetent passwd "${euid}") ]] && break
+       done
+       if (( "${euid}" == 999 )); then
+               die "out of available UIDs!"
+       else
+               echo "${euid}"
+       fi
+}
+
+sys-user_src_prepare() {
+       eapply_user # whatever
+
+       if [[ -n $(egetent passwd "${SYS_USER_NAME}") ]]; then
+               # UPGRADE PATH: This user already exists, so if the eclass
+               # consumer doesn't care about some settings, we can reuse the
+               # pre-existing ones.
+               #
+               # This is also useful for sys-user package upgrades, becaused it
+               # prevents us from incrementing the UID pointlessly on a
+               # reinstall. Usually that will prevent rebuilds of depending
+               # packages, and is crucial to our ability to use subslot deps to
+               # cause rebuilds when the UID changes. We don't want the UID to
+               # change if the subslot doesn't change, and the subslot for "I
+               # don't care about the UID" will always be "-1", so the UID
+               # shouldn't generally change either when SYS_USER_UID=-1.
+               if (( "${SYS_USER_UID}" == -1 )); then
+                       SYS_USER_UID=$(id --real --user "${SYS_USER_NAME}")
+               fi
+
+               if (( "${SYS_USER_HOME}" == -1 )); then
+                       SYS_USER_HOME=$(egethome "${SYS_USER_NAME}")
+               fi
+
+               if (( "${SYS_USER_SHELL}" == -1 )); then
+                       SYS_USER_SHELL=$(egetshell "${SYS_USER_NAME}")
+
+                       if [[ ${SYS_USER_SHELL} == */false ]] || \
+                                  [[ ${SYS_USER_SHELL} == */nologin ]]; then
+                               # WHYYYYY? enewuser complains if we try to set a default
+                               # shell explicitly.
+                               SYS_USER_SHELL="-1"
+                       fi
+               fi
+       elif (( "${SYS_USER_UID}" == -1 )); then
+               # There is no pre-existing user (i.e. this isn't along the
+               # upgrade path), and the consumer says he doesn't care about the
+               # UID, so pick the next one.
+               SYS_USER_UID=$(sys-user_next_uid)
+       fi
+
+       # We do something with this in src_install.
+       touch "${T}/${SYS_USER_UID}" || die
+}
+
+sys-user_src_install() {
+       # Install a placeholder file to /var/lib/sys-user/$uid. This will
+       # cause collisions if two packages try to install users with the
+       # same UID. The same problem potentially exists with the username,
+       # but as long as SYS_USER_NAME is hard-coded to $PN, that shouldn't
+       # be possible.
+       #
+       # Beware, this only works if SYS_USER_UID is guaranteed to have a
+       # real UID and not, for example, -1. That is taken care of in
+       # src_prepare() for now.
+       insinto "/var/lib/sys-user"
+       doins "${T}/${SYS_USER_UID}"
+
+       # TODO: do we want to try to create the user's home directory within
+       # the package manager so that it can be cleaned up later? The
+       # obvious problem with that plan is that we need to be careful not
+       # to give the new user ownership of e.g. /dev/null.
+}
+
+sys-user_pkg_preinst() {
+       if [[ -z $(egetent passwd "${SYS_USER_NAME}") ]]; then
+               # The user does not already exist. This is the nice and easy
+               # case because no matter how we got here, we want to go ahead
+               # and create the (new) user.
+               enewuser "${SYS_USER_NAME}" \
+                                "${SYS_USER_UID}" \
+                                "${SYS_USER_SHELL}" \
+                                "${SYS_USER_HOME}" \
+                                "${SYS_USER_GROUPS}" \
+                       || die "failed to add user ${SYS_USER_NAME}"
+       elif [[ -n "${REPLACING_VERSIONS}" ]]; then
+                # This is an upgrade from an existing sys-user package. This
+                # case is a little bit weird. If we do it in preinst(), then it
+                # will happen before the "old" user is removed in
+                # pkg_prerm(). Except the old user and the new user are the
+                # same, so if we overwrite the existing user here, then prerm
+                # for the version that created it will clobber our new entry.
+                #
+                # We also can't just LEAVE the old user there, because then no
+                # upgrade happens.
+                #
+                # Uh, let's do this case in pkg_postinst so that it happens
+                # after the old version's prerm.
+                :
+       else
+               # UPGRADE PATH: Ok, the user exists but this isn't an upgrade of
+               # a sys-user package. This is the upgrade path from the old
+               # style of user/group management to the new style. What can we
+               # do? We could make it policy that old users must be compatible
+               # with the new ones, but that entails hard-coding UIDs that
+               # don't need to be hard-coded.
+               #
+               # Instead lets see if the new user is compatible with the old
+               # (it usually will be), and then only bail out if there's a real
+               # problem.
+               local oldhome=$(egethome "${SYS_USER_NAME}")
+               local oldshell=$(egetshell "${SYS_USER_NAME}")
+               local olduid=$(id --real --user "${SYS_USER_NAME}")
+
+               if [[ "${oldhome}" -ne "${SYS_USER_HOME}" ]]; then
+                       die "home directory conflict for new user ${SYS_USER_HOME}"
+               fi
+
+               if [[ "${oldhshell}" -ne "${SYS_USER_SHELL}" ]]; then
+                       die "shell conflict for new user ${SYS_USER_HOME}"
+               fi
+
+               if [[ "${olduid}" -ne "${SYS_USER_UID}" ]]; then
+                       die "UID conflict for new user ${SYS_USER_NAME}"
+               fi
+
+               # The user already exists, so all we have left to do is to try
+               # to append SYS_USER_GROUPS to the existing groups. The "usermod"
+               # tool expects a comma-separated list, so change our spaces to
+               # commas. This does succeed if you append duplicates.
+               usermod --append --groups "${SYS_USER_GROUPS// /,}" \
+                       || die "failed to append groups to existing user ${SYS_USER_NAME}"
+       fi
+}
+
+sys-user_pkg_postinst() {
+       if [[ -n "${REPLACING_VERSIONS}" ]]; then
+          # This is an upgrade from a previous version of a sys-user
+          # package. This case has to be handled carefully to make sure
+          # that the pkg_prerm() of the old version doesn't remove the user
+          # that this new version is going to add. At this point, in our
+          # pkg_postinst(), the old version's pkg_prerm() phase should have
+          # already happened.
+          if [[ -n $(egetent passwd "${SYS_USER_NAME}") ]]; then
+                  die "User ${SYS_USER_NAME} already exists during an upgrade."
+          else
+                  enewuser "${SYS_USER_NAME}" \
+                                       "${SYS_USER_UID}" \
+                                       "${SYS_USER_SHELL}" \
+                                       "${SYS_USER_HOME}" \
+                                       "${SYS_USER_GROUPS}" \
+                          || die "failed to add user ${SYS_USER_NAME}"
+          fi
+       fi
+}
+
+sys-user_pkg_prerm() {
+       if [[ -z $(egetent passwd "${SYS_USER_NAME}") ]]; then
+               # We have successfully done nothing.
+               ewarn "Tried to remove nonexistent user ${SYS_USER_NAME}."
+       else
+               userdel "${SYS_USER_NAME}" || \
+                       die "failed to remove user ${SYS_USER_NAME}"
+               einfo "Removed user ${SYS_USER_NAME} from the system."
+       fi
+}
diff --git a/profiles/categories b/profiles/categories
new file mode 100644 (file)
index 0000000..3d1160f
--- /dev/null
@@ -0,0 +1,2 @@
+sys-user
+sys-group
diff --git a/sys-group/tcpdump/Manifest b/sys-group/tcpdump/Manifest
new file mode 100644 (file)
index 0000000..533fca4
--- /dev/null
@@ -0,0 +1,2 @@
+EBUILD tcpdump-0.ebuild 296 SHA256 5e8e06824597b8e566c1e02caac20527f402c9172b80305e94144d7c14f4ce3a SHA512 3aebd8e0f0932fe9af7635d34894fe68103e862af8ec93b4ac611a20c0079123a479b03a3e71c5cf489349ae1353f576d0977f557656ad93786b09009d344a25 WHIRLPOOL 45bf28123ba735000f449aa1e6fdc5f142016831bdbe4d43f716a71cbfe02cad3b8c7a9876930107eca131b24f147b504be42604fbb7a50ce7a98ba17f0f852e
+MISC metadata.xml 533 SHA256 f0a9810780f90804554690040776736f8f95d79fb5225d1df8f9e1b94f2a94f2 SHA512 3303989855dc26af76cd2fd5ad93fcb70d5484886a122c72a2c71f7dc2070b23bf8c25a46180a4ebc6ffb6537e2b78354e8f24a1167a831a7498475b12712827 WHIRLPOOL e6e19f8dc8e0e88382e11e20c1a68e418469297dad2b34e98998e44eeeb6c374c012c39b1ce6f38c0614e3f360696864247daa0ebf5107b0bff61f994f7088a7
diff --git a/sys-group/tcpdump/metadata.xml b/sys-group/tcpdump/metadata.xml
new file mode 100644 (file)
index 0000000..a7ca9ec
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
+<pkgmetadata>
+  <!--
+  <maintainer type="project">
+    <email></email>
+    <name></name>
+  </maintainer>
+  -->
+  <maintainer type="person">
+    <email>mjo@gentoo.org</email>
+    <name>Michael Orlitzky</name>
+  </maintainer>
+  <!--
+    <use>
+      <flag name='aspell'>Uses <pkg>app-text/aspell</pkg> for spell checking.
+      Requires an installed dictionary from <cat>app-dicts</cat></flag>
+    </use>
+  -->
+</pkgmetadata>
diff --git a/sys-group/tcpdump/tcpdump-0.ebuild b/sys-group/tcpdump/tcpdump-0.ebuild
new file mode 100644 (file)
index 0000000..e05878c
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright 1999-2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+EAPI=6
+
+DESCRIPTION="The tcpdump system group"
+HOMEPAGE="https://www.gentoo.org/"
+SRC_URI=""
+
+LICENSE="GPL-2"
+SLOT="0"
+KEYWORDS="~amd64 ~x86"
+IUSE=""
+
+DEPEND=""
+RDEPEND="${DEPEND}"
diff --git a/sys-user/tcpdump/Manifest b/sys-user/tcpdump/Manifest
new file mode 100644 (file)
index 0000000..d77a09c
--- /dev/null
@@ -0,0 +1,2 @@
+EBUILD tcpdump-0.ebuild 313 SHA256 1e33bfc902f64357bf6d97d749743ebf9cc61a4b995777bff055020c9c1c74cf SHA512 5cbdf67fc8f6efa417107e20062c7a1c169edf7bd012014f9692944ef2ae78624dad81cedb9935422beaa97122bb353a9baf5e44b920bcb135db68d84c4d9fb6 WHIRLPOOL 15d9e0df558a1487a05d517590077de187839edd6eeec0ce81dfc8d88a566734ac930732808828330c4d0ffd336d12e70933614245da8829dd19e0705eed2948
+MISC metadata.xml 533 SHA256 f0a9810780f90804554690040776736f8f95d79fb5225d1df8f9e1b94f2a94f2 SHA512 3303989855dc26af76cd2fd5ad93fcb70d5484886a122c72a2c71f7dc2070b23bf8c25a46180a4ebc6ffb6537e2b78354e8f24a1167a831a7498475b12712827 WHIRLPOOL e6e19f8dc8e0e88382e11e20c1a68e418469297dad2b34e98998e44eeeb6c374c012c39b1ce6f38c0614e3f360696864247daa0ebf5107b0bff61f994f7088a7
diff --git a/sys-user/tcpdump/metadata.xml b/sys-user/tcpdump/metadata.xml
new file mode 100644 (file)
index 0000000..a7ca9ec
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
+<pkgmetadata>
+  <!--
+  <maintainer type="project">
+    <email></email>
+    <name></name>
+  </maintainer>
+  -->
+  <maintainer type="person">
+    <email>mjo@gentoo.org</email>
+    <name>Michael Orlitzky</name>
+  </maintainer>
+  <!--
+    <use>
+      <flag name='aspell'>Uses <pkg>app-text/aspell</pkg> for spell checking.
+      Requires an installed dictionary from <cat>app-dicts</cat></flag>
+    </use>
+  -->
+</pkgmetadata>
diff --git a/sys-user/tcpdump/tcpdump-0.ebuild b/sys-user/tcpdump/tcpdump-0.ebuild
new file mode 100644 (file)
index 0000000..b812dab
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright 1999-2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+EAPI=6
+
+inherit sys-user
+
+DESCRIPTION="The tcpdump system user"
+HOMEPAGE="https://www.gentoo.org/"
+SRC_URI=""
+
+LICENSE="GPL-2"
+KEYWORDS="~amd64 ~x86"
+IUSE=""
+
+DEPEND=""
+RDEPEND="${DEPEND}"