File size: 4,225 Bytes
246d201
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import subprocess

from openhands.core.logger import openhands_logger as logger


def init_user_and_working_directory(

    username: str, user_id: int, initial_cwd: str

) -> int | None:
    """Create working directory and user if not exists.

    It performs the following steps effectively:

    * Creates the Working Directory:

        - Uses mkdir -p to create the directory.

        - Sets ownership to username:root.

        - Adjusts permissions to be readable and writable by group and others.

    * User Verification and Creation:

        - Checks if the user exists using id -u.

        - If the user exists with the correct UID, it skips creation.

        - If the UID differs, it logs a warning and return an updated user_id.

        - If the user doesn't exist, it proceeds to create the user.

    * Sudo Configuration:

        - Appends %sudo ALL=(ALL) NOPASSWD:ALL to /etc/sudoers to grant

            passwordless sudo access to the sudo group.

        - Adds the user to the sudo group with the useradd command, handling

            UID conflicts by incrementing the UID if necessary.



    Args:

        username (str): The username to create.

        user_id (int): The user ID to assign to the user.

        initial_cwd (str): The initial working directory to create.



    Returns:

        int | None: The user ID if it was updated, None otherwise.

    """

    # First create the working directory, independent of the user
    logger.debug(f'Client working directory: {initial_cwd}')
    command = f'umask 002; mkdir -p {initial_cwd}'
    output = subprocess.run(command, shell=True, capture_output=True)
    out_str = output.stdout.decode()

    command = f'chown -R {username}:root {initial_cwd}'
    output = subprocess.run(command, shell=True, capture_output=True)
    out_str += output.stdout.decode()

    command = f'chmod g+rw {initial_cwd}'
    output = subprocess.run(command, shell=True, capture_output=True)
    out_str += output.stdout.decode()
    logger.debug(f'Created working directory. Output: [{out_str}]')

    # Skip root since it is already created
    if username == 'root':
        return None

    # Check if the username already exists
    existing_user_id = -1
    try:
        result = subprocess.run(
            f'id -u {username}', shell=True, check=True, capture_output=True
        )
        existing_user_id = int(result.stdout.decode().strip())

        # The user ID already exists, skip setup
        if existing_user_id == user_id:
            logger.debug(
                f'User `{username}` already has the provided UID {user_id}. Skipping user setup.'
            )
        else:
            logger.warning(
                f'User `{username}` already exists with UID {existing_user_id}. Skipping user setup.'
            )
            return existing_user_id
        return None
    except subprocess.CalledProcessError as e:
        # Returncode 1 indicates, that the user does not exist yet
        if e.returncode == 1:
            logger.debug(
                f'User `{username}` does not exist. Proceeding with user creation.'
            )
        else:
            logger.error(f'Error checking user `{username}`, skipping setup:\n{e}\n')
            raise

    # Add sudoer
    sudoer_line = r"echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers"
    output = subprocess.run(sudoer_line, shell=True, capture_output=True)
    if output.returncode != 0:
        raise RuntimeError(f'Failed to add sudoer: {output.stderr.decode()}')
    logger.debug(f'Added sudoer successfully. Output: [{output.stdout.decode()}]')

    command = (
        f'useradd -rm -d /home/{username} -s /bin/bash '
        f'-g root -G sudo -u {user_id} {username}'
    )
    output = subprocess.run(command, shell=True, capture_output=True)
    if output.returncode == 0:
        logger.debug(
            f'Added user `{username}` successfully with UID {user_id}. Output: [{output.stdout.decode()}]'
        )
    else:
        raise RuntimeError(
            f'Failed to create user `{username}` with UID {user_id}. Output: [{output.stderr.decode()}]'
        )
    return None