User Manager Guide

Configure user accounts, privileges, and LDAP authentication on OpenBMC.

Table of Contents

  1. Overview
  2. Setup & Configuration
    1. Build-Time Configuration (Yocto)
    2. Configuration Files
    3. Deploying Custom PAM Configuration via Yocto
    4. LDAP Configuration Persistence
    5. Runtime Configuration
  3. Local User Management
    1. Default Users
    2. Create User via Redfish
    3. Create User via D-Bus
    4. Modify User
    5. Delete User
  4. Privilege Roles
    1. Available Roles
    2. Role Permissions
    3. D-Bus Privilege Mapping
  5. IPMI User Management
    1. Configure IPMI Users
    2. IPMI User Privileges
  6. LDAP Configuration
    1. Enable LDAP Authentication
    2. LDAP Role Mapping
    3. D-Bus LDAP Configuration
    4. Test LDAP Connection
  7. Active Directory
    1. Configure AD Authentication
  8. Account Policies
    1. Configure Lockout
    2. Password Policy
  9. Multi-Factor Authentication (MFA)
    1. How TOTP Enrollment Works
    2. OTP Verification
    3. MFA State and D-Bus
    4. Per-User Bypass
  10. Session Management
    1. View Active Sessions
    2. Terminate Session
    3. Session Timeout
  11. Troubleshooting
    1. Login Failures
    2. LDAP Issues
    3. Account Locked
  12. Deep Dive
    1. PAM Integration
    2. LDAP Authentication Flow
    3. Password Hashing
    4. D-Bus Permission Enforcement
    5. Source Code Reference
  13. Examples
  14. References

Overview

OpenBMC user management is handled by phosphor-user-manager, providing local accounts, role-based access control, and LDAP integration.

---
title: User Manager Architecture
---
flowchart TB
    subgraph access["Access Methods"]
        direction TB
        redfish["Redfish API"]
        ipmi["IPMI Users"]
        ssh["SSH Login"]
        webui["WebUI Login"]
    end

    access --> usermgr

    subgraph usermgr["phosphor-user-manager"]
        direction TB
        local["Local Accounts<br/>/etc/passwd"]
        ldap["LDAP/AD Config<br/>nslcd/sssd"]
        priv["Privilege<br/>Management"]
    end

    usermgr --> pam["PAM<br/>(Pluggable Authentication Modules)"]
ASCII-art version (for comparison)
┌─────────────────────────────────────────────────────────────────┐
│                   User Manager Architecture                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │                    Access Methods                           ││
│  │                                                             ││
│  │   ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐    ││
│  │   │ Redfish  │  │  IPMI    │  │   SSH    │  │  WebUI   │    ││
│  │   │ API      │  │  Users   │  │ Login    │  │  Login   │    ││
│  │   └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘    ││
│  └────────┼─────────────┼─────────────┼─────────────┼──────────┘│
│           └─────────────┴──────┬──────┴─────────────┘           │
│                                │                                │
│  ┌─────────────────────────────┴───────────────────────────────┐│
│  │                   phosphor-user-manager                     ││
│  │                                                             ││
│  │   ┌────────────────┐  ┌────────────────┐  ┌──────────────┐  ││
│  │   │ Local Accounts │  │ LDAP/AD Config │  │ Privilege    │  ││
│  │   │ /etc/passwd    │  │ nslcd/sssd     │  │ Management   │  ││
│  │   └────────────────┘  └────────────────┘  └──────────────┘  ││
│  └──────────────────────────┬──────────────────────────────────┘│
│                             │                                   │
│  ┌──────────────────────────┴──────────────────────────────────┐│
│  │                          PAM                                ││
│  │              (Pluggable Authentication Modules)             ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘

Setup & Configuration

Build-Time Configuration (Yocto)

# In your machine .conf or local.conf

# Include user management
IMAGE_INSTALL:append = " \
    phosphor-user-manager \
"

# For LDAP support
IMAGE_INSTALL:append = " \
    nss-pam-ldapd \
    pam-plugin-ldap \
"

