[OE-core] [PATCH v2 2/2] systemd: add users/groups at build rather than runtime
Khem Raj
raj.khem at gmail.com
Tue May 10 00:58:07 UTC 2016
> On May 9, 2016, at 5:55 PM, Stephano Cetola <stephano.cetola at linux.intel.com> wrote:
>
> On 05/09, Khem Raj wrote:
>>
>>> On May 9, 2016, at 4:42 PM, Stephano Cetola <stephano.cetola at linux.intel.com> wrote:
>>>
>>> This fix ensures that systemd users are created at build and that any
>>> staticids for the users or groups are preserved. This functionality only
>>> existed for readonly filesystems, however it seems wise to be sure these
>>> users are added rather than relying on systemd to create them.
>>
>> We need to cover the case where online package management is used. If you were to fix
>> it in systemd recipe itself which takes care of creating these users in post installs
>> that will fix it for this case too.
> I'm not sure I follow you. I can see how this could be done in a post
> install script, but I'm missing how this would help online package
> management. Could you please point me in the right direction?
Lets say, I did not install microhttpserver in default image. But later on I decided to install it via
O_P_M feeds. or remove for that matter.
>>
>>>
>>> [ YOCTO #9497 ]
>>>
>>> Signed-off-by: Stephano Cetola <stephano.cetola at linux.intel.com>
>>> ---
>>> meta/classes/rootfs-postcommands.bbclass | 66 +++++++++++++++++++++-----------
>>> meta/classes/useradd-staticids.bbclass | 56 +--------------------------
>>> useradd-staticids-list.bbclass | 56 +++++++++++++++++++++++++++
>>> 3 files changed, 100 insertions(+), 78 deletions(-)
>>> create mode 100644 useradd-staticids-list.bbclass
>>>
>>> diff --git a/meta/classes/rootfs-postcommands.bbclass b/meta/classes/rootfs-postcommands.bbclass
>>> index 95d28af..db4cc75 100644
>>> --- a/meta/classes/rootfs-postcommands.bbclass
>>> +++ b/meta/classes/rootfs-postcommands.bbclass
>>> @@ -1,4 +1,4 @@
>>> -
>>> +inherit useradd-staticids-list
>>> # Zap the root password if debug-tweaks feature is not enabled
>>> ROOTFS_POSTPROCESS_COMMAND += '${@bb.utils.contains_any("IMAGE_FEATURES", [ 'debug-tweaks', 'empty-root-password' ], "", "zap_empty_root_password ; ",d)}'
>>>
>>> @@ -23,6 +23,9 @@ POSTINST_LOGFILE ?= "${localstatedir}/log/postinstall.log"
>>> SYSTEMD_DEFAULT_TARGET ?= '${@bb.utils.contains("IMAGE_FEATURES", "x11-base", "graphical.target", "multi-user.target", d)}'
>>> ROOTFS_POSTPROCESS_COMMAND += '${@bb.utils.contains("DISTRO_FEATURES", "systemd", "set_systemd_default_target; ", "", d)}'
>>>
>>> +# Create systemd users at build rather than at runtime
>>> +ROOTFS_POSTPROCESS_COMMAND += '${@bb.utils.contains("DISTRO_FEATURES", "systemd", "create_systemd_sysusers; ", "", d)}'
>>> +
>>> ROOTFS_POSTPROCESS_COMMAND += 'empty_var_volatile;'
>>>
>>> # Disable DNS lookups, the SSH_DISABLE_DNS_LOOKUP can be overridden to allow
>>> @@ -30,7 +33,45 @@ ROOTFS_POSTPROCESS_COMMAND += 'empty_var_volatile;'
>>> SSH_DISABLE_DNS_LOOKUP ?= " ssh_disable_dns_lookup ; "
>>> ROOTFS_POSTPROCESS_COMMAND_append_qemuall = "${SSH_DISABLE_DNS_LOOKUP}"
>>>
>>> -
>>> +# Add systemd users checking for any staticids
>>> +python create_systemd_sysusers () {
>>> + import shlex
>>> + import subprocess
>>> + s_users = merge_files(get_passwd_list(d), 7)
>>> + s_groups = merge_files(get_group_list(d), 4)
>>> + confs = ['%s/usr/lib/sysusers.d/systemd.conf' % d.getVar('IMAGE_ROOTFS', d), '%s/usr/lib/sysusers.d/systemd-remote.conf' % d.getVar('IMAGE_ROOTFS', d)]
>>> + for conf in confs:
>>> + if os.path.isfile(conf):
>>> + with open(conf, 'r') as f:
>>> + for line in f:
>>> + if line.startswith('#'):
>>> + continue
>>> + fields = shlex.split(line.rstrip())
>>> + if not fields:
>>> + continue
>>> + if fields[0] == 'u':
>>> + useradd_params = ''
>>> + if fields[1] in s_users:
>>> + useradd_params += '--uid %s' % s_users[fields[1]][2]
>>> + bb.warn("Changing user %s's uid to (%s), verify configuration files!" % (fields[1], s_users[fields[1]][2]))
>>> + elif fields[2] != '-':
>>> + useradd_params += '--uid %s' % fields[2]
>>> + if fields[3] != '-':
>>> + useradd_params += ' --comment "%s"' % fields[3]
>>> + useradd_params += ' --root "%s" --shell /sbin/nologin --system %s' % (d.getVar("IMAGE_ROOTFS", d), fields[1])
>>> + code = subprocess.call('useradd %s' % useradd_params, shell=True)
>>> + elif fields[0] == 'g':
>>> + groupadd_params = ""
>>> + if fields[1] in s_groups:
>>> + groupadd_params += '--gid %s' % s_groups[fields[1]][2]
>>> + bb.warn("Changing group %s's gid to (%s), verify configuration files!" % (fields[1], s_groups[fields[1]][2]))
>>> + elif fields[2] != '-':
>>> + groupadd_params += '--gid %s' % fields[2]
>>> + if fields[3] != '-':
>>> + groupadd_params += ' --comment "%s"' % (d.getVar("IMAGE_ROOTFS", d), fields[3])
>>> + groupadd_params += ' --root "%s" --system %s' % (d.getVar("IMAGE_ROOTFS", d), fields[1])
>>> + code = subprocess.call('groupadd %s' % groupadd_params, shell=True)
>>> +}
>>>
>>> #
>>> # A hook function to support read-only-rootfs IMAGE_FEATURES
>>> @@ -73,27 +114,6 @@ read_only_rootfs_hook () {
>>> ${IMAGE_ROOTFS}/etc/init.d/populate-volatile.sh
>>> fi
>>> fi
>>> -
>>> - if ${@bb.utils.contains("DISTRO_FEATURES", "systemd", "true", "false", d)}; then
>>> - # Update user database files so that services don't fail for a read-only systemd system
>>> - for conffile in ${IMAGE_ROOTFS}/usr/lib/sysusers.d/systemd.conf ${IMAGE_ROOTFS}/usr/lib/sysusers.d/systemd-remote.conf; do
>>> - [ -e $conffile ] || continue
>>> - grep -v "^#" $conffile | sed -e '/^$/d' | while read type name id comment; do
>>> - if [ "$type" = "u" ]; then
>>> - useradd_params=""
>>> - [ "$id" != "-" ] && useradd_params="$useradd_params --uid $id"
>>> - [ "$comment" != "-" ] && useradd_params="$useradd_params --comment $comment"
>>> - useradd_params="$useradd_params --system $name"
>>> - eval useradd --root ${IMAGE_ROOTFS} $useradd_params || true
>>> - elif [ "$type" = "g" ]; then
>>> - groupadd_params=""
>>> - [ "$id" != "-" ] && groupadd_params="$groupadd_params --gid $id"
>>> - groupadd_params="$groupadd_params --system $name"
>>> - eval groupadd --root ${IMAGE_ROOTFS} $groupadd_params || true
>>> - fi
>>> - done
>>> - done
>>> - fi
>>> }
>>>
>>> #
>>> diff --git a/meta/classes/useradd-staticids.bbclass b/meta/classes/useradd-staticids.bbclass
>>> index a9b506d..e9dfe69 100644
>>> --- a/meta/classes/useradd-staticids.bbclass
>>> +++ b/meta/classes/useradd-staticids.bbclass
>>> @@ -1,3 +1,4 @@
>>> +inherit useradd-staticids-list
>>> # In order to support a deterministic set of 'dynamic' users/groups,
>>> # we need a function to reformat the params based on a static file
>>> def update_useradd_static_config(d):
>>> @@ -17,35 +18,6 @@ def update_useradd_static_config(d):
>>> def error(self, message):
>>> raise bb.build.FuncFailed(message)
>>>
>>> - def list_extend(iterable, length, obj = None):
>>> - """Ensure that iterable is the specified length by extending with obj
>>> - and return it as a list"""
>>> - return list(itertools.islice(itertools.chain(iterable, itertools.repeat(obj)), length))
>>> -
>>> - def merge_files(file_list, exp_fields):
>>> - """Read each passwd/group file in file_list, split each line and create
>>> - a dictionary with the user/group names as keys and the split lines as
>>> - values. If the user/group name already exists in the dictionary, then
>>> - update any fields in the list with the values from the new list (if they
>>> - are set)."""
>>> - id_table = dict()
>>> - for conf in file_list.split():
>>> - if os.path.exists(conf):
>>> - f = open(conf, "r")
>>> - for line in f:
>>> - if line.startswith('#'):
>>> - continue
>>> - # Make sure there always are at least exp_fields elements in
>>> - # the field list. This allows for leaving out trailing
>>> - # colons in the files.
>>> - fields = list_extend(line.rstrip().split(":"), exp_fields)
>>> - if fields[0] not in id_table:
>>> - id_table[fields[0]] = fields
>>> - else:
>>> - id_table[fields[0]] = list(itertools.imap(lambda x, y: x or y, fields, id_table[fields[0]]))
>>> -
>>> - return id_table
>>> -
>>> # We parse and rewrite the useradd components
>>> def rewrite_useradd(params):
>>> # The following comes from --help on useradd from shadow
>>> @@ -73,19 +45,6 @@ def update_useradd_static_config(d):
>>> parser.add_argument("-U", "--user-group", help="create a group with the same name as the user", action="store_const", const=True)
>>> parser.add_argument("LOGIN", help="Login name of the new user")
>>>
>>> - # Return a list of configuration files based on either the default
>>> - # files/passwd or the contents of USERADD_UID_TABLES
>>> - # paths are resolved via BBPATH
>>> - def get_passwd_list(d):
>>> - str = ""
>>> - bbpath = d.getVar('BBPATH', True)
>>> - passwd_tables = d.getVar('USERADD_UID_TABLES', True)
>>> - if not passwd_tables:
>>> - passwd_tables = 'files/passwd'
>>> - for conf_file in passwd_tables.split():
>>> - str += " %s" % bb.utils.which(bbpath, conf_file)
>>> - return str
>>> -
>>> newparams = []
>>> users = None
>>> for param in re.split('''[ \t]*;[ \t]*(?=(?:[^'"]|'[^']*'|"[^"]*")*$)''', params):
>>> @@ -206,19 +165,6 @@ def update_useradd_static_config(d):
>>> parser.add_argument("-r", "--system", help="create a system account", action="store_true")
>>> parser.add_argument("GROUP", help="Group name of the new group")
>>>
>>> - # Return a list of configuration files based on either the default
>>> - # files/group or the contents of USERADD_GID_TABLES
>>> - # paths are resolved via BBPATH
>>> - def get_group_list(d):
>>> - str = ""
>>> - bbpath = d.getVar('BBPATH', True)
>>> - group_tables = d.getVar('USERADD_GID_TABLES', True)
>>> - if not group_tables:
>>> - group_tables = 'files/group'
>>> - for conf_file in group_tables.split():
>>> - str += " %s" % bb.utils.which(bbpath, conf_file)
>>> - return str
>>> -
>>> newparams = []
>>> groups = None
>>> for param in re.split('''[ \t]*;[ \t]*(?=(?:[^'"]|'[^']*'|"[^"]*")*$)''', params):
>>> diff --git a/useradd-staticids-list.bbclass b/useradd-staticids-list.bbclass
>>> new file mode 100644
>>> index 0000000..377f748
>>> --- /dev/null
>>> +++ b/useradd-staticids-list.bbclass
>>> @@ -0,0 +1,56 @@
>>> +# Return a list of configuration files based on either the default
>>> +# files/group or the contents of USERADD_GID_TABLES
>>> +# paths are resolved via BBPATH
>>> +def get_group_list(d):
>>> + str = ""
>>> + bbpath = d.getVar('BBPATH', True)
>>> + group_tables = d.getVar('USERADD_GID_TABLES', True)
>>> + if not group_tables:
>>> + group_tables = 'files/group'
>>> + for conf_file in group_tables.split():
>>> + str += " %s" % bb.utils.which(bbpath, conf_file)
>>> + return str
>>> +
>>> +def list_extend(iterable, length, obj = None):
>>> + import itertools
>>> + """Ensure that iterable is the specified length by extending with obj
>>> + and return it as a list"""
>>> + return list(itertools.islice(itertools.chain(iterable, itertools.repeat(obj)), length))
>>> +
>>> +def merge_files(file_list, exp_fields):
>>> + import itertools
>>> + """Read each passwd/group file in file_list, split each line and create
>>> + a dictionary with the user/group names as keys and the split lines as
>>> + values. If the user/group name already exists in the dictionary, then
>>> + update any fields in the list with the values from the new list (if they
>>> + are set)."""
>>> + id_table = dict()
>>> + for conf in file_list.split():
>>> + if os.path.exists(conf):
>>> + f = open(conf, "r")
>>> + for line in f:
>>> + if line.startswith('#'):
>>> + continue
>>> + # Make sure there always are at least exp_fields elements in
>>> + # the field list. This allows for leaving out trailing
>>> + # colons in the files.
>>> + fields = list_extend(line.rstrip().split(":"), exp_fields)
>>> + if fields[0] not in id_table:
>>> + id_table[fields[0]] = fields
>>> + else:
>>> + id_table[fields[0]] = list(itertools.imap(lambda x, y: x or y, fields, id_table[fields[0]]))
>>> +
>>> + return id_table
>>> +
>>> +# Return a list of configuration files based on either the default
>>> +# files/passwd or the contents of USERADD_UID_TABLES
>>> +# paths are resolved via BBPATH
>>> +def get_passwd_list(d):
>>> + str = ""
>>> + bbpath = d.getVar('BBPATH', True)
>>> + passwd_tables = d.getVar('USERADD_UID_TABLES', True)
>>> + if not passwd_tables:
>>> + passwd_tables = 'files/passwd'
>>> + for conf_file in passwd_tables.split():
>>> + str += " %s" % bb.utils.which(bbpath, conf_file)
>>> + return str
>>> --
>>> 2.8.0
>>>
>>> --
>>> _______________________________________________
>>> Openembedded-core mailing list
>>> Openembedded-core at lists.openembedded.org
>>> http://lists.openembedded.org/mailman/listinfo/openembedded-core
>>
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 204 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <http://lists.openembedded.org/pipermail/openembedded-core/attachments/20160509/d7dc655b/attachment-0002.sig>
More information about the Openembedded-core
mailing list