Jump to content
Read the Funtoo Newsletter: Summer 2023 ×

acct-user/acct-group seems wrong


Recommended Posts

My considerations about "problem" with constant uid/gid between machines.
Hope i understood correctly motivations from glep 81.
If we need a constant uid/gid for some packages, then we need something like /etc/services for uid and gid.
For example, /var/git/meta-repo/user-uid.map and /var/git/meta-repo/group-gid.map.
Format of these files could be:
user-uid.map:
UNAME  SP UID

group-gid.map:
GNAME SP GID

Where:
  UNAME - user name
  GNAME - group name
  UID - user id
  GID - group id
  SP - spaces and/or tabs ([ \t]+)

Then we should modify user.eclass a little. In such a way that enewuser and enewgroup must do 2 things:
- consult these files for constant uid/gid(if, for example, -S is specified)
- place package name which call enewgroup/enewuser in /var/lib/portage/group-pkg.map and /var/lib/portage/user-pkg.map respectively

Example changes for enewgroup:

--- user.eclass.orig    2020-05-06 09:27:19.264986735 +0000
+++ user.eclass 2020-05-06 16:09:38.664894650 +0000
@@ -262,6 +262,8 @@
 #
 # If -F is passed, enewgroup will always enforce specified GID and fail if it
 # can not be assigned.
+# If -S is passed, gid is got from group-gid.map; if -F is also passed and
+# such user already exist with different gid, then enewgroup fail.
 enewgroup() {
        if [[ ${EUID} != 0 ]] ; then
                einfo "Insufficient privileges to execute ${FUNCNAME[0]}"
@@ -269,10 +271,11 @@
        fi
        _assert_pkg_ebuild_phase ${FUNCNAME}
 
-       local force_gid=
+       local force_gid= strict_gid=
        while [[ $1 == -* ]]; do
                case $1 in
                        -F) force_gid=1;;
+                       -S) strict_gid=1;;
                        *) die "${FUNCNAME}: invalid option ${1}";;
                esac
                shift
@@ -287,6 +290,12 @@
 
        # see if group already exists
        if [[ -n $(egetent group "${egroup}") ]] ; then
+               local egid=$(emapget /var/git/meta-repo/group-gid.map ${egroup})
+               if [[ -n ${strict_gid} && -n ${force_gid} && \
+                 $(egetent group "${egroup}" | cut -d: -f3) != ${egid} ]] ; then
+                       die "${egroup} exist, but GID for ${egroup} group must be ${egid}"
+               fi
+               emapaddval /var/lib/portage/user-pkg.map ${egroup} ${PN}
                return 0
        fi
        einfo "Adding group '${egroup}' to your system ..."
@@ -294,6 +303,9 @@
        # handle gid
        local egid=$1; shift
        if [[ ! -z ${egid} ]] ; then
+               if [[ -n ${strict_gid} ]] ; then
+                       die "${FUNCNAME}: -S can't be specified with GID"
+               fi
                if [[ ${egid} -gt 0 ]] ; then
                        if [[ -n $(egetent group ${egid}) ]] ; then
                                [[ -n ${force_gid} ]] && die "${FUNCNAME}: GID ${egid} already taken"
@@ -304,8 +316,16 @@
                        die "${egid} is not a valid GID"
                fi
        else
-               [[ -n ${force_gid} ]] && die "${FUNCNAME}: -F with gid==-1 makes no sense"
-               egid="next available"
+               if [[ -n ${strict_gid} ]] ; then
+                       egid=$(emapget /var/git/meta-repo/group-gid.map ${egroup})
+                       if [[ -z ${egid} ]] ; then
+                               die "${FUNCNAME}: group ${egroup} doesn't exist in /var/git/meta-repo/group-gid.map"
+                       fi
+               elif [[ -n ${force_gid} ]] ; then
+                       die "${FUNCNAME}: -F with gid==-1 makes no sense"
+               else
+                       egid="next available"
+               fi
        fi
        einfo " - Groupid: ${egid}"
 
@@ -349,6 +369,158 @@
                groupadd -r ${opts} "${egroup}" || die
                ;;
        esac
