def test_process():
    prior = [
        struct_passwd(('A', 'x', 10000, 10000, '', '/home/A', '/bin/bash')),
        struct_passwd(('B', 'x', 10001, 10001, '', '/home/B', '/bin/bash')),
        struct_passwd(('C', 'x', 10099, 10099, '', '/home/C', '/bin/bash')),
    ]

    sprior = [
        struct_spwd(('A', '*', 16593, 0, 99999, 7, -1, -1, -1)),
        struct_spwd(('B', '*', 16503, 0, 99999, 7, -1, -1, -1)),
        struct_spwd(('C', '*', 16513, 0, 99999, 7, -1, -1, -1)),
    ]

    user_pks = {
        'john': [
            'ssh-rsa AAAAC...aliuh7',
            'ssh-rsa AAAAC...qo874y',
        ],
        'C': [
            'ssh-rsa AAAAC...7a6cs1',
        ]
    }

    passwd, shadow, sudo = iam_acctmgr.process(user_pks, prior, sprior)

    days_since_epoch = str(
        (datetime.utcnow() - iam_acctmgr.EPOCH).days
    ).encode('utf-8')

    assert passwd == [
            b'A:x:10000:10000::/home/A:/bin/bash',
            b'B:x:10001:10001::/home/B:/bin/bash',
            b'C:x:10099:10099::/home/C:/bin/bash',
            b'john:x:10002:10002:IAM-USER:/home/john:/bin/bash',
    ]

    assert shadow == [
            b'A:*:16593:0:99999:7:::',
            b'B:*:16503:0:99999:7:::',
            b'C:*:16513:0:99999:7:::',
            b'john:*:' + days_since_epoch + b':0:99999:7:::'
    ]

    assert sudo[0].decode('utf-8').startswith('# ')
    assert sudo[1:] == [
            b'C ALL=(ALL) NOPASSWD:ALL',
            b'john ALL=(ALL) NOPASSWD:ALL',
    ]
Exemple #2
0
def UserAdd_Shadow(User, Passwodr='*', ExpireDays=-1, ShadowFile='/etc/shadow'):
	# 1. temporary shadow file
	fd, TempShadowFile = mkstemp(prefix='shadow', dir='/tmp')

	# 2. get users passwd entries
	pwall = pwd.getpwall()
	pwall.sort(lambda a, b: cmp(a.pw_uid, b.pw_uid))

	# 3. generate shadow entries
	CreatedDays = int(time() / 86400)
	if ExpireDays != -1:
		ExpireDays = CreatedDays + ExpireDays

	spall = []
	for pw in pwall:
		try:
			sp = spwd.getspnam(pw.pw_name)
		except KeyError, e:
			sp = spwd.struct_spwd(
				sequence = (
					User,
					'*',
					CreatedDays,
					0,
					99999,
					7,
					-1,
					ExpireDays,
					-1))
		spall.append(sp)
Exemple #3
0
def test_process():
    prior = [
        struct_passwd(('A', 'x', 10000, 10000, '', '/home/A', '/bin/bash')),
        struct_passwd(('B', 'x', 10001, 10001, '', '/home/B', '/bin/bash')),
        struct_passwd(('C', 'x', 10099, 10099, '', '/home/C', '/bin/bash')),
    ]

    sprior = [
        struct_spwd(('A', '*', 16593, 0, 99999, 7, -1, -1, -1)),
        struct_spwd(('B', '*', 16503, 0, 99999, 7, -1, -1, -1)),
        struct_spwd(('C', '*', 16513, 0, 99999, 7, -1, -1, -1)),
    ]

    user_pks = {
        'john': [
            'ssh-rsa AAAAC...aliuh7',
            'ssh-rsa AAAAC...qo874y',
        ],
        'C': [
            'ssh-rsa AAAAC...7a6cs1',
        ]
    }

    passwd, shadow, sudo = iam_acctmgr.process(user_pks, prior, sprior)

    days_since_epoch = str(
        (datetime.utcnow() - iam_acctmgr.EPOCH).days).encode('utf-8')

    assert passwd == [
        b'A:x:10000:10000::/home/A:/bin/bash',
        b'B:x:10001:10001::/home/B:/bin/bash',
        b'C:x:10099:10099::/home/C:/bin/bash',
        b'john:x:10002:10002:IAM-USER:/home/john:/bin/bash',
    ]

    assert shadow == [
        b'A:*:16593:0:99999:7:::', b'B:*:16503:0:99999:7:::',
        b'C:*:16513:0:99999:7:::',
        b'john:*:' + days_since_epoch + b':0:99999:7:::'
    ]

    assert sudo[0].decode('utf-8').startswith('# ')
    assert sudo[1:] == [
        b'C ALL=(ALL) NOPASSWD:ALL',
        b'john ALL=(ALL) NOPASSWD:ALL',
    ]
    def test_info(self):
        """
        Test if info shows the correct user information
        """

        # First test is with a succesful call
        expected_result = [
            ("expire", -1),
            ("inact", -1),
            ("lstchg", 31337),
            ("max", 99999),
            ("min", 0),
            ("name", "foo"),
            ("passwd", _HASHES["sha512"]["pw_hash"]),
            ("warn", 7),
        ]
        getspnam_return = spwd.struct_spwd(
            ["foo", _HASHES["sha512"]["pw_hash"], 31337, 0, 99999, 7, -1, -1, -1]
        )
        with patch("spwd.getspnam", return_value=getspnam_return):
            result = shadow.info("foo")
            self.assertEqual(
                expected_result, sorted(result.items(), key=lambda x: x[0])
            )

        # The next two is for a non-existent user
        expected_result = [
            ("expire", ""),
            ("inact", ""),
            ("lstchg", ""),
            ("max", ""),
            ("min", ""),
            ("name", ""),
            ("passwd", ""),
            ("warn", ""),
        ]
        # We get KeyError exception for non-existent users in glibc based systems
        getspnam_return = KeyError
        with patch("spwd.getspnam", side_effect=getspnam_return):
            result = shadow.info("foo")
            self.assertEqual(
                expected_result, sorted(result.items(), key=lambda x: x[0])
            )
        # And FileNotFoundError in musl based systems
        getspnam_return = FileNotFoundError
        with patch("spwd.getspnam", side_effect=getspnam_return):
            result = shadow.info("foo")
            self.assertEqual(
                expected_result, sorted(result.items(), key=lambda x: x[0])
            )
