root/usr/src/cmd/krb5/kproplog/kproplog.c
/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * This module will parse the update logs on the master or slave servers.
 */

#include <stdio.h>
#include <libintl.h>
#include <sys/types.h>
#include <time.h>
#include <limits.h>
#include <locale.h>
#include <syslog.h>
#include <kdb/kdb_log.h>
#include <kadm5/admin.h>

static char     *progname;

static void
usage()
{
        (void) fprintf(stderr, gettext("\nUsage: %s [-h] [-v] [-e num]\n\n"),
            progname);
        exit(1);
}

/*
 * Print the individual types if verbose mode was specified.
 */
static void
print_attr(kdbe_attr_type_t type)
{
        switch (type) {
                case AT_ATTRFLAGS:
                        (void) printf(gettext("\t\tAttribute flags\n"));
                        break;
                case AT_MAX_LIFE:
                        (void) printf(gettext("\t\tMaximum ticket life\n"));
                        break;
                case AT_MAX_RENEW_LIFE:
                        (void) printf(gettext("\t\tMaximum renewable life\n"));
                        break;
                case AT_EXP:
                        (void) printf(gettext("\t\tPrincipal expiration\n"));
                        break;
                case AT_PW_EXP:
                        (void) printf(gettext("\t\tPassword expiration\n"));
                        break;
                case AT_LAST_SUCCESS:
                        (void) printf(gettext("\t\tLast successful auth\n"));
                        break;
                case AT_LAST_FAILED:
                        (void) printf(gettext("\t\tLast failed auth\n"));
                        break;
                case AT_FAIL_AUTH_COUNT:
                        (void) printf(gettext("\t\tFailed passwd attempt\n"));
                        break;
                case AT_PRINC:
                        (void) printf(gettext("\t\tPrincipal\n"));
                        break;
                case AT_KEYDATA:
                        (void) printf(gettext("\t\tKey data\n"));
                        break;
                case AT_TL_DATA:
                        (void) printf(gettext("\t\tTL data\n"));
                        break;
                case AT_LEN:
                        (void) printf(gettext("\t\tLength\n"));
                        break;
                case AT_MOD_PRINC:
                        (void) printf(gettext("\t\tModifying principal\n"));
                        break;
                case AT_MOD_TIME:
                        (void) printf(gettext("\t\tModification time\n"));
                        break;
                case AT_MOD_WHERE:
                        (void) printf(gettext("\t\tModified where\n"));
                        break;
                case AT_PW_LAST_CHANGE:
                        (void) printf(gettext("\t\tPassword last changed\n"));
                        break;
                case AT_PW_POLICY:
                        (void) printf(gettext("\t\tPassword policy\n"));
                        break;
                case AT_PW_POLICY_SWITCH:
                        (void) printf(gettext("\t\tPassword policy switch\n"));
                        break;
                case AT_PW_HIST_KVNO:
                        (void) printf(gettext("\t\tPassword history KVNO\n"));
                        break;
                case AT_PW_HIST:
                        (void) printf(gettext("\t\tPassword history\n"));
                        break;
        } /* switch */

}
/*
 * Print the update entry information
 */
static void
print_update(kdb_hlog_t *ulog, uint32_t entry, bool_t verbose)
{
        XDR             xdrs;
        uint32_t        start_sno, i, j, indx;
        char            *dbprinc;
        kdb_ent_header_t *indx_log;
        kdb_incr_update_t upd;

        if (entry && (entry < ulog->kdb_num))
                start_sno = ulog->kdb_last_sno - entry;
        else
                start_sno = ulog->kdb_first_sno - 1;

        for (i = start_sno; i < ulog->kdb_last_sno; i++) {
                indx = i % ulog->kdb_num;

                indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);

                /*
                 * Check for corrupt update entry
                 */
                if (indx_log->kdb_umagic != KDB_UMAGIC) {
                        (void) fprintf(stderr,
                            gettext("Corrupt update entry\n\n"));
                        exit(1);
                }

                (void) memset((char *)&upd, 0, sizeof (kdb_incr_update_t));
                xdrmem_create(&xdrs, (char *)indx_log->entry_data,
                    indx_log->kdb_entry_size, XDR_DECODE);
                if (!xdr_kdb_incr_update_t(&xdrs, &upd)) {
                        (void) printf(gettext("Entry data decode failure\n\n"));
                        exit(1);
                }

                (void) printf("---\n");
                (void) printf(gettext("Update Entry\n"));

                (void) printf(gettext("\tUpdate serial # : %u\n"),
                    indx_log->kdb_entry_sno);

                (void) printf(gettext("\tUpdate operation : "));
                if (upd.kdb_deleted)
                        (void) printf(gettext("Delete\n"));
                else
                        (void) printf(gettext("Add\n"));

                dbprinc = malloc(upd.kdb_princ_name.utf8str_t_len + 1);
                if (dbprinc == NULL) {
                        (void) printf(gettext("Could not allocate "
                            "principal name\n\n"));
                        exit(1);
                }
                (void) strlcpy(dbprinc, upd.kdb_princ_name.utf8str_t_val,
                    (upd.kdb_princ_name.utf8str_t_len + 1));
                (void) printf(gettext("\tUpdate principal : %s\n"), dbprinc);

                (void) printf(gettext("\tUpdate size : %u\n"),
                    indx_log->kdb_entry_size);

                (void) printf(gettext("\tUpdate committed : %s\n"),
                    indx_log->kdb_commit ? "True" : "False");

                if (indx_log->kdb_time.seconds == 0L)
                        (void) printf(gettext("\tUpdate time stamp : None\n"));
                else
                        (void) printf(gettext("\tUpdate time stamp : %s"),
                            ctime((time_t *)&(indx_log->kdb_time.seconds)));

                (void) printf(gettext("\tAttributes changed : %d\n"),
                    upd.kdb_update.kdbe_t_len);

                if (verbose)
                        for (j = 0; j < upd.kdb_update.kdbe_t_len; j++)
                                print_attr(
                                    upd.kdb_update.kdbe_t_val[j].av_type);

                xdr_free(xdr_kdb_incr_update_t, (char *)&upd);
                if (dbprinc)
                        free(dbprinc);
        } /* for */
}

