#!/usr/bin/python3

'''
SPDX-License-Identifier: Apache-2.0
Copyright 2022 IBM Corporation
'''

import os
import grp
import pwd

from keylime import keylime_logging

# Configure logger
logger = keylime_logging.init_logging('privileges')


def string_to_uidgid(user_and_group):
    """ Translate the user_and_group string to uid and gid.
        The userandgroup parameter must be a string of the format '<user>[:[<group>]]'
        or '[<user>]:gid'
        User and group can be strings or integers. If no group is given, -1 will be
        returned for gid.
        :raises ValueError: if user or group could not be resolved
    """
    params = user_and_group.split(':')
    if len(params) > 2:
        raise ValueError(f"User and group {user_and_group} are in wrong format. Expected <user>[:[<group>]] or [<user>]:group")

    gid = None
    if len(params) == 2 and len(params[1]) > 0:
        if params[1].isnumeric():
            gid = int(params[1])
            if gid < 0:
                raise ValueError(f"User and group {user_and_group} contains an illegal value")
        else:
            try:
                gr = grp.getgrnam(params[1])
                gid = gr.gr_gid
            except KeyError as e:
                raise ValueError(f'Could not resolve group {params[1]}: {e}') from e

    uid = None
    if len(params[0]) > 0:
        if params[0].isnumeric():
            uid = int(params[0])
            if uid < 0:
                raise ValueError(f"User and group {user_and_group} contains an illegal value")
        else:
            try:
                passwd = pwd.getpwnam(params[0])
                uid = passwd.pw_uid
            except KeyError as e:
                raise ValueError(f'Could not resolve user {params[0]}: {e}') from e

    if uid is None and gid is None:
        raise ValueError(f"User and group {user_and_group} are in wrong format. Expected <user>[:[<group>]] or [<user>]:group")

    return uid, gid


def change_uidgid(user_and_group):
    """ Change uid and gid of the current process.
        The user_and_group parameter must be a string of the format
        '<user>[:[<group>]]' or [<user>]:<group>. User and group can
        be strings or integers.
        :raises ValueError: if user or group could not be resolved
        :raises RuntimeError: if setting gid or uid did not succeed
    """
    uid, gid = string_to_uidgid(user_and_group)

    # First change group and then user
    if gid is not None:
        try:
            os.setgid(gid)
        except (OSError, PermissionError) as e:
            raise RuntimeError(f'Could not set gid to {gid}: {e}') from e

    if uid is not None:
        try:
            os.setuid(uid)
        except (OSError, PermissionError) as e:
            raise RuntimeError(f'Could not set uid to {uid}: {e}') from e


def chown(path, user_and_group):
    """ Change ownership on a given file to the new owner described in
        user_and_group string.
        The user_and_group parameter must be a string of the format
        '<user>[:[<group>]]' or [<user>]:<group>. User and group can
        be strings or integers.
        :raises ValueError: if user or group could not be resolved
    """
    uid, gid = string_to_uidgid(user_and_group)
    if uid is None:
        uid = -1
    if gid is None:
        gid = -1

    os.chown(path, uid, gid)