# Configure Meson options
EXTRA_OEMESON:pn-phosphor-user-manager = " \
    -Dldap=enabled \
"

Configuration Files

Config File Install Path Description
PAM auth config /etc/pam.d/common-auth Authentication module stack
PAM password config /etc/pam.d/common-password Password change rules
PAM account config /etc/pam.d/common-account Account validation
LDAP client config /etc/nslcd.conf nslcd LDAP client settings
LDAP NSS config /etc/nsswitch.conf Name service switch (adds ldap)
D-Bus policy /etc/dbus-1/system.d/phosphor-user-manager.conf D-Bus access control

Deploying Custom PAM Configuration via Yocto

To customize PAM authentication (e.g., add stricter password policies or modify the auth module order), create a bbappend for the pam recipe:

# meta-myplatform/recipes-phosphor/users/phosphor-user-manager/
# └── files/
# │   └── common-auth
# │   └── common-password
# └── phosphor-user-manager_%.bbappend

cat > phosphor-user-manager_%.bbappend << 'EOF'
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI += " \
    file://common-auth \
    file://common-password \
"

do_install:append() {
    # Deploy custom PAM configuration
    install -d ${D}${sysconfdir}/pam.d
    install -m 0644 ${WORKDIR}/common-auth ${D}${sysconfdir}/pam.d/
    install -m 0644 ${WORKDIR}/common-password ${D}${sysconfdir}/pam.d/
}
EOF

Example common-auth with lockout policy:

# /etc/pam.d/common-auth
auth required   pam_tally2.so deny=5 unlock_time=300 onerr=fail
auth sufficient pam_unix.so nullok try_first_pass
auth sufficient pam_ldap.so use_first_pass
auth required   pam_deny.so

LDAP Configuration Persistence

LDAP configuration set via Redfish/D-Bus is persisted to:

# LDAP config persistence (managed by phosphor-user-manager)
/var/lib/phosphor-user-manager/ldap.conf

# nslcd runtime config (generated from D-Bus settings)
/etc/nslcd.conf

To bake default LDAP settings into the image:

# meta-myplatform/recipes-phosphor/users/nss-pam-ldapd/
# └── files/
# │   └── nslcd.conf
# └── nss-pam-ldapd_%.bbappend

cat > nss-pam-ldapd_%.bbappend << 'EOF'
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI += "file://nslcd.conf"

do_install:append() {
    install -m 0600 ${WORKDIR}/nslcd.conf ${D}${sysconfdir}/
}
EOF

Runtime Configuration

# Check user manager service
systemctl status phosphor-user-manager

# View logs
journalctl -u phosphor-user-manager -f

# User configuration files
cat /etc/passwd
cat /etc/group

# Verify PAM config
cat /etc/pam.d/common-auth

# Verify LDAP client config
cat /etc/nslcd.conf

Local User Management

Default Users

Username Default Password Role
root 0penBmc Administrator

Create User via Redfish

# Create new user
curl -k -u root:0penBmc -X POST \
    -H "Content-Type: application/json" \
    -d '{
        "UserName": "operator1",
        "Password": "SecurePass123!",
        "RoleId": "Operator",
        "Enabled": true
    }' \
    https://localhost/redfish/v1/AccountService/Accounts

Create User via D-Bus

# Create user
busctl call xyz.openbmc_project.User.Manager \
    /xyz/openbmc_project/user \
    xyz.openbmc_project.User.Manager \
    CreateUser ssasbs \
    "newuser" \
    3 "ipmi" "redfish" "ssh" \
    "priv-admin" \
    true

Modify User

# Change password via Redfish
curl -k -u root:0penBmc -X PATCH \
    -H "Content-Type: application/json" \
    -d '{"Password": "NewPassword123!"}' \
    https://localhost/redfish/v1/AccountService/Accounts/operator1