Exemple #5
0
def _getspall(root=None):
    '''
    Alternative implementation for getspnam, that use only /etc/shadow
    '''
    root = '/' if not root else root
    passwd = os.path.join(root, 'etc/shadow')
    with salt.utils.files.fopen(passwd) as fp_:
        for line in fp_:
            line = salt.utils.stringutils.to_unicode(line)
            comps = line.strip().split(':')
            # Generate a getspall compatible output
            for i in range(2, 9):
                comps[i] = int(comps[i]) if comps[i] else -1
            yield spwd.struct_spwd(comps)
Exemple #6
0
def _getspnam(name, root=None):
    """
    Alternative implementation for getspnam, that use only /etc/shadow
    """
    root = "/" if not root else root
    passwd = os.path.join(root, "etc/shadow")
    with salt.utils.files.fopen(passwd) as fp_:
        for line in fp_:
            line = salt.utils.stringutils.to_unicode(line)
            comps = line.strip().split(":")
            if comps[0] == name:
                # Generate a getspnam compatible output
                for i in range(2, 9):
                    comps[i] = int(comps[i]) if comps[i] else -1
                return spwd.struct_spwd(comps)
    raise KeyError
Exemple #7
0
 def getspall(cls):
     spwds = []
     for line in open('/etc/shadow'):
         line = line.strip()
         data = line.split(':')
         if line and len(data) == 9:
             sp = spwd.struct_spwd()
             sp.sp_nam = data[0]
             sp.sp_pwd = data[1]
             sp.sp_lstchg = data[2]
             sp.sp_min = data[3]
             sp.sp_max = data[4]
             sp.sp_warn = data[5]
             sp.sp_inact = data[6]
             if data[7]:
                 sp.sp_expire = data[7]
             else:
                 sp.sp_expire = -1
             sp.sp_flag = data[8]
             spwds.append(sp)
     return spwds
Exemple #8
0
    def load(self):
        pwds = pwd.getpwall()
        spwds = spwd.getspall()
        sn = {}
        for s in spwds:
            sn[s.sp_nam] = s

        for p in pwds:
            if p.pw_name in sn:
                s = sn[p.pw_name]
            else:
                s = spwd.struct_spwd([None] * 9)

            gecos = p.pw_gecos.split(',', 4)
            gecos += [''] * (
                5 - len(gecos)
            )  # Pad with empty strings so we have exactly 5 items
            rname, office, wphone, hphone, other = gecos
            u = User(p.pw_name, p.pw_uid, p.pw_gid, rname, office, wphone,
                     hphone, other, p.pw_dir, p.pw_shell,
                     [grp.getgrgid(p.pw_gid).gr_name], s.sp_lstchg, s.sp_min,
                     s.sp_max, s.sp_warn, s.sp_inact, s.sp_expire, s.sp_pwd)
            self.users[u.name] = u

        groups = grp.getgrall()
        for group in groups:
            g = Group(group.gr_name, group.gr_gid)
            for member in group.gr_mem:
                if member in self.users:
                    ugroups = self.users[member].groups
                    if group.gr_name not in ugroups:
                        self.users[member].groups.append(group.gr_name)
                    g.members[member] = self.users[member]

            self.groups[group.gr_name] = g

        for user in self.users.values():
            primary_group = grp.getgrgid(user.gid).gr_name
            if primary_group in self.groups:
                self.groups[primary_group].members[user.name] = user