+       emapaddval /var/lib/portage/user-pkg.map ${egroup} ${PN}
+}
+
+emapget() {
+       local mapfile=$1 key=$2
+
+       # TODO: here must be a file lock
+       if [[ ! -f ${mapfile} ]]; then
+               return 0
+       fi
+       awk -v key=$key '
+       $1 == key {
+               values=$2
+               for(i = 3; i <= NF; i++) {
+                       values=values " " $i
+               }
+               print values
+               exit
+       }' ${mapfile}
+}
+
+emapset() {
+       local mapfile=$1 key=$2
+       shift 2
+       local values="$@"
+
+       # TODO: here must be a file lock
+       if [[ ! -f ${mapfile} ]]; then
+               touch ${mapfile}
+       fi
+       awk -v key=$key -v values="$values" '
+       $1 != key {
+               print $0
+       }
+       $1 == key {
+               is_found=1
+               print key " " values
+       }
+       END {
+               if (!is_found) {
+                       print key " " values
+               }
+       }' ${mapfile} > ${PORTAGE_TMPDIR}/$(basename ${mapfile}).$$.TMP
+       if [[ $? -ne 0 ]] ; then
+               rm ${PORTAGE_TMPDIR}/$(basename ${mapfile}).$$.TMP
+               die "emapset error: awk error"
+       fi
+       mv ${PORTAGE_TMPDIR}/$(basename ${mapfile}).$$.TMP ${mapfile}
+       if [[ $? -ne 0 ]] ; then
+               rm ${PORTAGE_TMPDIR}/$(basename ${mapfile}).$$.TMP
+               die "emapset error: mv error"
+       fi
+}
+
+emaprm() {
+       local mapfile=$1 key=$2
+
+       # TODO: here must be a file lock
+       if [[ ! -f ${mapfile} ]]; then
+               return 0
+       fi
+       awk -v key=$key '
+       $1 != key {
+               print $0
+       }' ${mapfile} > $PORTAGE_TMPDIR/$(basename ${mapfile}).$$.TMP
+       if [[ $? -ne 0 ]] ; then
+               rm $PORTAGE_TMPDIR/$(basename ${mapfile}).$$.TMP
+               die "emaprm error: awk error"
+       fi
+       mv $PORTAGE_TMPDIR/$(basename ${mapfile}).$$.TMP ${mapfile}
+       if [[ $? -ne 0 ]] ; then
+               rm $PORTAGE_TMPDIR/$(basename ${mapfile}).$$.TMP
+               die "emaprm error: mv error"
+       fi
+}
+
+emapaddval() {
+       local mapfile=$1 key=$2
+       shift 2
+       local values="$@"
+
+       # TODO: here must be a file lock
+       if [[ ! -f ${mapfile} ]]; then
+               touch ${mapfile}
+       fi
+       awk -v key=$key -v values="$values" '
+       $1 != key {
+               print $0
+       }
+       $1 == key {
+               is_found = 1
+               vtoadd = ""
+               n = split(values, vals)
+               for(i = 1; i <= n; i++) {
+                       for(j = 2; j <= NF; j++)
+                               if ($j == vals[i])
+                                       break
+                       if (j == (NF+1))
+                               vtoadd = vtoadd " " vals[i]
+               }
+               print $0 vtoadd
+       }
+       END {
+               if (!is_found) {
+                       print key " " values
+               }
+       }' ${mapfile} > $PORTAGE_TMPDIR/$(basename ${mapfile}).$$.TMP
+       if [[ $? -ne 0 ]] ; then
+               rm ${PORTAGE_TMPDIR}/$(basename ${mapfile}).$$.TMP
+               die "${FUNCNAME}: awk error"
+       fi
+       mv $PORTAGE_TMPDIR/$(basename ${mapfile}).$$.TMP ${mapfile}
+       if [[ $? -ne 0 ]] ; then
+               rm ${PORTAGE_TMPDIR}/$(basename ${mapfile}).$$.TMP
+               die "${FUNCNAME}: mv error"
+       fi
+}
+
+emaprmval() {
+       local mapfile=$1 key=$2
+       shift 2
+       local values="$@"
+
+       # TODO: here must be a file lock
+       if [[ ! -f ${mapfile} ]]; then
+               return 0
+       fi
+       awk -v key=$key -v values="$values" '
+       $1 != key {
+               print $0
+       }
+       $1 == key {
+               vnew = ""
+               n = split(values, vals)
+               for(i = 2; i <= NF; i++) {
+                       for(j = 1; j <= n; j++)
+                               if ($i == vals[j])
+                                       break
+                       if (j == (n+1))
+                               vnew = vnew " " $i
+               }
+               print key vnew
+       }' ${mapfile} > ${PORTAGE_TMPDIR}/$(basename ${mapfile}).$$.TMP
+       if [[ $? -ne 0 ]] ; then
+               rm ${PORTAGE_TMPDIR}/$(basename ${mapfile}).$$.TMP
+               die "emaprmval error: awk error"
+       fi
+       mv ${PORTAGE_TMPDIR}/$(basename ${mapfile}).$$.TMP ${mapfile}
+       if [[ $? -ne 0 ]] ; then
+               rm ${PORTAGE_TMPDIR}/$(basename ${mapfile}).$$.TMP
+               die "emaprmval error: can't do mv"
+       fi
 }
 
 # @FUNCTION: egetusername

 

After that we have info in /var/lib/portage/user-pkg.map and /var/lib/portage/group-pkg.map about what user/group is used by what packages. And can show this with equery module. If we see user/group without packages - this entry is orphaned. We can show this with a same equery module and give a user possibility to remove this with some ego module(something like "ego user cleanup" and "ego group cleanup").

Link to comment
Share on other sites

user-uid.map can contain shell, homedir and groups in addition to uid. Thus, enewuser can derive all needed parameters from the map file(so, if many packages really need the same user, they can create it independently).

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...