# Change role
curl -k -u root:0penBmc -X PATCH \
    -H "Content-Type: application/json" \
    -d '{"RoleId": "Administrator"}' \
    https://localhost/redfish/v1/AccountService/Accounts/operator1

# Enable/disable user
curl -k -u root:0penBmc -X PATCH \
    -H "Content-Type: application/json" \
    -d '{"Enabled": false}' \
    https://localhost/redfish/v1/AccountService/Accounts/operator1

Delete User

# Via Redfish
curl -k -u root:0penBmc -X DELETE \
    https://localhost/redfish/v1/AccountService/Accounts/operator1

# Via IPMI
ipmitool -I lanplus -H bmc-ip -U root -P 0penBmc user set name 3 ""

Privilege Roles

Available Roles

Role Redfish IPMI Priv Description
Administrator Administrator 4 (admin) Full access
Operator Operator 3 (operator) Operations, no user mgmt
ReadOnly ReadOnly 2 (user) Read-only access
Callback Callback 1 Limited callback access

Role Permissions

# View available roles
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/AccountService/Roles

# Get role details
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/AccountService/Roles/Operator

D-Bus Privilege Mapping

# View user privileges
busctl get-property xyz.openbmc_project.User.Manager \
    /xyz/openbmc_project/user/newuser \
    xyz.openbmc_project.User.Attributes \
    UserPrivilege

IPMI User Management

Configure IPMI Users

# List users
ipmitool user list

# Create user
ipmitool user set name 3 operator1
ipmitool user set password 3 Password123!
ipmitool user priv 3 3 1  # operator privilege, channel 1
ipmitool user enable 3

# Disable user
ipmitool user disable 3

# Delete user
ipmitool user set name 3 ""

IPMI User Privileges

Level Name Description
1 Callback Minimal access
2 User Read sensors, view logs
3 Operator Power control, sensor config
4 Administrator Full access
5 OEM Vendor-specific

LDAP Configuration

Enable LDAP Authentication

# Configure LDAP via Redfish
curl -k -u root:0penBmc -X PATCH \
    -H "Content-Type: application/json" \
    -d '{
        "LDAP": {
            "ServiceEnabled": true,
            "ServiceAddresses": ["ldap://ldap.example.com"],
            "Authentication": {
                "AuthenticationType": "UsernameAndPassword",
                "Username": "cn=admin,dc=example,dc=com",
                "Password": "ldappassword"
            },
            "LDAPService": {
                "SearchSettings": {
                    "BaseDistinguishedNames": ["dc=example,dc=com"],
                    "UsernameAttribute": "uid",
                    "GroupsAttribute": "memberOf"
                }
            }
        }
    }' \
    https://localhost/redfish/v1/AccountService

LDAP Role Mapping

# Map LDAP group to role
curl -k -u root:0penBmc -X POST \
    -H "Content-Type: application/json" \
    -d '{
        "RemoteGroup": "cn=admins,ou=groups,dc=example,dc=com",
        "LocalRole": "Administrator"
    }' \
    https://localhost/redfish/v1/AccountService/LDAP/RemoteRoleMapping

D-Bus LDAP Configuration

# Create LDAP config
busctl call xyz.openbmc_project.User.Manager \
    /xyz/openbmc_project/user/ldap \
    xyz.openbmc_project.User.Ldap.Create \
    Create sssssa{ss} \
    "ldap://ldap.example.com" \
    "cn=admin,dc=example,dc=com" \
    "dc=example,dc=com" \
    "uid" \
    "OpenLDAP" \
    0

Test LDAP Connection

# Test authentication
ldapsearch -x -H ldap://ldap.example.com \
    -D "cn=admin,dc=example,dc=com" \
    -w password \
    -b "dc=example,dc=com" \
    "(uid=testuser)"

Active Directory

Configure AD Authentication

