Viewing: login.c
📄 login.c (Read Only) ⬅ To go back
// SPDX-License-Identifier: BSD-3-Clause
/*
 * Copyright (c) 2018, Tulio A M Mendes <[email protected]>
 * All rights reserved.
 * See LICENSE for details.
 *
 * Source: https://github.com/tadryanom/AdrOS
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pwd.h>
#include <termios.h>
#include <sys/types.h>
#include <utmp.h>
#include <sys/utsname.h>

/* Simple login command */
int main(int argc, char** argv) {
    (void)argc;
    (void)argv;

    printf("AdrOS Login\n");

    while (1) {
        char username[64];
        char password[64];
        char tty_name[32] = "ttyS0";  /* Default TTY */

        /* Get TTY name from environment or default */
        char* tty = ttyname(STDIN_FILENO);
        if (tty) {
            /* Strip /dev/ prefix if present */
            if (strncmp(tty, "/dev/", 5) == 0) {
                strncpy(tty_name, tty + 5, sizeof(tty_name) - 1);
            } else {
                strncpy(tty_name, tty, sizeof(tty_name) - 1);
            }
            tty_name[sizeof(tty_name) - 1] = '\0';
        }

        /* Prompt for username */
        printf("login: ");
        fflush(stdout);

        if (fgets(username, sizeof(username), stdin) == NULL) {
            break;
        }

        /* Remove trailing newline */
        size_t len = strlen(username);
        if (len > 0 && username[len - 1] == '\n') {
            username[len - 1] = '\0';
        }

        if (username[0] == '\0') {
            continue;
        }

        /* Prompt for password (no echo) */
        printf("Password: ");
        fflush(stdout);

        /* Disable echo */
        struct termios oldt, newt;
        tcgetattr(STDIN_FILENO, &oldt);
        newt = oldt;
        newt.c_lflag &= ~ECHO;
        tcsetattr(STDIN_FILENO, TCSANOW, &newt);

        if (fgets(password, sizeof(password), stdin) == NULL) {
            tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
            printf("\n");
            break;
        }

        /* Restore echo */
        tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
        printf("\n");

        /* Remove trailing newline */
        len = strlen(password);
        if (len > 0 && password[len - 1] == '\n') {
            password[len - 1] = '\0';
        }

        /* Verify password */
        if (check_password(username, password) == 0) {
            /* Authentication successful */
            struct passwd* pw = getpwnam(username);
            if (pw) {
                printf("Welcome %s!\n", pw->pw_name);

                /* Set UID/GID */
                if (setgid(pw->pw_gid) < 0) {
                    perror("setgid");
                    continue;
                }
                if (setuid(pw->pw_uid) < 0) {
                    perror("setuid");
                    continue;
                }

                /* Change to home directory */
                if (pw->pw_dir && pw->pw_dir[0] != '\0') {
                    chdir(pw->pw_dir);
                }

                /* Register login in utmp */
                struct utsname uts;
                char hostname[64] = "localhost";
                if (uname(&uts) == 0) {
                    strncpy(hostname, uts.nodename, sizeof(hostname) - 1);
                    hostname[sizeof(hostname) - 1] = '\0';
                }
                utmp_login(getpid(), tty_name, username, hostname);

                /* Execute shell */
                char* shell = pw->pw_shell;
                if (!shell || shell[0] == '\0') {
                    shell = "/bin/sh";
                }

                execl(shell, shell, NULL);
                perror("execl");
                exit(1);
            } else {
                printf("Login failed (user not found)\n");
            }
        } else {
            printf("Login incorrect\n");
        }
    }

    return 1;
}