Exemple #1
0
/* Helper functions */
int _pam_send_account(int tac_fd, int type, const char *user, char *tty,
    char *r_addr, char *cmd) {

    char buf[64];
    struct tac_attrib *attr;
    int retval;

    attr=(struct tac_attrib *)xcalloc(1, sizeof(struct tac_attrib));

    sprintf(buf, "%lu", (unsigned long)time(NULL));

    if (type == TAC_PLUS_ACCT_FLAG_START) {
        tac_add_attrib(&attr, "start_time", buf);
    } else if (type == TAC_PLUS_ACCT_FLAG_STOP) {
        tac_add_attrib(&attr, "stop_time", buf);
    }
    sprintf(buf, "%hu", task_id);
    tac_add_attrib(&attr, "task_id", buf);
    tac_add_attrib(&attr, "service", tac_service);
    if(tac_protocol[0] != '\0')
      tac_add_attrib(&attr, "protocol", tac_protocol);
    if (cmd != NULL) {
        tac_add_attrib(&attr, "cmd", cmd);
    }

    retval = tac_acct_send(tac_fd, type, user, tty, r_addr, attr);

    /* this is no longer needed */
    tac_free_attrib(&attr);

    if(retval < 0) {
        _pam_log (LOG_WARNING, "%s: send %s accounting failed (task %hu)",
            __FUNCTION__,
            tac_acct_flag2str(type),
            task_id);
        close(tac_fd);
        return -1;
    }

    struct areply re;
    if( tac_acct_read(tac_fd, &re) != TAC_PLUS_ACCT_STATUS_SUCCESS ) {
        _pam_log (LOG_WARNING, "%s: accounting %s failed (task %hu)",
            __FUNCTION__,
            tac_acct_flag2str(type),
            task_id);

        if(re.msg != NULL)
            xfree(re.msg);

        close(tac_fd);
        return -1;
    }

    if(re.msg != NULL)
        xfree(re.msg);

    close(tac_fd);
    return 0;
}
Exemple #2
0
int main(int argc, char **argv) {
    char *pass = NULL;
    char *tty = NULL;
    char *command = NULL;
    char *remote_addr = NULL;
    char *service = NULL;
    char *protocol = NULL;
    struct addrinfo *tac_server;
    char *tac_server_name = NULL;
    char *tac_secret = NULL;
    int tac_fd;
    short int task_id = 0;
    char buf[40];
    int ret;
#ifndef USE_SYSTEM
    pid_t pid;
#endif
    struct areply arep;

    /* options */
    flag log_wtmp = 1;
    flag do_author = 0;
    flag do_authen = 0;
    flag do_account = 0;
    flag login_mode = 0;

    /* check argc */
    if (argc < 2) {
        showusage(argv[0]);
        exit(EXIT_ERR);
    }

    /* check for login mode */
    if (argc == 2 && isalpha(*argv[1])) {
        g_user = argv[1];
        do_author = do_authen = do_account = 1;
        command = DEFAULT_COMMAND;
        login_mode = 1;
    } else {
        int c;
        int opt_index;

        while ((c = getopt_long(argc, argv, opt_string, long_options,
                                &opt_index)) != EOF) {
            switch (c) {
                case 'T':
                    do_authen = 1;
                    break;
                case 'R':
                    do_author = 1;
                    break;
                case 'A':
                    do_account = 1;
                    break;
                case 'V':
                    showversion(argv[0]);
                    /*NOTREACHED*/
                    break;
                case 'h':
                    showusage(argv[0]);
                    /*NOTREACHED*/
                    break;
                case 'u':
                    g_user = optarg;
                    break;
                case 'r':
                    remote_addr = optarg;
                    break;
                case 'L':
                    // tac_login is a global variable initialized in libtac
                    xstrcpy(tac_login, optarg, sizeof(tac_login));
                    break;
                case 'p':
                    pass = optarg;
                    break;
                case 's':
                    tac_server_name = optarg;
                    break;
                case 'k':
                    tac_secret = optarg;
                    break;
                case 'c':
                    command = optarg;
                    break;
                case 'S':
                    service = optarg;
                    break;
                case 'P':
                    protocol = optarg;
                    break;
                case 'q':
                    quiet = 1;
                    break;
                case 'w':
                    log_wtmp = 0;
                    break;
                case 'n':
                    tac_encryption = 0;
                    break;
                case 'y':
                    tty = optarg;
                    break;
            }
        }
    }

    /* check available information and set to defaults if needed */
    if (do_authen + do_author + do_account == 0) {
        printf("error: one of -TRAVh options is required\n");
        exit(EXIT_ERR);
    }

    if (g_user == NULL) {
        printf("error: username is required.\n");
        exit(EXIT_ERR);
    }

    if (remote_addr == NULL) {
        printf("error: remote address is required.\n");
        exit(EXIT_ERR);
    }

    if (service == NULL) {
        printf("error: service is required.\n");
        exit(EXIT_ERR);
    }

    if (protocol == NULL) {
        printf("error: protocol is required.\n");
        exit(EXIT_ERR);
    }

    if (tac_server_name == NULL) {
        printf("error: server name is required.\n");
        exit(EXIT_ERR);
    }

    struct addrinfo hints;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    ret = getaddrinfo(tac_server_name, "tacacs", &hints, &tac_server);
    if (ret != 0) {
        printf("error: resolving name %s: %s", tac_server_name,
               gai_strerror(ret));
        exit(EXIT_ERR);
    }

    if (tac_secret == NULL) {
        printf("error: server secret is required.\n");
        exit(EXIT_ERR);
    }

    if (pass == NULL) {
        signal(SIGALRM, timeout_handler);
        alarm(GETPASS_TIMEOUT);
        pass = getpass(PASSWORD_PROMPT);
        alarm(0);
        signal(SIGALRM, SIG_DFL);
        if (!strlen(pass))
            exit(EXIT_ERR);
    }

    if (tty == NULL) {
        printf("error: tty name is required.\n");
        exit(EXIT_ERR);
    }

    /* open syslog before any TACACS+ calls */
    openlog("tacc", LOG_CONS | LOG_PID, LOG_AUTHPRIV);

    if (do_authen)
        authenticate(tac_server, tac_secret, g_user, pass, tty, remote_addr);

    if (do_author) {
        /* authorize user */
        struct tac_attrib *attr = NULL;
        tac_add_attrib(&attr, "service", service);
        tac_add_attrib(&attr, "protocol", protocol);

        tac_fd = tac_connect_single(tac_server, tac_secret, NULL, 60);
        if (tac_fd < 0) {
            if (!quiet)
                printf("Error connecting to TACACS+ server: %m\n");
            exit(EXIT_ERR);
        }

        tac_author_send(tac_fd, g_user, tty, remote_addr, attr);

        tac_author_read(tac_fd, &arep);
        if (arep.status != AUTHOR_STATUS_PASS_ADD
            && arep.status != AUTHOR_STATUS_PASS_REPL) {
            if (!quiet)
                printf("Authorization FAILED: %s\n", arep.msg);
            exit(EXIT_FAIL);
        } else {
            if (!quiet)
                printf("Authorization OK: %s\n", arep.msg);
        }

        tac_free_attrib(&attr);
    }

    /* we no longer need the password in our address space */
    bzero(pass, strlen(pass));
    pass = NULL;

    if (do_account) {
        /* start accounting */
        struct tac_attrib *attr = NULL;

        sprintf(buf, "%lu", time(0));
        tac_add_attrib(&attr, "start_time", buf);

        // this is not crypto but merely an identifier
        long rnd_id = random();
        memcpy(&task_id, &rnd_id, sizeof(task_id));

        sprintf(buf, "%hu", task_id);
        tac_add_attrib(&attr, "task_id", buf);
        tac_add_attrib(&attr, "service", service);
        tac_add_attrib(&attr, "protocol", protocol);

        tac_fd = tac_connect_single(tac_server, tac_secret, NULL, 60);
        if (tac_fd < 0) {
            if (!quiet)
                printf("Error connecting to TACACS+ server: %m\n");
            exit(EXIT_ERR);
        }

        tac_acct_send(tac_fd, TAC_PLUS_ACCT_FLAG_START, g_user, tty, remote_addr,
                      attr);

        ret = tac_acct_read(tac_fd, &arep);
        if (ret == 0) {
            if (!quiet)
                printf("Accounting: START failed: %s\n", arep.msg);
            syslog(LOG_INFO, "TACACS+ accounting start failed: %s", arep.msg);
        } else if (!login_mode && !quiet)
            printf("Accounting: START OK\n");

        close(tac_fd);

        tac_free_attrib(&attr);

    }

    /* log in local utmp */
    if (log_wtmp) {
#if defined(HAVE_PUTUTXLINE)
        struct timeval tv;

        gettimeofday(&tv, NULL);

        memset(&utmpx, 0, sizeof(utmpx));
        utmpx.ut_type = USER_PROCESS;
        utmpx.ut_pid = getpid();
        xstrcpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line));
        strncpy(utmpx.ut_id, tty + C_STRLEN("tty"), sizeof(utmpx.ut_id));
        xstrcpy(utmpx.ut_host, "dialup", sizeof(utmpx.ut_host));
        utmpx.ut_tv.tv_sec = tv.tv_sec;
        utmpx.ut_tv.tv_usec = tv.tv_usec;
        xstrcpy(utmpx.ut_user, g_user, sizeof(utmpx.ut_user));
        /* ut_addr unused ... */
        setutxent();
        pututxline(&utmpx);