# Configure Active Directory
curl -k -u root:0penBmc -X PATCH \
    -H "Content-Type: application/json" \
    -d '{
        "ActiveDirectory": {
            "ServiceEnabled": true,
            "ServiceAddresses": ["ldap://ad.example.com"],
            "Authentication": {
                "AuthenticationType": "UsernameAndPassword",
                "Username": "admin@example.com",
                "Password": "adpassword"
            },
            "LDAPService": {
                "SearchSettings": {
                    "BaseDistinguishedNames": ["DC=example,DC=com"],
                    "UsernameAttribute": "sAMAccountName",
                    "GroupsAttribute": "memberOf"
                }
            }
        }
    }' \
    https://localhost/redfish/v1/AccountService

Account Policies

Configure Lockout

# Set account lockout policy
curl -k -u root:0penBmc -X PATCH \
    -H "Content-Type: application/json" \
    -d '{
        "AccountLockoutThreshold": 5,
        "AccountLockoutDuration": 300,
        "AccountLockoutCounterResetAfter": 60
    }' \
    https://localhost/redfish/v1/AccountService

Password Policy

# Set minimum password length
curl -k -u root:0penBmc -X PATCH \
    -H "Content-Type: application/json" \
    -d '{
        "MinPasswordLength": 12
    }' \
    https://localhost/redfish/v1/AccountService

Multi-Factor Authentication (MFA)

Beyond passwords, LDAP, and Active Directory, phosphor-user-manager supports multi-factor authentication (MFA) using TOTP (Time-based One-Time Password), which is compatible with Google Authenticator and equivalent authenticator apps. When MFA is enabled for a user, login requires both the account password and a current one-time passcode (OTP).

How TOTP Enrollment Works

  1. Secret generation — enabling TOTP for a user runs the google-authenticator utility to produce a per-user secret. OpenBMC invokes it non-interactively in time-based mode (google-authenticator -s <path> -u -W -Q NONE -t -f -d -C), so no QR code or interactive prompt is generated.
  2. Provisional secret — the new secret is first written to a temporary file (a .google_authenticator.tmp under the user’s home) and is not yet active.
  3. Verification makes it permanent — the user must submit one valid OTP. Only after that OTP verifies successfully is the secret promoted (renamed) to its live location, ~/.google_authenticator. A failed verification — or disabling MFA — removes the temporary secret, so a half-finished enrollment never locks the account.

OTP Verification

One-time passcodes are checked through a dedicated PAM service, mfa_pam (installed to /etc/pam.d/mfa_pam). The internal Totp::verify(username, token) helper opens a PAM conversation against that service, answers its Verification code: prompt with the supplied token, and reports success only when PAM accepts the code. Isolating OTP checks in their own PAM stack lets MFA layer on top of the existing common-auth password flow without modifying it.

MFA State and D-Bus

MFA configuration lives on the xyz.openbmc_project.User.Manager service, exposed through the xyz.openbmc_project.User.MultiFactorAuthConfiguration interface — whose Enabled property selects the active MFA type (for example GoogleAuthenticator or None) — and is mirrored to the Redfish AccountService. The selected MFA type and related state are persisted as JSON (via the manager’s JsonSerializer), so the setting survives a BMC reboot.

# Inspect the user manager object and its MFA-related interfaces
busctl introspect xyz.openbmc_project.User.Manager \
    /xyz/openbmc_project/user

Per-User Bypass

For temporary exceptions — a break-glass account, or a user who has lost their authenticator — phosphor-user-manager supports a per-user bypass protocol. Bypassing a protocol (such as GoogleAuthenticator) exempts that user from the corresponding factor and clears their stored secret. The bypass selection is itself persisted as JSON, so it too survives a reboot.

MFA secrets are sensitive. A user’s ~/.google_authenticator secret is the shared key for their second factor. It is stored with restricted permissions under the user’s home directory and must never be logged, exported, or copied off the BMC — treat it with the same care as a private key or password hash.


Session Management

View Active Sessions

# List sessions
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/SessionService/Sessions

Terminate Session

# Delete specific session
curl -k -u root:0penBmc -X DELETE \
    https://localhost/redfish/v1/SessionService/Sessions/session_id

Session Timeout