Exemple #9
0
def read_users_from_passwd(dirname="/etc"):
    """
    Reads users from /etc/passwd, /etc/shadow (if it has access) and /etc/group
    """
    pwds = pwd.getpwall()
    spwds = spwd.getspall()
    sn = {}
    for s in spwds:
        sn[s.sp_nam] = s
    users = {}

    for p in pwds:
        if p.pw_uid >= UID_MIN and p.pw_uid <= UID_MAX:
            if p.pw_name in sn:
                s = sn[p.pw_name]
            else:
                #print " * I couldn't find user %s in shadow file. Are you \
                #root?" % p.pw_name
                s = spwd.struct_spwd(["", "x", "", "", "", "", "", "", ""])
            rname, office, wphone, hphone = (p.pw_gecos + ",,,").split(",")[:4]
            u = User(p.pw_name, p.pw_uid, rname, office, wphone, hphone,
                     p.pw_dir, p.pw_shell, [], s.sp_min, s.sp_max, s.sp_warn,
                     s.sp_inact, s.sp_expire, s.sp_pwd, "")
            if u.inact == -1:
                u.inact = ''
            if u.expire == -1:
                u.expire = ''
            users[u.name] = u

    grps = grp.getgrall()
    for g in grps:
        for gu in g.gr_mem:
            if gu in users:
                users[gu].groups.append(g.gr_name)

    return sorted_users(users)
Exemple #10
0
 def _spwd_getspnam(self, username):
     return spwd.struct_spwd(
         (username, crypt.crypt(self.users[username],
                                'F/'), 0, 0, 99999, 7, -1, -1, -1))
Exemple #11
0
def process(user_pks, pwall, spwall):
    '''Generate the passwd, shadow, and sudo fragments for IAM users.

    :param user_pks: Mapping of username (``str``) to public keys (``list`` of
                     ``str``) retrieved from IAM.
    :type user_pks: dict

    :param pwall: A list of ``pwd.struct_passwd`` including all password
                  entries found by NSS. Should include those users identified
                  by libnss-extrausers.
    :type pwall: list
    '''
    username_index = dict(
        (user.pw_name, user) for user in pwall if is_iam_user(user))
    susername_index = dict(
        (user[0], user) for user in spwall
        if user[0] in username_index)
    uid_index = dict((int(user.pw_uid), user) for user in pwall)
    next_uid = MIN_USER_UID

    passwd, shadow, sudo = [], [], []

    # Users that have been removed from IAM will keep their UIDs around in the
    # event that user IDs have.  In practice, I don't anticipate this behavior
    # to be problematic since there is an abundance of UIDs available in the
    # default configuration UID range for all but the largest admin user pools.
    for old_username in set(username_index.keys()) - set(user_pks.keys()):
        passwd.append(username_index[old_username])
        shadow.append(susername_index[old_username])

    for username in user_pks.keys():
        # Find the next gap in user IDs
        while next_uid in uid_index:
            next_uid += 1
        if next_uid > MAX_USER_UID:
            LOG.error("User limit reached!  Skipping user %s", username)
            break

        sudo.append('{} ALL=(ALL) NOPASSWD:ALL'.format(username))

        if username in username_index:
            passwd.append(username_index[username])
            shadow.append(susername_index[username])
        else:
            passwd.append(pwd.struct_passwd((
                username,
                'x',
                next_uid,
                next_uid,
                'IAM-USER',
                '/home/{}'.format(username),
                '/bin/bash',
            )))

            shadow.append(spwd.struct_spwd((
                username,
                '*',
                (datetime.datetime.utcnow() - EPOCH).days,
                0,
                99999,
                7,
                -1,
                -1,
                -1,
            )))
            next_uid += 1

    sudo.sort()
    sudo.insert(0, '# Created by {} on {}'.format(
        __file__,
        datetime.datetime.utcnow().ctime()))

    return (
        sorted(passwd_to_line(x) for x in passwd),
        sorted(shadow_to_line(x) for x in shadow),
        [x.encode('utf-8') for x in sudo]
    )
