# General note about security

`pam_usb` is intended as an "user comfort" utility. While it can enhance security, if used as a second factor, it can also reduce it.

Make sure you are aware of how it works and what you combine it with (see other warnings).

Also I want to point it that this is barely audited. I've tried to raise funds for it but there was literally no interest in it seemingly...

# Warning about XDMCP

This warning has been **partially mitigated** since 0.9.1 but XDMCP + pam_usb is still not recommended. Read carefully.

**What changed in 0.9.1 (GHSA-w38v-cw9r-x9p6):** The root cause of the original bypass was that the `PAM_RHOST` check was gated behind the `deny_remote` option. Display managers whitelisted with `deny_remote=false` (e.g. `gdm-password`, `lightdm`) also skipped the `PAM_RHOST` check entirely, so a remote XDMCP client was never identified as remote by pam_usb.

Since 0.9.1, the `PAM_RHOST` check runs unconditionally regardless of `deny_remote`. When a display manager correctly sets `PAM_RHOST` to the remote client's IP for XDMCP connections, pam_usb will detect it and return `PAM_IGNORE`.

**Why this is still not a guarantee:** `PAM_RHOST` is set by the display manager, not by the kernel or PAM itself. Whether a given DM sets it correctly for XDMCP depends on its implementation. Major display managers (GDM, LightDM) do set `PAM_RHOST` for remote sessions; less common or older DMs may not. If your DM does not set `PAM_RHOST` for XDMCP connections, the 0.9.1 fix offers no protection.

The `remote_desktop_check` option (enabled by default since 0.9.0) provides an additional layer via evdev virtual device detection, which XDMCP sessions typically trigger. However this too is not a guaranteed catch-all.

**Recommendation:** XDMCP is an unencrypted, largely deprecated protocol that should be avoided on general security grounds regardless of pam_usb. If you must use it, ensure you are on 0.9.1+ and verify that your specific display manager sets `PAM_RHOST` for XDMCP connections before relying on pam_usb as a meaningful security control.

# Warning about remote desktop tools

Since v0.8.8, pam_usb ships built-in remote desktop detection controlled by the `remote_desktop_check` option (default: `true`). When enabled, authentication is denied if a known remote desktop service is detected as active.

## What is detected

| Tool | Detection method |
|------|-----------------|
| **AnyDesk** | Process presence alone — denied even if no remote session is active |
| **VNC** (x11vnc, Xvnc, GNOME Remote Desktop/VNC) | Process running **and** external established connection on port 5900 |
| **RDP** (GNOME Remote Desktop/RDP) | Process running **and** external established connection on port 3389 |
| **TeamViewer** | Process running **and** outbound connection to TeamViewer relay servers (port 5938) |
| **Virtual input devices** | Any tool that injects synthetic input via a `BUS_VIRTUAL` evdev device with no physical path |

All checks exclude loopback connections — a VNC or RDP session over localhost is not treated as remote.

## What is still NOT reliably detected

- TeamViewer in idle state (daemon running but no active remote session)
- x11vnc / Xvnc with no client currently connected
- VNC or RDP servers listening on non-standard ports
- GNOME desktop sharing over WebRTC (newer GNOME Remote Desktop protocol)
- Parsec, Rustdesk, Chrome Remote Desktop, NoMachine, and other tools not listed above

There will likely always be some remote access software that can circumvent the check. If this is a concern, use pam_usb as a second factor (`required` instead of `sufficient` in your PAM stack) so a password is still required even when pam_usb grants access.

## Known false positives

The virtual input device check (`BUS_VIRTUAL` evdev devices) can produce false positives for locally-running tools that happen to create synthetic input devices:

- Screen readers and on-screen keyboards
- Drawing tablet drivers (Wacom, Huion)
- Key remappers (keyd, xremap, input-remapper)
- Accessibility software

If pam_usb unexpectedly denies access and you do not use any remote desktop tools, set `remote_desktop_check=false` in the relevant section of `/etc/security/pam_usb.conf` to disable the check.

# Warning about remote access (SSH etc)

