Skip to content

Instantly share code, notes, and snippets.

@lukaszlach
Created December 2, 2023 22:22
Show Gist options
  • Select an option

  • Save lukaszlach/8a451ff4996094b7864a4a0d81c67f1e to your computer and use it in GitHub Desktop.

Select an option

Save lukaszlach/8a451ff4996094b7864a4a0d81c67f1e to your computer and use it in GitHub Desktop.

Revisions

  1. lukaszlach created this gist Dec 2, 2023.
    109 changes: 109 additions & 0 deletions su-exec.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,109 @@
    /* set user and group id and exec */

    #include <sys/types.h>

    #include <err.h>
    #include <errno.h>
    #include <grp.h>
    #include <pwd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>

    static char *argv0;

    static void usage(int exitcode)
    {
    printf("Usage: %s user-spec command [args]\n", argv0);
    exit(exitcode);
    }

    int main(int argc, char *argv[])
    {
    char *user, *group, **cmdargv;
    char *end;

    uid_t uid = getuid();
    gid_t gid = getgid();

    argv0 = argv[0];
    if (argc < 3)
    usage(0);

    user = argv[1];
    group = strchr(user, ':');
    if (group)
    *group++ = '\0';

    cmdargv = &argv[2];

    struct passwd *pw = NULL;
    if (user[0] != '\0') {
    uid_t nuid = strtol(user, &end, 10);
    if (*end == '\0')
    uid = nuid;
    else {
    pw = getpwnam(user);
    if (pw == NULL)
    err(1, "getpwnam(%s)", user);
    }
    }
    if (pw == NULL) {
    pw = getpwuid(uid);
    }
    if (pw != NULL) {
    uid = pw->pw_uid;
    gid = pw->pw_gid;
    }

    setenv("HOME", pw != NULL ? pw->pw_dir : "/", 1);

    if (group && group[0] != '\0') {
    /* group was specified, ignore grouplist for setgroups later */
    pw = NULL;

    gid_t ngid = strtol(group, &end, 10);
    if (*end == '\0')
    gid = ngid;
    else {
    struct group *gr = getgrnam(group);
    if (gr == NULL)
    err(1, "getgrnam(%s)", group);
    gid = gr->gr_gid;
    }
    }

    if (pw == NULL) {
    if (setgroups(1, &gid) < 0)
    err(1, "setgroups(%i)", gid);
    } else {
    int ngroups = 0;
    gid_t *glist = NULL;

    while (1) {
    int r = getgrouplist(pw->pw_name, gid, glist, &ngroups);

    if (r >= 0) {
    if (setgroups(ngroups, glist) < 0)
    err(1, "setgroups");
    break;
    }

    glist = realloc(glist, ngroups * sizeof(gid_t));
    if (glist == NULL)
    err(1, "malloc");
    }
    }

    if (setgid(gid) < 0)
    err(1, "setgid(%i)", gid);

    if (setuid(uid) < 0)
    err(1, "setuid(%i)", uid);

    execvp(cmdargv[0], cmdargv);
    err(1, "%s", cmdargv[0]);

    return 1;
    }