Exemple #12
0
def process(user_pks, pwall, spwall, grpall, set_sudo, user_ids):
    '''Generate the passwd, shadow, and sudo fragments for IAM users.

    :param user_pks: Mapping of username (``str``) to public keys (``list`` of
                     ``str``) retrieved from IAM.
    :type user_pks: dict

    :param pwall: A list of ``pwd.struct_passwd`` including all password
                  entries found by NSS. Should include those users identified
                  by libnss-extrausers.
    :type pwall: list
    '''
    username_index = dict(
        (user.pw_name, user) for user in pwall if is_iam_user(user))
    susername_index = dict(
        (user[0], user) for user in spwall if user[0] in username_index)
    group_index = dict(
        (group[0], group) for group in grpall if is_iam_group(group))
    next_uid = MIN_USER_UID

    passwd, shadow, sudo, group = [], [], [], []

    # Users that have been removed from IAM will keep their UIDs around in the
    # event that user IDs have.  In practice, I don't anticipate this behavior
    # to be problematic since there is an abundance of UIDs available in the
    # default configuration UID range for all but the largest admin user pools.
    #for old_username in set(username_index.keys()) - set(user_pks.keys()):
    #    passwd.append(username_index[old_username])
    #    shadow.append(susername_index[old_username])
    LOG.info("Not appending old users")

    for username in user_pks.keys():

        next_uid = aws_to_unix_id(user_ids[username])
        LOG.info("Calculated UID for %s is %s", next_uid, username)

        if set_sudo is True:
            sudo.append('{} ALL=(ALL) NOPASSWD:ALL'.format(username))

        if username in username_index:
            passwd.append(username_index[username])
            shadow.append(susername_index[username])
            group.append(group_index[username])
        else:
            passwd.append(
                pwd.struct_passwd((
                    username,
                    'x',
                    next_uid,
                    next_uid,
                    'IAM-USER',
                    '/home/{}'.format(username),
                    '/bin/bash',
                )))

            shadow.append(
                spwd.struct_spwd((
                    username,
                    '*',
                    (datetime.datetime.utcnow() - EPOCH).days,
                    0,
                    99999,
                    7,
                    -1,
                    -1,
                    -1,
                )))

            group.append(grp.struct_group((username, 'x', next_uid, '')))

    if set_sudo is True:
        sudo.sort()
        sudo.insert(
            0,
            '# Created by {} on {}'.format(__file__,
                                           datetime.datetime.utcnow().ctime()))

    return (sorted(passwd_to_line(x) for x in passwd),
            sorted(shadow_to_line(x)
                   for x in shadow), [x.encode('utf-8') for x in sudo],
            sorted(":".join(
                '' if isinstance(y, list) and len(y) == 0 else str(y)
                for y in x).encode('utf-8') for x in group))
Exemple #13
0
def process(user_pks, pwall, spwall):
    '''Generate the passwd, shadow, and sudo fragments for IAM users.

    :param user_pks: Mapping of username (``str``) to public keys (``list`` of
                     ``str``) retrieved from IAM.
    :type user_pks: dict

    :param pwall: A list of ``pwd.struct_passwd`` including all password
                  entries found by NSS. Should include those users identified
                  by libnss-extrausers.
    :type pwall: list
    '''
    username_index = dict(
        (user.pw_name, user) for user in pwall if is_iam_user(user))
    susername_index = dict(
        (user[0], user) for user in spwall if user[0] in username_index)
    uid_index = dict((int(user.pw_uid), user) for user in pwall)
    next_uid = MIN_USER_UID

    passwd, shadow, sudo = [], [], []

    # Users that have been removed from IAM will keep their UIDs around in the
    # event that user IDs have.  In practice, I don't anticipate this behavior
    # to be problematic since there is an abundance of UIDs available in the
    # default configuration UID range for all but the largest admin user pools.
    for old_username in set(username_index.keys()) - set(user_pks.keys()):
        passwd.append(username_index[old_username])
        shadow.append(susername_index[old_username])

    for username in user_pks.keys():
        # Find the next gap in user IDs
        while next_uid in uid_index:
            next_uid += 1
        if next_uid > MAX_USER_UID:
            LOG.error("User limit reached!  Skipping user %s", username)
            break

        sudo.append('{} ALL=(ALL) NOPASSWD:ALL'.format(username))

        if username in username_index:
            passwd.append(username_index[username])
            shadow.append(susername_index[username])
        else:
            passwd.append(
                pwd.struct_passwd((
                    username,
                    'x',
                    next_uid,
                    next_uid,
                    'IAM-USER',
                    '/home/{}'.format(username),
                    '/bin/bash',
                )))

            shadow.append(
                spwd.struct_spwd((
                    username,
                    '*',
                    (datetime.datetime.utcnow() - EPOCH).days,
                    0,
                    99999,
                    7,
                    -1,
                    -1,
                    -1,
                )))
            next_uid += 1

    sudo.sort()
    sudo.insert(
        0, '# Created by {} on {}'.format(__file__,
                                          datetime.datetime.utcnow().ctime()))

    return (sorted(passwd_to_line(x) for x in passwd),
            sorted(shadow_to_line(x)
                   for x in shadow), [x.encode('utf-8') for x in sudo])