# Configure session timeout
curl -k -u root:0penBmc -X PATCH \
    -H "Content-Type: application/json" \
    -d '{"SessionTimeout": 1800}' \
    https://localhost/redfish/v1/SessionService

Troubleshooting

Login Failures

# Check PAM logs
journalctl | grep pam

# Check user exists
cat /etc/passwd | grep username

# Verify user enabled
busctl get-property xyz.openbmc_project.User.Manager \
    /xyz/openbmc_project/user/username \
    xyz.openbmc_project.User.Attributes \
    UserEnabled

LDAP Issues

# Check LDAP service
systemctl status nslcd

# Test LDAP bind
ldapwhoami -x -H ldap://ldap.example.com \
    -D "uid=user,dc=example,dc=com" -W

# Check LDAP configuration
busctl introspect xyz.openbmc_project.User.Manager \
    /xyz/openbmc_project/user/ldap

Account Locked

# Check lockout status (via PAM tally)
pam_tally2 --user=username

# Reset lockout
pam_tally2 --user=username --reset

Deep Dive

Advanced implementation details for user management developers.

PAM Integration

OpenBMC uses PAM (Pluggable Authentication Modules) for authentication:

┌─────────────────────────────────────────────────────────────────────────┐
│                    PAM Authentication Flow                              │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   Login Request (Redfish/IPMI/SSH)                                      │
│          │                                                              │
│          ▼                                                              │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │                    PAM Stack                                    │   │
│   │   /etc/pam.d/common-auth                                        │   │
│   └────────────────────────────┬────────────────────────────────────┘   │
│                                │                                        │
│          ┌─────────────────────┼─────────────────────┐                  │
│          │                     │                     │                  │
│          ▼                     ▼                     ▼                  │
│   ┌────────────┐        ┌────────────┐        ┌────────────┐            │
│   │ pam_unix   │        │ pam_ldap   │        │ pam_radius │            │
│   │ (local)    │        │ (LDAP/AD)  │        │ (RADIUS)   │            │
│   └─────┬──────┘        └─────┬──────┘        └─────┬──────┘            │
│         │                     │                     │                   │
│         ▼                     ▼                     ▼                   │
│   /etc/shadow           LDAP Server           RADIUS Server             │
│                                                                         │
│   PAM Configuration (/etc/pam.d/common-auth):                           │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │ auth sufficient pam_unix.so nullok try_first_pass               │   │
│   │ auth sufficient pam_ldap.so use_first_pass                      │   │
│   │ auth required   pam_deny.so                                     │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

PAM module flow:

  • sufficient: If module succeeds, skip remaining; if fails, continue
  • required: Must pass, but continue checking other modules
  • requisite: Must pass, fail immediately if not

LDAP Authentication Flow

┌─────────────────────────────────────────────────────────────────────────┐
│                    LDAP Authentication Sequence                         │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   BMC (phosphor-user-manager)              LDAP Server                  │
│          │                                      │                       │
│          │  1. Bind (service account)           │                       │
│          │─────────────────────────────────────▶│                       │
│          │◀─────────────────────────────────────│ Bind success          │
│          │                                      │                       │
│          │  2. Search (find user DN)            │                       │
│          │  filter: (uid=username)              │                       │
│          │─────────────────────────────────────▶│                       │
│          │◀─────────────────────────────────────│ User DN returned      │
│          │                                      │                       │
│          │  3. Bind (user DN + password)        │                       │
│          │─────────────────────────────────────▶│                       │
│          │◀─────────────────────────────────────│ Auth success/fail     │
│          │                                      │                       │
│          │  4. Search (get group membership)    │                       │
│          │  filter: (member=userDN)             │                       │
│          │─────────────────────────────────────▶│                       │
│          │◀─────────────────────────────────────│ Group list            │
│          │                                      │                       │
│                                                                         │
│   Group to Privilege Mapping:                                           │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │ LDAP Group          │ OpenBMC Role      │ IPMI Privilege        │   │
│   ├─────────────────────┼───────────────────┼───────────────────────┤   │
│   │ cn=bmc-admins       │ Administrator     │ 4 (Administrator)     │   │
│   │ cn=bmc-operators    │ Operator          │ 3 (Operator)          │   │
│   │ cn=bmc-users        │ User              │ 2 (User)              │   │
│   │ cn=bmc-readonly     │ ReadOnly          │ 1 (Callback)          │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Password Hashing