#elif defined(HAVE_LOGWTMP)
        logwtmp(tty, g_user, "dialup");
#endif
    }

    if (command != NULL) {
        int ret;

        syslog(LOG_DEBUG, "starting %s for %s", command, g_user);

        signal(SIGHUP, SIG_IGN);
        signal(SIGTERM, SIG_IGN);
        signal(SIGINT, SIG_IGN);
        signal(SIGCHLD, SIG_IGN);

#ifdef COMMAND_MESSAGE
        printf(COMMAND_MESSAGE);
#endif

#if USE_SYSTEM
        ret = system(command);
        if (ret < 0)
            syslog(LOG_WARNING, "command failed: %m");
        else
            syslog(LOG_NOTICE, "command exit code %u", ret);
#else
        pid=fork();

        if(pid == 0) {
            /* child */

            execl(DEFAULT_COMMAND, DEFAULT_COMMAND, ARGS, NULL);
            syslog(LOG_ERR, "execl() failed: %m");
            _exit(EXIT_FAIL);
        }

        if(pid < 0) {
            /* error */
            syslog(LOG_ERR, "fork failed: %m");
            exit(EXIT_FAIL);
        }

        if(pid > 0) {
            /* parent */
            int st, r;

            r=wait(&st);
        }
#endif
    }

    if (do_account) {
        /* stop accounting */
        struct tac_attrib *attr = NULL;
        sprintf(buf, "%lu", time(0));
        tac_add_attrib(&attr, "stop_time", buf);
        sprintf(buf, "%hu", task_id);
        tac_add_attrib(&attr, "task_id", buf);

        tac_fd = tac_connect_single(tac_server, tac_secret, NULL, 60);
        if (tac_fd < 0) {
            if (!quiet)
                printf("Error connecting to TACACS+ server: %m\n");
            exit(EXIT_ERR);
        }

        tac_acct_send(tac_fd, TAC_PLUS_ACCT_FLAG_STOP, g_user, tty, remote_addr,
                      attr);
        ret = tac_acct_read(tac_fd, &arep);
        if (ret == 0) {
            if (!quiet)
                printf("Accounting: STOP failed: %s", arep.msg);
            syslog(LOG_INFO, "TACACS+ accounting stop failed: %s\n", arep.msg);
        } else if (!login_mode && !quiet)
            printf("Accounting: STOP OK\n");

        close(tac_fd);

        tac_free_attrib(&attr);
    }

    /* logout from utmp */
    if (log_wtmp) {
#if defined(HAVE_PUTUTXLINE)
        utmpx.ut_type = DEAD_PROCESS;
        memset(utmpx.ut_line, 0, sizeof(utmpx.ut_line));
        memset(utmpx.ut_user, 0, sizeof(utmpx.ut_user));
        memset(utmpx.ut_host, 0, sizeof(utmpx.ut_host));
        utmpx.ut_tv.tv_sec = utmpx.ut_tv.tv_usec = 0;
        setutxent();
        pututxline(&utmpx);
#elif defined(HAVE_LOGWTMP)
        logwtmp(tty, "", "");
#endif
    }

    exit(EXIT_OK);
}