root/usr/src/lib/libbsm/common/audit_ftpd.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
 */

#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>

#include <sys/socket.h>
#include <sys/sockio.h>
#include <netinet/in.h>
#include <tsol/label.h>

#include <bsm/audit.h>
#include <bsm/audit_record.h>
#include <bsm/audit_uevents.h>
#include <bsm/libbsm.h>
#include <bsm/audit_private.h>

#include <locale.h>
#include <pwd.h>
#include <generic.h>

#define BAD_PASSWD      (1)
#define UNKNOWN_USER    (2)
#define EXCLUDED_USER   (3)
#define NO_ANONYMOUS    (4)
#define MISC_FAILURE    (5)

static char             luser[LOGNAME_MAX + 1];

static void generate_record(char *, int, char *);
static int selected(uid_t, char *, au_event_t, int);

void
audit_ftpd_bad_pw(char *uname)
{
        if (cannot_audit(0)) {
                return;
        }
        (void) strncpy(luser, uname, LOGNAME_MAX);
        generate_record(luser, BAD_PASSWD, dgettext(bsm_dom, "bad password"));
}


void
audit_ftpd_unknown(char *uname)
{
        if (cannot_audit(0)) {
                return;
        }
        (void) strncpy(luser, uname, LOGNAME_MAX);
        generate_record(luser, UNKNOWN_USER, dgettext(bsm_dom, "unknown user"));
}


void
audit_ftpd_excluded(char *uname)
{
        if (cannot_audit(0)) {
                return;
        }
        (void) strncpy(luser, uname, LOGNAME_MAX);
        generate_record(luser, EXCLUDED_USER, dgettext(bsm_dom,
            "excluded user"));
}


void
audit_ftpd_no_anon(void)
{
        if (cannot_audit(0)) {
                return;
        }
        generate_record("", NO_ANONYMOUS, dgettext(bsm_dom, "no anonymous"));
}

void
audit_ftpd_failure(char *uname)
{
        if (cannot_audit(0)) {
                return;
        }
        generate_record(uname, MISC_FAILURE, dgettext(bsm_dom, "misc failure"));
}

void
audit_ftpd_success(char *uname)
{
        if (cannot_audit(0)) {
                return;
        }
        (void) strncpy(luser, uname, LOGNAME_MAX);
        generate_record(luser, 0, "");
}



static void
generate_record(
                char    *locuser,       /* username of local user */
                int     err,            /* error status */
                                        /* (=0 success, >0 error code) */
                char    *msg)           /* error message */
{
        int     rd;             /* audit record descriptor */
        char    buf[256];       /* temporary buffer */
        uid_t   uid;
        gid_t   gid;
        uid_t   ruid;           /* real uid */
        gid_t   rgid;           /* real gid */
        pid_t   pid;
        struct passwd *pwd;
        uid_t   ceuid;          /* current effective uid */
        struct auditinfo_addr info;

        if (cannot_audit(0)) {
                return;
        }

        pwd = getpwnam(locuser);
        if (pwd == NULL) {
                uid = (uid_t)-1;
                gid = (gid_t)-1;
        } else {
                uid = pwd->pw_uid;
                gid = pwd->pw_gid;
        }

        ceuid = geteuid();      /* save current euid */
        (void) seteuid(0);      /* change to root so you can audit */

        /* determine if we're preselected */
        if (!selected(uid, locuser, AUE_ftpd, err)) {
                (void) seteuid(ceuid);
                return;
        }

        ruid = getuid();        /* get real uid */
        rgid = getgid();        /* get real gid */

        pid = getpid();

        /* see if terminal id already set */
        if (getaudit_addr(&info, sizeof (info)) < 0) {
                perror("getaudit");
        }

        rd = au_open();

        /* add subject token */
        (void) au_write(rd, au_to_subject_ex(uid, uid, gid,
            ruid, rgid, pid, pid, &info.ai_termid));

        if (is_system_labeled())
                (void) au_write(rd, au_to_mylabel());

        /* add return token */
        errno = 0;
        if (err) {
                /* add reason for failure */
                if (err == UNKNOWN_USER)
                        (void) snprintf(buf, sizeof (buf),
                            "%s %s", msg, locuser);
                else
                        (void) snprintf(buf, sizeof (buf), "%s", msg);
                (void) au_write(rd, au_to_text(buf));
#ifdef _LP64
                (void) au_write(rd, au_to_return64(-1, (int64_t)err));
#else
                (void) au_write(rd, au_to_return32(-1, (int32_t)err));
#endif
        } else {
#ifdef _LP64
                (void) au_write(rd, au_to_return64(0, (int64_t)0));
#else
                (void) au_write(rd, au_to_return32(0, (int32_t)0));
#endif
        }

        /* write audit record */
        if (au_close(rd, 1, AUE_ftpd) < 0) {
                (void) au_close(rd, 0, 0);
        }
        (void) seteuid(ceuid);
}


static int
selected(
        uid_t           uid,
        char            *locuser,
        au_event_t      event,
        int     err)
{
        int             sorf;
        struct au_mask  mask;

        mask.am_success = mask.am_failure = 0;
        if (uid > MAXEPHUID) {
                /* get non-attrib flags */
                (void) auditon(A_GETKMASK, (caddr_t)&mask, sizeof (mask));
        } else {
                (void) au_user_mask(locuser, &mask);
        }

        if (err == 0) {
                sorf = AU_PRS_SUCCESS;
        } else if (err >= 1) {
                sorf = AU_PRS_FAILURE;
        } else {
                sorf = AU_PRS_BOTH;
        }

        return (au_preselect(event, &mask, sorf, AU_PRS_REREAD));
}


void
audit_ftpd_logout(void)
{
        int     rd;             /* audit record descriptor */
        uid_t   euid;
        gid_t   egid;
        uid_t   uid;
        gid_t   gid;
        pid_t   pid;
        struct auditinfo_addr info;

        if (cannot_audit(0)) {
                return;
        }

        (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_AUDIT, NULL);

        /* see if terminal id already set */
        if (getaudit_addr(&info, sizeof (info)) < 0) {
                perror("getaudit");
        }

        /* determine if we're preselected */
        if (au_preselect(AUE_ftpd_logout, &info.ai_mask, AU_PRS_SUCCESS,
            AU_PRS_USECACHE) == 0) {
                (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_AUDIT,
                    NULL);
                return;
        }

        euid = geteuid();
        egid = getegid();
        uid = getuid();
        gid = getgid();
        pid = getpid();

        rd = au_open();

        /* add subject token */
        (void) au_write(rd, au_to_subject_ex(info.ai_auid, euid,
            egid, uid, gid, pid, pid, &info.ai_termid));

        if (is_system_labeled())
                (void) au_write(rd, au_to_mylabel());

        /* add return token */
        errno = 0;
#ifdef _LP64
        (void) au_write(rd, au_to_return64(0, (int64_t)0));
#else
        (void) au_write(rd, au_to_return32(0, (int32_t)0));
#endif

        /* write audit record */
        if (au_close(rd, 1, AUE_ftpd_logout) < 0) {
                (void) au_close(rd, 0, 0);
        }
        (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_AUDIT, NULL);
}