┌─────────────────────────────────────────────────────────────────────────┐
│                    Password Storage                                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   /etc/shadow format:                                                   │
│   username:$6$salt$hash:lastchange:min:max:warn:inactive:expire:        │
│                                                                         │
│   Hash Types:                                                           │
│   ├── $1$ = MD5 (deprecated, insecure)                                  │
│   ├── $5$ = SHA-256                                                     │
│   └── $6$ = SHA-512 (default, recommended)                              │
│                                                                         │
│   Password Change Flow:                                                 │
│   ┌──────────────────────────────────────────────────────────────────┐  │
│   │ 1. Redfish PATCH /AccountService/Accounts/{id}                   │  │
│   │    { "Password": "newPassword" }                                 │  │
│   │                                                                  │  │
│   │ 2. bmcweb calls D-Bus:                                           │  │
│   │    xyz.openbmc_project.User.Manager.RenameUser() or              │  │
│   │    org.freedesktop.Accounts.User.SetPassword()                   │  │
│   │                                                                  │  │
│   │ 3. phosphor-user-manager:                                        │  │
│   │    - Validates password policy (length, complexity)              │  │
│   │    - Calls pam_chauthtok() to update /etc/shadow                 │  │
│   │    - Emits PropertiesChanged signal                              │  │
│   └──────────────────────────────────────────────────────────────────┘  │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

D-Bus Permission Enforcement

┌─────────────────────────────────────────────────────────────────────────┐
│                    D-Bus Access Control                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   /etc/dbus-1/system.d/ policy files control D-Bus access:              │
│                                                                         │
│   Example: phosphor-user-manager.conf                                   │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │ <policy user="root">                                            │   │
│   │   <allow own="xyz.openbmc_project.User.Manager"/>               │   │
│   │   <allow send_destination="xyz.openbmc_project.User.Manager"/>  │   │
│   │ </policy>                                                       │   │
│   │                                                                 │   │
│   │ <policy context="default">                                      │   │
│   │   <deny send_destination="xyz.openbmc_project.User.Manager"     │   │
│   │         send_interface="xyz.openbmc_project.User.Manager"/>     │   │
│   │   <allow send_destination="xyz.openbmc_project.User.Manager"    │   │
│   │         send_interface="org.freedesktop.DBus.Properties"        │   │
│   │         send_member="Get"/>                                     │   │
│   │ </policy>                                                       │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│   Privilege Enforcement in bmcweb:                                      │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │ // Route with privilege requirement                             │   │
│   │ BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") │   │
│   │     .privileges(redfish::privileges::patchAccount)              │   │
│   │     .methods(boost::beast::http::verb::patch)(handlePatch);     │   │
│   │                                                                 │   │
│   │ // privileges::patchAccount requires ConfigureUsers             │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Source Code Reference

Key implementation files in phosphor-user-manager:

File Description
user_mgr.cpp Main user manager implementation
users.cpp Individual user object handling
ldap_config.cpp LDAP configuration management
ldap_mapper.cpp LDAP group to privilege mapping
shadowlock.cpp /etc/shadow file locking
phosphor-ldap-conf.cpp LDAP config daemon

Examples

Working examples are available in the examples/user-manager directory:

  • user-management.sh - User CRUD operations script
  • ldap-config.json - LDAP configuration example

References


Tested on: OpenBMC master, QEMU romulus


Back to top

OpenBMC Guide Tutorial is not affiliated with the OpenBMC project. Content is provided for educational purposes.

This site uses Just the Docs, a documentation theme for Jekyll.