In the past there have been ways to circumvent the local check (see issue [#51](https://github.com/mcdope/pam_usb/issues/51) and also the "[cup of tee](https://github.com/mcdope/pam_usb/issues/39)"). I'm confident that all known ways are fixed now.

But I need to underline "known"... I'm no security expert and it's very well possible that there are still ways to circumvent the checks.

Kudos to [@Fuseteam](https://github.com/Fuseteam) for extensive testing, breaking and reporting.

# Warning about the ability to unlock the GNOME keyring

If you use the ability to auto-unlock your keyring while using pam_usb you are exposing your keyring password to everyone being able to access the file containing it.

This means at least root (and users able to use sudo) can read your keyring password in cleartext. If you use the SAMBA feature to share your home directory you will also expose it to everyone allowed to access that share.

For most users this isn't an issue. But if you're sharing your machine with other users, or use it in a network, you should for sure keep it in mind.

# Require a specific device for superuser access

In case you want to use multiple devices, and enable only one (or some) of them for superuser grants (su, sudo, polkit) you can do so with some manual configuration. You need to be sure about covering every mechanism/pam service used in your system though, in example if you enable it for sudo only but the user is able to run pkexec it will obviously fail to take effect.

Available from v0.8.7.

This feature allows you to designate specific USB devices as **superuser-capable** — valid for privilege-escalation services such as `sudo`, `su`, and `polkit-1` — while other registered devices remain valid only for non-privileged services (login, screensaver unlock, etc.).

A single `superuser="true"` attribute on a `<device>` element covers all services you mark as requiring it. No per-service device entries are needed.

**Use case:** In a shared-account environment (e.g. school lab), students and teachers use the same Unix account. Students carry a StudentUSB that lets them log in; teachers carry a TeacherUSB that additionally grants `sudo` access. The configuration enforces this without creating separate accounts.

---

### How it works

Two things must be configured for the restriction to take effect:

1. **Mark the device** as superuser-capable in the `<user>` block, using the `superuser="true"` attribute on the `<device>` element.
2. **Mark the service** as requiring a superuser device, by setting `<option name="superuser">true</option>` inside the corresponding `<service>` block.

When a user authenticates against a service marked with `superuser=true`, any device in their list that does **not** carry the `superuser="true"` attribute is silently excluded for that authentication attempt. If no superuser-capable device is present, authentication is denied.

Services **not** marked with `superuser=true` are unaffected — all registered devices for the user remain valid (fully backward-compatible).

---

### Option reference

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `superuser` | Boolean | `false` | When set on a `<service>`, only devices with `superuser="true"` in the user's device list are accepted for that service. No effect when set on `<defaults>`, `<devices>`, or `<users>`. |

---

### User configuration

The `<device>` element under `<user>` accepts an optional `superuser` XML attribute:

| Name | Type | Description | Example |
|------|------|-------------|---------|
| `superuser` | Attribute (optional) | Marks this device as valid for superuser services. Devices without this attribute are excluded when the service requires superuser. | `superuser="true"` |

```xml
<user id="alex">
    <!-- Works for login and all non-superuser services -->
    <device>StudentUSB</device>

    <!-- Works for all services including sudo, su, polkit-1 -->
    <device superuser="true">TeacherUSB</device>
</user>
```

A device with `superuser="true"` is **not** restricted to superuser services — it works for every service, including login. The attribute only adds eligibility for superuser-marked services.

---

### Service configuration

Mark any service as requiring a superuser-capable device by adding the `superuser` option:

```xml
<service id="sudo">
    <option name="superuser">true</option>
</service>

<service id="su">
    <option name="superuser">true</option>
</service>

<!-- polkit-1 is also whitelisted for deny_remote by default -->
<service id="polkit-1">
    <option name="superuser">true</option>
    <option name="deny_remote">false</option>
</service>
```

You can apply the `superuser` option to any service name that appears in your PAM configuration — it is not limited to `sudo`, `su`, and `polkit-1`.

---

### Complete example

**Scenario:** A shared account `labuser` has two USB keys. The StudentUSB grants login only; the TeacherUSB grants login and sudo/pkexec.

```xml
<configuration>
    <devices>
        <device id="StudentUSB">
            <vendor>SanDisk Corp.</vendor>
            <model>Cruzer Blade</model>
            <serial>SNDKXXXXXXXXXXXXXXXX</serial>
            <volume_uuid>AAAA-1111</volume_uuid>
        </device>

        <device id="TeacherUSB">
            <vendor>Kingston</vendor>
            <model>DataTraveler</model>
            <serial>KNGXXXXXXXXXXXXXXXXX</serial>
            <volume_uuid>BBBB-2222</volume_uuid>
        </device>
    </devices>

    <users>
        <user id="labuser">
            <device>StudentUSB</device>
            <device superuser="true">TeacherUSB</device>
        </user>
    </users>

    <services>
        <service id="sudo">
            <option name="superuser">true</option>
        </service>
        <service id="su">
            <option name="superuser">true</option>
        </service>
        <service id="polkit-1">
            <option name="superuser">true</option>
            <option name="deny_remote">false</option>
        </service>
    </services>
</configuration>
```

**Result:**

| Device | Service | Outcome |
|--------|---------|---------|
| StudentUSB | login, gdm, screensaver | Allowed |
| StudentUSB | sudo, su, polkit-1 | **Denied** - no `superuser` attribute |
| TeacherUSB | login, gdm, screensaver | Allowed |
| TeacherUSB | sudo, su, polkit-1 | Allowed |

---

### Log output

If all of a user's devices are excluded by the superuser filter, pam_usb emits an error visible in the system log even without debug mode *(from v0.9.2)*:

```
Service "sudo" for user "alex" requires a superuser-capable device but none of the registered devices have the superuser attribute.
```

With `<option name="debug">true</option>`, the per-device filtering decisions are also logged:

```
Service "sudo" requires superuser device. Filtering device list.
Device "StudentUSB" excluded for service "sudo" (no superuser attribute).
```

---

### Notes

- The restriction is configured entirely in `/etc/security/pam_usb.conf` — no PAM stack changes are needed.
- Adding more superuser-granted services requires only a new `<service>` entry; no change to the device or user configuration is needed.
- If a user has no device with `superuser="true"` and authenticates against a superuser-marked service, pam_usb denies the request. The fallback PAM module (e.g. `pam_unix`) still runs if configured as `sufficient` rather than `required`.
- `pamusb-conf` does not yet have a CLI flag for the `superuser` attribute — add it manually to the `<device>` element in the config file after running `pamusb-conf --add-user`. Tracked in [issue #337](https://github.com/mcdope/pam_usb/issues/337).