int
main(int argc, char **argv)
{
        int                     c;
        bool_t                  verbose = FALSE;
        bool_t                  headeronly = FALSE;
        uint32_t                entry = 0;
        krb5_context            context;
        kadm5_config_params     params;
        kdb_log_context         *log_ctx;
        kdb_hlog_t              *ulog = NULL;

        (void) setlocale(LC_ALL, "");

#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif /* TEXT_DOMAIN */

        (void) textdomain(TEXT_DOMAIN);

        if (geteuid() != (uid_t)0) {
                (void) fprintf(stderr,
                    gettext("kproplog must be run as root\n\n"));
                exit(1);
        }

        progname = argv[0];

        while ((c = getopt(argc, argv, "vhe:")) != -1) {
                switch (c) {
                        case 'h':
                                headeronly = TRUE;
                                break;
                        case 'e':
                                entry = atoi(optarg);
                                break;
                        case 'v':
                                verbose = TRUE;
                                break;
                        default:
                                usage();
                }
        }

        if (krb5_init_context(&context)) {
                (void) fprintf(stderr,
                    gettext("Unable to initialize Kerberos\n\n"));
                exit(1);
        }

        (void) memset((char *)&params, 0, sizeof (params));

        if (kadm5_get_config_params(context, NULL, NULL, &params, &params)) {
                (void) fprintf(stderr,
                    gettext("Couldn't read database_name\n\n"));
                exit(1);
        }

        (void) printf(gettext("\nKerberos update log (%s.ulog)\n"),
            params.dbname);

        if (ulog_map(context, &params, FKPROPLOG)) {
                (void) fprintf(stderr, gettext("Unable to map log file "
                    "%s.ulog\n\n"), params.dbname);
                exit(1);
        }

        log_ctx = context->kdblog_context;
        if (log_ctx)
                ulog = log_ctx->ulog;
        else {
                (void) fprintf(stderr, gettext("Unable to map log file "
                    "%s.ulog\n\n"), params.dbname);
                exit(1);
        }

        if (ulog->kdb_hmagic != KDB_HMAGIC) {
                (void) fprintf(stderr,
                    gettext("Corrupt header log, exiting\n\n"));
                exit(1);
        }

        (void) printf(gettext("Update log dump :\n"));
        (void) printf(gettext("\tLog version # : %u\n"), ulog->db_version_num);
        (void) printf(gettext("\tLog state : "));
        switch (ulog->kdb_state) {
                case KDB_STABLE:
                        (void) printf(gettext("Stable\n"));
                        break;
                case KDB_UNSTABLE:
                        (void) printf(gettext("Unstable\n"));
                        break;
                case KDB_CORRUPT:
                        (void) printf(gettext("Corrupt\n"));
                        break;
                default:
                        (void) printf(gettext("Unknown state: %d\n"),
                            ulog->kdb_state);
                        break;
        }
        (void) printf(gettext("\tEntry block size : %u\n"), ulog->kdb_block);
        (void) printf(gettext("\tNumber of entries : %u\n"), ulog->kdb_num);

        if (ulog->kdb_last_sno == 0)
                (void) printf(gettext("\tLast serial # : None\n"));
        else {
                if (ulog->kdb_first_sno == 0)
                        (void) printf(gettext("\tFirst serial # : None\n"));
                else {
                        (void) printf(gettext("\tFirst serial # : "));
                        (void) printf("%u\n", ulog->kdb_first_sno);
                }

                (void) printf(gettext("\tLast serial # : "));
                (void) printf("%u\n", ulog->kdb_last_sno);
        }

        if (ulog->kdb_last_time.seconds == 0L) {
                (void) printf(gettext("\tLast time stamp : None\n"));
        } else {
                if (ulog->kdb_first_time.seconds == 0L)
                        (void) printf(gettext("\tFirst time stamp : None\n"));
                else {
                        (void) printf(gettext("\tFirst time stamp : %s"),
                            ctime((time_t *)
                            &(ulog->kdb_first_time.seconds)));
                }

                (void) printf(gettext("\tLast time stamp : %s\n"),
                    ctime((time_t *)&(ulog->kdb_last_time.seconds)));
        }

        if ((!headeronly) && ulog->kdb_num) {
                print_update(ulog, entry, verbose);
        }

        (void) printf("\n");

        return (0);
}