/*
 * legacy-auth.c.txt
 * =================
 * INTENTIONALLY VULNERABLE C authentication module for CTF / code-auditing practice.
 * DO NOT compile or deploy in production. All vulnerabilities are educational.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_USERS    100
#define TOKEN_LEN    32

struct User {
    char username[32];
    char password[64];
    int  privilege_level;
    int  is_active;
};

static struct User user_db[MAX_USERS];
static int user_count = 0;

/* VULNERABILITY: Buffer Overflow -- strcpy with no bounds checking */
int register_user(const char *username, const char *password, int privilege) {
    if (user_count >= MAX_USERS) return -1;

    struct User *u = &user_db[user_count];
    /* Vulnerable: username could exceed 32-byte buffer */
    strcpy(u->username, username);   /* TODO: add bounds check */
    strcpy(u->password, password);   /* TODO: add bounds check */
    u->privilege_level = privilege;
    u->is_active = 1;
    user_count++;
    return 0;
}

/* VULNERABILITY: Format String -- printf with user-controlled format */
void log_login_attempt(const char *username) {
    char log_msg[256];
    snprintf(log_msg, sizeof(log_msg), "Login attempt: %s", username);
    /* Vulnerable: log_msg is user-controlled and used as format string */
    printf(log_msg);   /* TODO: should be printf("%s", log_msg) */
    printf("\n");
}

/* VULNERABILITY: Use-After-Free */
struct User *find_and_deactivate(const char *username) {
    struct User *found = NULL;
    for (int i = 0; i < user_count; i++) {
        if (strcmp(user_db[i].username, username) == 0) {
            found = malloc(sizeof(struct User));
            memcpy(found, &user_db[i], sizeof(struct User));
            break;
        }
    }
    if (found) {
        found->is_active = 0;
        /* Vulnerable: freeing the struct, then returning the dangling pointer */
        free(found);  /* TODO: do not free before returning */
    }
    return found;  /* caller receives a dangling pointer */
}

/* VULNERABILITY: Integer Overflow in token allocation */
char *generate_tokens(unsigned int count) {
    /* Vulnerable: count * TOKEN_LEN can wrap around to a small value.
       e.g., count = 0x08000001 => 0x08000001 * 32 = 0x100000020,
       which truncates to 0x00000020 (32) on 32-bit size_t. */
    size_t total_size = count * TOKEN_LEN;  /* TODO: check for overflow */
    char *tokens = malloc(total_size);
    if (!tokens) return NULL;

    for (unsigned int i = 0; i < count; i++) {
        /* Writes far beyond allocated buffer when overflow occurred */
        memset(tokens + (i * TOKEN_LEN), 'A' + (i % 26), TOKEN_LEN);
    }
    return tokens;
}

/* VULNERABILITY: Stack-based Buffer Overflow via gets() */
int authenticate(void) {
    char username[32];
    char password[64];

    printf("Username: ");
    gets(username);           /* TODO: never use gets() */
    printf("Password: ");
    gets(password);           /* TODO: never use gets() */

    log_login_attempt(username);

    for (int i = 0; i < user_count; i++) {
        if (strcmp(user_db[i].username, username) == 0 &&
            strcmp(user_db[i].password, password) == 0) {
            if (!user_db[i].is_active) {
                printf("Account deactivated.\n");
                return -1;
            }
            printf("Welcome, %s (privilege %d)\n",
                   user_db[i].username, user_db[i].privilege_level);
            return user_db[i].privilege_level;
        }
    }
    printf("Authentication failed.\n");
    return -1;
}

int main(void) {
    register_user("admin", "correcthorsebatterystaple", 9);
    register_user("guest", "guest", 0);

    int level = authenticate();
    if (level > 0) {
        printf("Elevated access granted.\n");
    }
    return 0;
}
