# 5.3 Reading and writing a file's security descriptor

_Peios / Developing for Peios / SDK Reference / file.h — File Security_

> Getting and setting a file's descriptor by path or by fd, with the secinfo mask that selects which components are touched.

A file's SD can be accessed **by path** or **by fd**. In both cases `secinfo` is a mask of `KACS_SECINFO_*` bits selecting which components (owner, group, DACL, SACL, …) the operation touches — you read or write just the parts you name and leave the rest alone.

The rights required scale with the components you touch (see [Managing file security](/peios/security-fundamentals/file-access/managing-file-security.md)):

| Component (`KACS_SECINFO_*`) | Reading needs | Writing needs |
|---|---|---|
| `OWNER` / `GROUP` | `READ_CONTROL` | `WRITE_OWNER` (plus owner-SID validation) |
| `DACL` | `READ_CONTROL` | `WRITE_DAC` |
| `SACL` | `ACCESS_SYSTEM_SECURITY` | `ACCESS_SYSTEM_SECURITY` |
| `LABEL` | `READ_CONTROL` | `WRITE_OWNER` (the label cannot rise above the caller's integrity without `SeRelabelPrivilege`) |

`ACCESS_SYSTEM_SECURITY` is itself gated by `SeSecurityPrivilege`; `READ_CONTROL` and `WRITE_DAC` are implicitly granted to the owner. `SACL` and `LABEL` cannot be combined in one call (`EINVAL`). The check is all-or-nothing: if any requested component fails its check, the whole call fails.

### 5.3.0.1 By path

```c
ssize_t peios_file_get_sd(int dirfd, const char *path, uint32_t secinfo,
                          void *buf, size_t cap, uint32_t at_flags);
int     peios_file_set_sd(int dirfd, const char *path, uint32_t secinfo,
                          const void *sd, size_t len, uint32_t at_flags);
```

- `peios_file_get_sd` reads the `secinfo`-selected components of `path`'s SD into `buf`, getxattr-style ([two-call protocol](/peios/developing-for-peios/sdk-reference/sdk-conventions/library-conventions.md#the-two-call-buffer-protocol) — probe with `cap == 0`, and a too-small non-zero buffer fails `ERANGE` without truncating). `at_flags` accepts `AT_SYMLINK_NOFOLLOW`. Errors: `EACCES` (component right missing), `EINVAL` (`SACL` + `LABEL` together; `NULL` path, or `NULL` buffer with non-zero `cap`), `ERANGE` (non-probe buffer too small), `ENOENT` (path doesn't exist), `ELOOP` (no-follow and symlink).
- `peios_file_set_sd` writes the `secinfo` components of `sd` onto `path`, **preserving the components you did not select**. So to change only the DACL, build an SD with a DACL, pass `secinfo = KACS_SECINFO_DACL`, and the owner/group/SACL are untouched. Errors: `EACCES` (component right missing), `EPERM` (owner-SID validation failed without `SeRestorePrivilege`; label raised without `SeRelabelPrivilege`; MANDATORY attribute removed without `SeTcbPrivilege`), `EINVAL` (malformed SD, `SACL` + `LABEL` together, `NULL` or zero-length `sd`), `ENOENT`, `ELOOP`.

### 5.3.0.2 By fd

```c
ssize_t peios_fd_get_sd(int fd, uint32_t secinfo, void *buf, size_t cap);
int     peios_fd_set_sd(int fd, uint32_t secinfo, const void *sd, size_t len);
```

The same operations against the object `fd` already refers to. The access check they perform depends on the fd type: a normal file fd is checked against its **cached granted mask** (the one baked in at open), while an `O_PATH`, pidfd, or token fd triggers a **live** check. That distinction — cached for the fixed-grant file fd, live for the others — is documented in the Peios Kernel TRM §3.9, FACS; the practical upshot is that a file fd already opened with the right access can get/set its SD without a second path resolution.

The required rights and errors match the by-path calls, minus the path-resolution failures (`ENOENT`/`ELOOP`), plus `EBADF` (bad fd).
