1# 2# Copyright OpenEmbedded Contributors 3# 4# SPDX-License-Identifier: GPL-2.0-only 5# 6 7import os 8 9def sort_shadowutils_file(filename, mapping): 10 """ 11 Sorts a passwd or group file based on the numeric ID in the third column. 12 If a mapping is given, the name from the first column is mapped via that 13 dictionary instead (necessary for /etc/shadow and /etc/gshadow). If not, 14 a new mapping is created on the fly and returned. 15 """ 16 17 new_mapping = {} 18 with open(filename, 'rb+') as f: 19 lines = f.readlines() 20 # No explicit error checking for the sake of simplicity. /etc 21 # files are assumed to be well-formed, causing exceptions if 22 # not. 23 for line in lines: 24 entries = line.split(b':') 25 name = entries[0] 26 if mapping is None: 27 id = int(entries[2]) 28 else: 29 id = mapping[name] 30 new_mapping[name] = id 31 # Sort by numeric id first, with entire line as secondary key 32 # (just in case that there is more than one entry for the same id). 33 lines.sort(key=lambda line: (new_mapping[line.split(b':')[0]], line)) 34 # We overwrite the entire file, i.e. no truncate() necessary. 35 f.seek(0) 36 f.write(b''.join(lines)) 37 38 return new_mapping 39 40def sort_shadowutils_files(sysconfdir): 41 """ 42 Sorts shadow-utils 'passwd' and 'group' files in a rootfs' /etc directory 43 by ID. 44 """ 45 46 for main, shadow in (('passwd', 'shadow'), 47 ('group', 'gshadow')): 48 filename = os.path.join(sysconfdir, main) 49 if os.path.exists(filename): 50 mapping = sort_shadowutils_file(filename, None) 51 filename = os.path.join(sysconfdir, shadow) 52 if os.path.exists(filename): 53 sort_shadowutils_file(filename, mapping) 54 55def remove_shadowutils_backup_file(filename): 56 """ 57 Remove shadow-utils backup file for files like /etc/passwd. 58 """ 59 60 backup_filename = filename + '-' 61 if os.path.exists(backup_filename): 62 os.unlink(backup_filename) 63 64def remove_shadowutils_backup_files(sysconfdir): 65 """ 66 Remove shadow-utils backup files in a rootfs /etc directory. They are not 67 needed in the initial root filesystem and sorting them can be inconsistent 68 (YOCTO #11043). 69 """ 70 71 for filename in ( 72 'group', 73 'gshadow', 74 'passwd', 75 'shadow', 76 'subgid', 77 'subuid', 78 ): 79 filepath = os.path.join(sysconfdir, filename) 80 remove_shadowutils_backup_file(filepath) 81 82def tidy_shadowutils_files(sysconfdir): 83 """ 84 Tidy up shadow-utils files. 85 """ 86 87 remove_shadowutils_backup_files(sysconfdir) 88 sort_shadowutils_files(sysconfdir) 89 90 return True 91