seteuid(2)

πŸ’– seteuid(2) β€” the "who am I really today" girlies πŸ’–

okay bestie, we're in section 2 of the manual (System Calls Manual, that's the syscall girlies) and today's topic is seteuid and setegid. it's giving identity crisis but make it privileged. let's go πŸ¦‹


✨ NAME ✨

seteuid, setegid β€” set effective user or group ID

so like. they change your effective ID. yes there's a real one and an effective one and a saved one. yes it's a whole thing. we'll get there. πŸ’…

πŸ“š LIBRARY πŸ“š

Standard C library (libc, -lc) β€” the classics, no cap.

🌸 SYNOPSIS 🌸

#include <unistd.h>

int seteuid(uid_t euid);
int setegid(gid_t egid);

look at them. two little functions. so much power. 😭

πŸŽ€ Feature Test Macro Requirements for glibc (see feature_test_macros(7)) πŸŽ€

seteuid(), setegid():
    _POSIX_C_SOURCE >= 200112L
        || /* glibc <= 2.19: */ _BSD_SOURCE
ngl if you're on old glibc (2.19 or earlier) you're gonna need _BSD_SOURCE to unlock these. vintage era behavior, we respect the elders 🫢

πŸ’– DESCRIPTION πŸ’–

seteuid() sets the effective user ID of the calling process. that's the one the kernel actually checks when you try to do stuff.

here's the tea for unprivileged processes: they may only set the effective user ID to

  • the real user ID,
  • the effective user ID, or
  • the saved set-user-ID.

that's it. that's the whole shortlist. no wandering off the menu, bestie.

Precisely the same holds for setegid() with "group" instead of "user". literally the exact same deal, just group flavored. πŸ“

πŸ”₯ RETURN VALUE πŸ”₯

On success, zero is returned. cute. clean. slay.

On error, -1 is returned, and errno is set to indicate the error.

Note: there are cases where seteuid() can fail even when the caller is UID 0; it is a grave security error to omit checking for a failure return from seteuid(). not me stressing about this but like. CHECK. YOUR. RETURN. VALUE. πŸ˜­πŸ”’ serious business only.

πŸ’€ ERRORS πŸ’€

  • EINVAL β€” The target user or group ID is not valid in this user namespace.
  • EPERM β€” In the case of seteuid(): the calling process is not privileged (does not have the CAP_SETUID capability in its user namespace) and euid does not match the current real user ID, current effective user ID, or current saved set-user-ID.

In the case of setegid(): the calling process is not privileged (does not have the CAP_SETGID capability in its user namespace) and egid does not match the current real group ID, current effective group ID, or current saved set-group-ID.

so basically, no capability + no match = permission denied, bestie. vibe check failed πŸ‘‘βŒ

🌈 VERSIONS 🌈

Setting the effective user (group) ID to the saved set-user-ID (saved set-group-ID) is possible since Linux 1.1.37 (1.1.38). On an arbitrary system one should check _POSIX_SAVED_IDS.

Under glibc 2.0, seteuid(euid) is equivalent to setreuid(-1, euid) and hence may change the saved set-user-ID. Under glibc 2.1 and later, it is equivalent to setresuid(-1, euid, -1) and hence does not change the saved set-user-ID. Analogous remarks hold for setegid(), with the difference that the change in implementation from setregid(-1, egid) to setresgid(-1, egid, -1) occurred in glibc 2.2 or 2.3 (depending on the hardware architecture).

so like. old glibc was out here changing your saved ID as a side quest and modern glibc said "not today". glow up fr. ✨

According to POSIX.1, seteuid() (setegid()) need not permit euid (egid) to be the same value as the current effective user (group) ID, and some implementations do not permit this.

🧚 C library/kernel differences 🧚

On Linux, seteuid() and setegid() are implemented as library functions that call, respectively, setresuid(2) and setresgid(2).

it's a wrapper. a cute little middleman. passing the message along πŸ’Œ

⭐ STANDARDS ⭐

POSIX.1-2024. periodt.

πŸ‘‘ HISTORY πŸ‘‘

POSIX.1-2001, 4.3BSD. ancient. iconic. still here.

πŸ¦‹ SEE ALSO πŸ¦‹

geteuid(2), setresuid(2), setreuid(2), setuid(2), capabilities(7), credentials(7), user_namespaces(7)

go read them, they're all part of the same lore arc i promise πŸ“–βœ¨


okay that's the whole page bestie!! this one's from Linux man-pages 6.20, dated 2026-02-08, and it's filed under seteuid(2). love that for us. go check your return values, stay hydrated, and never trust a -1 πŸ’–πŸŽ€πŸ«Ά

πŸ“¦ where this page comes from
  • arch rolling: man-pages 6.20-1 Β· BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • πŸ“œ the page's license: Linux-man-pages-copyleft
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms