#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define CODE_PATH  "/root/code"
#define FLAG_PATH  "/root/flag"
#define BUF_SIZE   256
#define NAME_LEN   32

static void read_secret(char *out, size_t max) {
    int fd = open(CODE_PATH, O_RDONLY);
    if (fd < 0) {
        perror("open code");
        exit(1);
    }
    ssize_t n = read(fd, out, max - 1);
    close(fd);
    if (n <= 0) {
        out[0] = '\0';
        return;
    }
    out[n] = '\0';
    if (n > 0 && out[n - 1] == '\n')
        out[n - 1] = '\0';
}

static void print_flag(void) {
    FILE *f = fopen(FLAG_PATH, "r");
    if (!f) {
        perror("fopen flag");
        return;
    }
    char buf[512];
    while (fgets(buf, sizeof(buf), f))
        fputs(buf, stdout);
    fclose(f);
}

static void self_rename(void) {
    char self[BUF_SIZE];
    ssize_t n = readlink("/proc/self/exe", self, sizeof(self) - 1);
    if (n <= 0)
        return;
    self[n] = '\0';

    char *dir = strrchr(self, '/');
    if (!dir)
        return;
    size_t dirlen = (size_t)(dir - self);
    if (dirlen >= sizeof(self))
        return;

    int fd = open("/dev/urandom", O_RDONLY);
    if (fd < 0)
        return;
    char name[NAME_LEN + 1];
    const char hex[] = "0123456789abcdef";
    for (int i = 0; i < NAME_LEN; i++) {
        unsigned char b;
        if (read(fd, &b, 1) != 1) {
            close(fd);
            return;
        }
        name[i] = hex[b % 16];
    }
    close(fd);
    name[NAME_LEN] = '\0';

    char newpath[BUF_SIZE];
    snprintf(newpath, sizeof(newpath), "%.*s/%s", (int)dirlen, self, name);
    rename(self, newpath);
}

int main(void) {
    if (setuid(0) != 0) {
        perror("setuid");
        return 1;
    }

    char secret[BUF_SIZE];
    read_secret(secret, sizeof(secret));

    char input[BUF_SIZE];
    if (!fgets(input, sizeof(input), stdin)) {
        self_rename();
        return 1;
    }
    size_t len = strlen(input);
    if (len > 0 && input[len - 1] == '\n') {
        input[len - 1] = '\0';
        len--;
    }

    if (strcmp(input, secret) == 0) {
        print_flag();
        return 0;
    }

    self_rename();
    return 1;
}
