k5-klog-20061026
authorMarcus Watts <mdw@umich.edu>
Fri, 27 Oct 2006 00:39:15 +0000 (00:39 +0000)
committerJim Rees <rees@umich.edu>
Fri, 27 Oct 2006 00:39:15 +0000 (00:39 +0000)
k5 version of klog

src/aklog/Makefile.in
src/aklog/add_etbl.c [new file with mode: 0644]
src/aklog/klog.c [new file with mode: 0644]
src/aklog/skipwrap.c [new file with mode: 0644]

index 7693265..19086bc 100644 (file)
@@ -20,7 +20,7 @@ AFSLIBS = ${TOP_LIBDIR}/libprot.a ${TOP_LIBDIR}/libauth.a \
 SRCS=  aklog.c aklog_main.c  krb_util.c linked_list.c
 OBJS=   aklog.o aklog_main.o krb_util.o linked_list.o
 
-all: aklog @ASETKEY@
+all: aklog @ASETKEY@ klog
 
 aklog: ${OBJS} ${AFSLIBS}
        ${CC} -o $@ ${CFLAGS} ${OBJS} ${AKLIBS} ${AFSLIBS} ${XLIBS}
@@ -28,6 +28,9 @@ aklog:        ${OBJS} ${AFSLIBS}
 asetkey: asetkey.o ${AFSLIBS}
        ${CC} -o $@ ${CFLAGS} asetkey.o ${AKLIBS} ${AFSLIBS} ${XLIBS}
 
+klog:  klog.o skipwrap.o ${AFSLIBS}
+       ${CC} -o $@ ${CFLAGS} klog.o skipwrap.o ${AKLIBS} ${AFSLIBS} ${TOP_LIBDIR}/libcmd.a ${XLIBS}
+
 #
 # Installation targets
 #
@@ -51,6 +54,6 @@ dest: aklog @ASETKEY@
 # Misc. targets
 #
 clean:
-       $(RM) -f *.o ${OBJS} aklog asetkey
+       $(RM) -f *.o ${OBJS} aklog asetkey klog
 
 include ../config/Makefile.version
diff --git a/src/aklog/add_etbl.c b/src/aklog/add_etbl.c
new file mode 100644 (file)
index 0000000..d862af3
--- /dev/null
@@ -0,0 +1,19 @@
+#include <afsconfig.h>
+#ifndef HAVE_ADD_TO_ERROR_TABLE
+#include <afs/stds.h>
+#include <afs/com_err.h>
+
+/* #define error_table error_table_compat */
+#include <afs/error_table.h>
+/* #undef error_table */
+
+#ifndef HAVE_ADD_ERROR_TABLE
+void add_error_table (const struct error_table *);
+#endif /* !HAVE_ADD_ERROR_TABLE */
+
+void
+add_to_error_table(struct et_list *new_table)
+{
+       add_error_table((struct error_table *) new_table->table);
+}
+#endif /* HAVE_ADD_TO_ERROR_TABLE */
diff --git a/src/aklog/klog.c b/src/aklog/klog.c
new file mode 100644 (file)
index 0000000..67d5a29
--- /dev/null
@@ -0,0 +1,738 @@
+/*
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ * 
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+
+#include <afs/stds.h>
+#include <sys/types.h>
+#include <rx/xdr.h>
+#ifdef AFS_AIX32_ENV
+#include <signal.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+#include <errno.h>
+
+#include <lock.h>
+#include <ubik.h>
+
+#include <stdio.h>
+#include <pwd.h>
+#if 0
+#include <afs/com_err.h>
+#endif
+#include <afs/auth.h>
+#include <afs/afsutil.h>
+#include <afs/cellconfig.h>
+#ifdef AFS_RXK5
+#include "rxk5_utilafs.h"
+#endif
+#include <afs/ptclient.h>
+#include <afs/cmd.h>
+#include <krb5.h>
+
+#ifdef HAVE_KRB5_CREDS_KEYBLOCK
+#define USING_MIT 1
+#endif
+#ifdef HAVE_KRB5_CREDS_SESSION
+#define USING_HEIMDAL 1
+#endif
+
+#ifndef USING_HEIMDAL
+extern krb5_cc_ops krb5_mcc_ops;
+#endif
+
+#include "assert.h"
+
+
+/* This code borrowed heavily from the previous version of log.  Here is the
+   intro comment for that program: */
+
+/*
+       log -- tell the Andrew Cache Manager your password
+       5 June 1985
+       modified
+       February 1986
+
+       Further modified in August 1987 to understand cell IDs.
+
+       Further modified in October 2006 to understand kerberos 5.
+ */
+
+/* Current Usage:
+     klog [principal [password]] [-t] [-c cellname] [-k <k5realm>]
+
+     where:
+       principal is of the form 'name' or 'name@cell' which provides the
+         cellname.  See the -c option below.
+       password is the user's password.  This form is NOT recommended for
+         interactive users.
+       -t advises klog to write a Kerberos style ticket file in /tmp.
+       -c identifies cellname as the cell in which authentication is to take
+         place.
+       -k identifies an alternate kerberos realm to use provide
+         authentication services for the cell.
+ */
+
+#define KLOGEXIT(code) rx_Finalize(); \
+                       (exit(!!code))
+extern int CommandProc(struct cmd_syndesc *as, char *arock);
+
+static int zero_argc;
+static char **zero_argv;
+
+static krb5_context k5context;
+static struct afsconf_dir *tdir;
+static int always_evil = 2;    /* gcc optimizes 0 into bss.  fools. */
+
+int
+main(int argc, char *argv[])
+{
+    struct cmd_syndesc *ts;
+    afs_int32 code;
+#ifdef AFS_AIX32_ENV
+    /*
+     * The following signal action for AIX is necessary so that in case of a 
+     * crash (i.e. core is generated) we can include the user's data section 
+     * in the core dump. Unfortunately, by default, only a partial core is
+     * generated which, in many cases, isn't too useful.
+     */
+    struct sigaction nsa;
+
+    sigemptyset(&nsa.sa_mask);
+    nsa.sa_handler = SIG_DFL;
+    nsa.sa_flags = SA_FULLDUMP;
+    sigaction(SIGABRT, &nsa, NULL);
+    sigaction(SIGSEGV, &nsa, NULL);
+#endif
+    zero_argc = argc;
+    zero_argv = argv;
+
+    ts = cmd_CreateSyntax(NULL, CommandProc, 0,
+                         "obtain Kerberos authentication");
+
+#define aXFLAG 0
+#define aPRINCIPAL 1
+#define aPASSWORD 2
+#define aCELL 3
+#define aKRBREALM 4
+#define aPIPE 5
+#define aSILENT 6
+#define aLIFETIME 7
+#define aSETPAG 8
+#define aTMP 9
+#define aNOPRDB 10
+#define aUNWRAP 11
+#define aK5 12
+#define aK4 13
+
+    cmd_AddParm(ts, "-x", CMD_FLAG, CMD_OPTIONAL|CMD_HIDDEN, 0);
+    cmd_Seek(ts, aPRINCIPAL);
+    cmd_AddParm(ts, "-principal", CMD_SINGLE, CMD_OPTIONAL, "user name");
+    cmd_AddParm(ts, "-password", CMD_SINGLE, CMD_OPTIONAL, "user's password");
+    cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
+    cmd_AddParm(ts, "-k", CMD_SINGLE, CMD_OPTIONAL, "krb5 realm");
+    cmd_AddParm(ts, "-pipe", CMD_FLAG, CMD_OPTIONAL,
+               "read password from stdin");
+    cmd_AddParm(ts, "-silent", CMD_FLAG, CMD_OPTIONAL, "silent operation");
+    cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
+               "ticket lifetime in hh[:mm[:ss]]");
+    cmd_AddParm(ts, "-setpag", CMD_FLAG, CMD_OPTIONAL,
+               "Create a new setpag before authenticating");
+    cmd_AddParm(ts, "-tmp", CMD_FLAG, CMD_OPTIONAL,
+               "write Kerberos-style ticket file in /tmp");
+    cmd_AddParm(ts, "-noprdb", CMD_FLAG, CMD_OPTIONAL, "don't consult pt");
+    cmd_AddParm(ts, "-unwrap", CMD_FLAG, CMD_OPTIONAL, "perform 524d conversion");
+#ifdef AFS_RXK5
+    cmd_AddParm(ts, "-k5", CMD_FLAG, CMD_OPTIONAL, "get rxk5 credentials");
+    cmd_AddParm(ts, "-k4", CMD_FLAG, CMD_OPTIONAL, "get rxkad credentials");
+#else
+    ++ts->nParms;      /* skip -k5 */
+    cmd_AddParm(ts, "-k4", CMD_FLAG, CMD_OPTIONAL|CMD_HIDDEN, 0);
+#endif
+
+    code = cmd_Dispatch(argc, argv);
+    KLOGEXIT(code);
+}
+
+static char *
+getpipepass(void)
+{
+    static char gpbuf[BUFSIZ];
+    /* read a password from stdin, stop on \n or eof */
+    register int i, tc;
+    memset(gpbuf, 0, sizeof(gpbuf));
+    for (i = 0; i < (sizeof(gpbuf) - 1); i++) {
+       tc = fgetc(stdin);
+       if (tc == '\n' || tc == EOF)
+           break;
+       gpbuf[i] = tc;
+    }
+    return gpbuf;
+}
+
+void
+silent_errors(const char *who,
+    afs_int32 code,
+    const char *fmt,
+    va_list ap)
+{
+    /* ignore and don't print error */
+}
+
+#if defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size)
+
+#define get_princ_str(c, p, n) krb5_princ_component(c, p, n)->data
+#define get_princ_len(c, p, n) krb5_princ_component(c, p, n)->length
+#define num_comp(c, p) (krb5_princ_size(c, p))
+#define realm_data(c, p) krb5_princ_realm(c, p)->data
+#define realm_len(c, p) krb5_princ_realm(c, p)->length
+
+#elif defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
+
+#define get_princ_str(c, p, n) krb5_principal_get_comp_string(c, p, n)
+#define get_princ_len(c, p, n) strlen(krb5_principal_get_comp_string(c, p, n))
+#define num_comp(c, p) ((p)->name.name_string.len)
+#define realm_data(c, p) krb5_realm_data(krb5_principal_get_realm(c, p))
+#define realm_len(c, p) krb5_realm_length(krb5_principal_get_realm(c, p))
+
+#else
+#error "Must have either krb5_princ_size or krb5_principal_get_comp_string"
+#endif
+
+#if defined(HAVE_KRB5_CREDS_KEYBLOCK)
+
+#define get_cred_keydata(c) c->keyblock.contents
+#define get_cred_keylen(c) c->keyblock.length
+#define get_creds_enctype(c) c->keyblock.enctype
+
+#elif defined(HAVE_KRB5_CREDS_SESSION)
+
+#define get_cred_keydata(c) c->session.keyvalue.data
+#define get_cred_keylen(c) c->session.keyvalue.length
+#define get_creds_enctype(c) c->session.keytype
+
+#else
+#error "Must have either keyblock or session member of krb5_creds"
+#endif
+
+static int
+whoami(struct ktc_token *atoken,
+    struct afsconf_cell *cellconfig,
+    struct ktc_principal *aclient,
+    int *vicep)
+{
+    int scIndex;
+    int code;
+    int i;
+    struct ubik_client *ptconn = 0;
+    struct rx_securityClass *sc;
+    struct rx_connection *conns[MAXSERVERS+1];
+    idlist lids[1];
+    namelist lnames[1];
+    char tempname[PR_MAXNAMELEN + 1];
+
+    memset(lnames, 0, sizeof *lnames);
+    memset(lids, 0, sizeof *lids);
+    scIndex = 2;
+    sc = rxkad_NewClientSecurityObject(rxkad_auth,
+       &atoken->sessionKey, atoken->kvno,
+       atoken->ticketLen, atoken->ticket);
+    for (i = 0; i < cellconfig->numServers; ++i)
+       conns[i] = rx_NewConnection(cellconfig->hostAddr[i].sin_addr.s_addr,
+               cellconfig->hostAddr[i].sin_port, PRSRV, sc, scIndex);
+    conns[i] = 0;
+    ptconn = 0;
+    if ((code = ubik_ClientInit(conns, &ptconn)))
+       goto Failed;
+    if (*aclient->instance)
+       snprintf (tempname, sizeof tempname, "%s.%s",
+           aclient->name, aclient->instance);
+    else
+       snprintf (tempname, sizeof tempname, "%s", aclient->name);
+    lnames->namelist_len = 1;
+    lnames->namelist_val = (prname *) tempname;
+    code = ubik_PR_NameToID(ptconn, 0, lnames, lids);
+    if (lids->idlist_val) {
+       *vicep = *lids->idlist_val;
+    }
+Failed:
+    if (lids->idlist_val) free(lids->idlist_val);
+    if (ptconn) ubik_ClientDestroy(ptconn);
+    return code;
+}
+
+static void
+k5_to_k4_name(krb5_context k5context,
+    krb5_principal k5princ,
+    struct ktc_principal *ktcprinc)
+{
+    int i;
+
+    switch(num_comp(k5context, k5princ)) {
+       default:
+       /* case 2: */
+           i = get_princ_len(k5context, k5princ, 1);
+           if (i > MAXKTCNAMELEN-1) i = MAXKTCNAMELEN-1;
+           memcpy(ktcprinc->instance, get_princ_str(k5context, k5princ, 1), i);
+           /* fall through */
+       case 1:
+           i = get_princ_len(k5context, k5princ, 0);
+           if (i > MAXKTCNAMELEN-1) i = MAXKTCNAMELEN-1;
+           memcpy(ktcprinc->name, get_princ_str(k5context, k5princ, 0), i);
+           /* fall through */
+       case 0:
+           break;
+       }
+}
+
+/* save and reuse password.  This is necessary to make
+ *  "direct to service" authentication work with most
+ *  flavors of kerberos, when the afs principal has no instance.
+ */
+struct kp_arg {
+    char **pp, *pstore;
+};
+krb5_error_code
+klog_prompter(krb5_context context,
+    void *a,
+    const char *name,
+    const char *banner,
+    int num_prompts,
+    krb5_prompt prompts[])
+{
+    krb5_error_code code;
+    int i, type;
+#ifndef USING_HEIMDAL
+    krb5_prompt_type *types;
+#endif
+    struct kp_arg *kparg = (struct kp_arg *) a;
+    code = krb5_prompter_posix(context, a, name, banner, num_prompts, prompts);
+    if (code) return code;
+#ifndef USING_HEIMDAL
+    if ((types = krb5_get_prompt_types(context)))
+#endif
+    for (i = 0; i < num_prompts; ++i) {
+#ifdef USING_HEIMDAL
+       type = prompts[i].type;
+#else
+       type = types[i];
+#endif
+#if 0
+       printf ("i%d t%d <%.*s>\n", i,
+type,
+prompts[i].reply->length,
+prompts[i].reply->data);
+#endif
+       switch(type) {
+       case KRB5_PROMPT_TYPE_PASSWORD:
+       case KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN:
+           memcpy(kparg->pstore, prompts[i].reply->data, prompts[i].reply->length);
+           kparg->pstore[prompts[i].reply->length] = 0;
+           *kparg->pp = kparg->pstore;
+       }
+    }
+    return 0;
+}
+
+int
+CommandProc(struct cmd_syndesc *as, char *arock)
+{
+    krb5_principal princ = 0;
+    char *cell, *pname, **hrealms, *service;
+    char service_temp[MAXKTCREALMLEN + 20];
+    char realm[MAXKTCREALMLEN];
+    char lrealm[MAXKTCREALMLEN];       /* uppercase copy of local cellname */
+    krb5_creds incred[1], mcred[1], *outcred = 0, *afscred;
+    krb5_ccache cc = 0;
+    krb5_get_init_creds_opt gic_opts[1];
+    char *tofree, *outname;
+    int code;
+    char *what;
+    int i, dosetpag, evil, noprdb, id;
+#ifdef AFS_RXK5
+    int authtype;
+#endif
+    krb5_data enc_part[1];
+    time_t lifetime;           /* requested ticket lifetime */
+    krb5_prompter_fct pf = NULL;
+    char *pass = 0;
+    char *pa = 0;
+    struct kp_arg klog_arg[1];
+
+    char passwd[BUFSIZ];
+    struct afsconf_cell cellconfig[1];
+
+    static char rn[] = "klog"; /*Routine name */
+    static int Pipe = 0;       /* reading from a pipe */
+    static int Silent = 0;     /* Don't want error messages */
+
+    int local;                 /* explicit cell is same a local one */
+    int writeTicketFile = 0;   /* write ticket file to /tmp */
+
+    char *reason;              /* string describing errors */
+
+    service = 0;
+    memset(incred, 0, sizeof *incred);
+    /* blow away command line arguments */
+    for (i = 1; i < zero_argc; i++)
+       memset(zero_argv[i], 0, strlen(zero_argv[i]));
+    zero_argc = 0;
+    memset(klog_arg, 0, sizeof *klog_arg);
+
+    /* first determine quiet flag based on -silent switch */
+    Silent = (as->parms[aSILENT].items ? 1 : 0);
+
+    if (Silent) {
+       set_com_err_hook(silent_errors);
+    }
+
+    if ((code = krb5_init_context(&k5context))) {
+       com_err(rn, code, "while initializing Kerberos 5 library");
+       KLOGEXIT(code);
+    }
+    if ((code = rx_Init(0))) {
+       com_err(rn, code, "while initializing rx");
+       KLOGEXIT(code);
+    }
+    initialize_U_error_table();
+    initialize_krb5_error_table();
+    initialize_RXK_error_table();
+    initialize_KTC_error_table();
+    initialize_ACFG_error_table();
+    /* initialize_rx_error_table(); */
+    if (!(tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))) {
+       com_err(rn, 0, "can't get afs configuration (afsconf_Open(%s))",
+           rn, AFSDIR_CLIENT_ETC_DIRPATH);
+       KLOGEXIT(1);
+    }
+
+    /* Parse remaining arguments. */
+
+    dosetpag = !! as->parms[aSETPAG].items;
+    Pipe = !! as->parms[aPIPE].items;
+    writeTicketFile = !! as->parms[aTMP].items;
+    noprdb = !! as->parms[aNOPRDB].items;
+    evil = (always_evil&1) || !! as->parms[aUNWRAP].items;
+
+#ifdef AFS_RXK5
+    authtype = 0;
+    if (as->parms[aK5].items)
+       authtype |= FORCE_RXK5;
+    if (as->parms[aK4].items)
+       authtype |= FORCE_RXKAD;
+    if (!authtype)
+       authtype |= env_afs_rxk5_default();
+#endif
+
+    cell = as->parms[aCELL].items ? cell = as->parms[aCELL].items->data : 0;
+    if ((code = afsconf_GetCellInfo(tdir, cell, "afsprot", cellconfig))) {
+       if (cell)
+           com_err(rn, code, "Can't get cell information for '%s'", cell);
+       else
+           com_err(rn, code, "Can't get determine local cell!");
+       KLOGEXIT(code);
+    }
+
+    if (as->parms[aKRBREALM].items) {
+       code = krb5_set_default_realm(k5context,
+               (const char *) as->parms[aKRBREALM].items);
+       if (code) {
+           com_err(rn, code, "Can't make <%s> the default realm",
+               as->parms[aKRBREALM].items);
+           KLOGEXIT(code);
+       }
+    }
+    else if ((code = krb5_get_host_realm(k5context, cellconfig->hostName[0], &hrealms))) {
+       com_err(rn, code, "Can't get realm for host <%s> in cell <%s>\n",
+               cellconfig->hostName[0], cellconfig->name);
+       KLOGEXIT(code);
+    } else {
+       if (hrealms && *hrealms) {
+           code = krb5_set_default_realm(k5context,
+                   *hrealms);
+           if (code) {
+               com_err(rn, code, "Can't make <%s> the default realm",
+                   *hrealms);
+               KLOGEXIT(code);
+           }
+       }
+       if (hrealms) krb5_free_host_realm(k5context, hrealms);
+    }
+
+    id = getuid();
+    if (as->parms[aPRINCIPAL].items) {
+       pname = as->parms[aPRINCIPAL].items->data;
+    } else {
+       /* No explicit name provided: use Unix uid. */
+       struct passwd *pw;
+       pw = getpwuid(id);
+       if (pw == 0) {
+           com_err(rn, 0,
+               "Can't figure out your name from your user id (%d).", id);
+           if (!Silent)
+               fprintf(stderr, "%s: Try providing the user name.\n", rn);
+           KLOGEXIT(1);
+       }
+       pname = pw->pw_name;
+    }
+    code = krb5_parse_name(k5context, pname, &princ);
+    if (code) {
+       com_err(rn, code, "Can't parse principal <%s>", pname);
+       KLOGEXIT(code);
+    }
+
+    if (as->parms[aPASSWORD].items) {
+       /*
+        * Current argument is the desired password string.  Remember it in
+        * our local buffer, and zero out the argument string - anyone can
+        * see it there with ps!
+        */
+       strncpy(passwd, as->parms[aPASSWORD].items->data, sizeof(passwd));
+       memset(as->parms[aPASSWORD].items->data, 0,
+              strlen(as->parms[aPASSWORD].items->data));
+       pass = passwd;
+    }
+
+    if (as->parms[aLIFETIME].items) {
+       char *life = as->parms[aLIFETIME].items->data;
+       char *sp;               /* string ptr to rest of life */
+       lifetime = 3600 * strtol(life, &sp, 0); /* hours */
+       if (sp == life) {
+         bad_lifetime:
+           if (!Silent)
+               fprintf(stderr, "%s: translating '%s' to lifetime failed\n",
+                       rn, life);
+           return 1;
+       }
+       if (*sp == ':') {
+           life = sp + 1;      /* skip the colon */
+           lifetime += 60 * strtol(life, &sp, 0);      /* minutes */
+           if (sp == life)
+               goto bad_lifetime;
+           if (*sp == ':') {
+               life = sp + 1;
+               lifetime += strtol(life, &sp, 0);       /* seconds */
+               if (sp == life)
+                   goto bad_lifetime;
+               if (*sp)
+                   goto bad_lifetime;
+           } else if (*sp)
+               goto bad_lifetime;
+       } else if (*sp)
+           goto bad_lifetime;
+    } else
+       lifetime = 0;
+
+    /* Get the password if it wasn't provided. */
+    if (!pass) {
+       if (Pipe) {
+           strncpy(passwd, getpipepass(), sizeof(passwd));
+           pass = passwd;
+       } else {
+           pf = klog_prompter;
+           pa = klog_arg;
+       }
+    }
+
+    service = 0;
+#ifdef AFS_RXK5
+    if (authtype & FORCE_RXK5) {
+       tofree = get_afs_krb5_svc_princ(cellconfig);
+       snprintf(service_temp, sizeof service_temp, "%s", tofree);
+    } else
+#endif
+    snprintf (service_temp, sizeof service_temp, "afs/%s", cellconfig->name);
+    if (writeTicketFile)
+       service = 0;
+    else 
+       service = service_temp;
+
+    klog_arg->pp = &pass;
+    klog_arg->pstore = passwd;
+    /* XXX should allow k5 to prompt in most cases -- what about expired pw?*/
+    krb5_get_init_creds_opt_init(gic_opts);
+    for (;;) {
+       code = krb5_get_init_creds_password(k5context,
+           incred,
+           princ,
+           pass,
+           pf, /* prompter */
+           pa, /* data */
+           0,  /* start_time */
+           service,    /* in_tkt_service */
+           gic_opts);
+       if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || service != service_temp) break;
+#ifdef AFS_RXK5
+       if (authtype & FORCE_RXK5) break;
+#endif
+       service = "afs";
+    }
+    memset(passwd, 0, sizeof(passwd));
+    if (code) {
+       char *r = 0;
+       if (krb5_get_default_realm(k5context, &r))
+           r = 0;
+       if (service)
+           com_err(rn, code, "Unable to authenticate to use %s", service);
+       else if (r)
+           com_err(rn, code, "Unable to authenticate in realm %s", r);
+       else
+           com_err(rn, code, "Unable to authenticate to use cell %s",
+               cellconfig->name);
+       if (r) free(r);
+       KLOGEXIT(code);
+    }
+
+    if (service) {
+       afscred = incred;
+    } else {
+       for (;;writeTicketFile = 0) {
+           if (writeTicketFile) {
+               what = "getting default ccache";
+               code = krb5_cc_default(k5context, &cc);
+           } else {
+               what = "krb5_cc_register";
+               code = krb5_cc_register(k5context, &krb5_mcc_ops, FALSE);
+               if (code && code != KRB5_CC_TYPE_EXISTS) goto Failed;
+               what = "krb5_cc_resolve";
+               code = krb5_cc_resolve(k5context, "MEMORY:core", &cc);
+               if (code) goto Failed;
+           }
+           what = "initializing ccache";
+           code = krb5_cc_initialize(k5context, cc, princ);
+           if (code) goto Failed;
+           what = "writing Kerberos ticket file";
+           code = krb5_cc_store_cred(k5context, cc, incred);
+           if (code) goto Failed;
+           if (writeTicketFile)
+               fprintf(stderr,
+                   "Wrote ticket file to %s\n",
+                   krb5_cc_get_name(k5context, cc));
+           break;
+       Failed:
+           if (code)
+               com_err(rn, code, what);
+           if (writeTicketFile) {
+               if (cc) {
+                   krb5_cc_close(k5context, cc);
+                   cc = 0;
+               }
+               continue;
+           }
+           KLOGEXIT(code);
+       }
+
+       for (service = service_temp;;service = "afs") {
+           memset(mcred, 0, sizeof *mcred);
+           mcred->client = princ;
+           code = krb5_parse_name(k5context, service, &mcred->server);
+           if (code) {
+               com_err(rn, code, "Unable to parse service <%s>\n", service);
+               KLOGEXIT(code);
+           }
+           if (tofree) { free(tofree); tofree = 0; }
+           if (!(code = krb5_unparse_name(k5context, mcred->server, &outname)))
+               tofree = outname;
+           else outname = service;
+           code = krb5_get_credentials(k5context, 0, cc, mcred, &outcred);
+           krb5_free_principal(k5context, mcred->server);
+           if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || service != service_temp) break;
+#ifdef AFS_RXK5
+           if (authtype & FORCE_RXK5) break;
+#endif
+       }
+       afscred = outcred;
+    }
+    if (code) {
+       com_err(rn, code, "Unable to get credentials to use %s", outname);
+       KLOGEXIT(code);
+    }
+
+#ifdef AFS_RXK5
+    if (authtype & FORCE_RXK5) {
+       struct ktc_principal aserver[1];
+       int viceid = 555;
+
+       memset(aserver, 0, sizeof *aserver);
+       strncpy(aserver->cell, cellconfig->name, MAXKTCREALMLEN-1);
+       code = ktc_SetK5Token(k5context, aserver, afscred, viceid, dosetpag);
+       if (code) {
+           com_err(rn, code, "Unable to store tokens for cell %s\n",
+               cellconfig->name);
+           KLOGEXIT(1);
+       }
+    } else
+#endif
+    {
+       struct ktc_principal aserver[1], aclient[1];
+       struct ktc_token atoken[1];
+
+       memset(atoken, 0, sizeof *atoken);
+       if (evil) {
+           atoken->kvno = RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY;
+           if (afs_krb5_skip_ticket_wrapper(afscred->ticket.data,
+                       afscred->ticket.length, &enc_part->data,
+                       &enc_part->length)) {
+               com_err(rn, 0, "Can't unwrap %s AFS credential",
+                   cellconfig->name);
+               KLOGEXIT(1);
+           }
+       } else {
+           atoken->kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
+           *enc_part = afscred->ticket;
+       }
+       atoken->startTime = afscred->times.starttime;
+       atoken->endTime = afscred->times.endtime;
+       memcpy(&atoken->sessionKey, get_cred_keydata(afscred),
+           get_cred_keylen(afscred));
+       memcpy(atoken->ticket, enc_part->data,
+           atoken->ticketLen = enc_part->length);
+       memset(aserver, 0, sizeof *aserver);
+       strncpy(aserver->name, "afs", 4);
+       strncpy(aserver->cell, cellconfig->name, MAXKTCREALMLEN-1);
+       memset(aclient, 0, sizeof *aclient);
+       i = realm_len(k5context, afscred->client);
+       if (i > MAXKTCREALMLEN-1) i = MAXKTCREALMLEN-1;
+       memcpy(aclient->cell, realm_data(k5context, afscred->client), i);
+       if (!noprdb) {
+           int viceid;
+           k5_to_k4_name(k5context, afscred->client, aclient);
+           code = whoami(atoken, cellconfig, aclient, &viceid);
+           if (code) {
+               com_err(rn, code, "Can't get your viceid", cellconfig->name);
+               *aclient->name = 0;
+           } else
+               snprintf(aclient->name, MAXKTCNAMELEN-1, "AFS ID %d", viceid);
+       }
+       if (!*aclient->name)
+           k5_to_k4_name(k5context, afscred->client, aclient);
+       code = ktc_SetToken(aserver, atoken, aclient, dosetpag);
+       if (code) {
+           com_err(rn, code, "Unable to store tokens for cell %s\n",
+               cellconfig->name);
+           KLOGEXIT(1);
+       }
+    }
+
+    krb5_free_principal(k5context, princ);
+    krb5_free_cred_contents(k5context, incred);
+    if (outcred) krb5_free_creds(k5context, outcred);
+    if (cc)
+       krb5_cc_close(k5context, cc);
+    if (tofree) free(tofree);
+
+    return 0;
+}
diff --git a/src/aklog/skipwrap.c b/src/aklog/skipwrap.c
new file mode 100644 (file)
index 0000000..d920bd7
--- /dev/null
@@ -0,0 +1,124 @@
+
+/*
+ * Copyright (c) 2006
+ * The Regents of the University of Michigan
+ * ALL RIGHTS RESERVED
+ *
+ * Permission is granted to use, copy, create derivative works
+ * and redistribute this software and such derivative works
+ * for any purpose, so long as the name of the University of
+ * Michigan is not used in any advertising or publicity
+ * pertaining to the use or distribution of this software
+ * without specific, written prior authorization.  If the
+ * above copyright notice or any other identification of the
+ * University of Michigan is included in any copy of any
+ * portion of this software, then the disclaimer below must
+ * also be included.
+ *
+ * This software is provided as is, without representation
+ * from the University of Michigan as to its fitness for any
+ * purpose, and without warranty by the University of
+ * Michigan of any kind, either express or implied, including
+ * without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose.  The
+ * regents of the University of Michigan shall not be liable
+ * for any damages, including special, indirect, incidental, or
+ * consequential damages, with respect to any claim arising
+ * out of or in connection with the use of the software, even
+ * if it has been or is hereafter advised of the possibility of
+ * such damages.
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+#include <stdio.h>
+#include <aklog.h>
+#include <krb5.h>
+
+/* evil hack */
+#define SEQUENCE 16
+#define CONSTRUCTED 32
+#define APPLICATION 64
+#define CONTEXT_SPECIFIC 128
+static int skip_get_number(char **pp, size_t *lp, int *np)
+{
+    unsigned l;
+    int r, n, i;
+    char *p;
+
+    l = *lp;
+    if (l < 1) {
+#ifdef DEBUG
+       fprintf(stderr, "skip_bad_number: missing number\n");
+#endif
+       return -1;
+    }
+    p = *pp;
+    r = (unsigned char)*p;
+    ++p; --l;
+    if (r & 0x80) {
+       n = (r&0x7f);
+       if (l < n) {
+#ifdef DEBUG
+           fprintf(stderr, "skip_bad_number: truncated number\n");
+#endif
+           return -1;
+       }
+       r = 0;
+       for (i = n; --i >= 0; ) {
+           r <<= 8;
+           r += (unsigned char)*p;
+           ++p; --l;
+       }
+    }
+    *np = r;
+    *pp = p;
+    *lp = l;
+    return 0;
+}
+
+int
+afs_krb5_skip_ticket_wrapper(char *tix, size_t tixlen, char **enc, size_t *enclen)
+{
+    char *p = tix;
+    size_t l = tixlen;
+    int code;
+    int num;
+
+    if (l < 1) return -1;
+    if (*p != (char) (CONSTRUCTED+APPLICATION+1)) return -1;
+    ++p; --l;
+    if ((code = skip_get_number(&p, &l, &num))) return code;
+    if (l != num) return -1;
+    if (l < 1) return -1;
+    if (*p != (char)(CONSTRUCTED+SEQUENCE)) return -1;
+    ++p; --l;
+    if ((code = skip_get_number(&p, &l, &num))) return code;
+    if (l != num) return -1;
+    if (l < 1) return -1;
+    if (*p != (char)(CONSTRUCTED+CONTEXT_SPECIFIC+0)) return -1;
+    ++p; --l;
+    if ((code = skip_get_number(&p, &l, &num))) return code;
+    if (l < num) return -1;
+    l -= num; p += num;
+    if (l < 1) return -1;
+    if (*p != (char)(CONSTRUCTED+CONTEXT_SPECIFIC+1)) return -1;
+    ++p; --l;
+    if ((code = skip_get_number(&p, &l, &num))) return code;
+    if (l < num) return -1;
+    l -= num; p += num;
+    if (l < 1) return -1;
+    if (*p != (char)(CONSTRUCTED+CONTEXT_SPECIFIC+2)) return -1;
+    ++p; --l;
+    if ((code = skip_get_number(&p, &l, &num))) return code;
+    if (l < num) return -1;
+    l -= num; p += num;
+    if (l < 1) return -1;
+    if (*p != (char)(CONSTRUCTED+CONTEXT_SPECIFIC+3)) return -1;
+    ++p; --l;
+    if ((code = skip_get_number(&p, &l, &num))) return code;
+    if (l != num) return -1;
+    *enc = p;
+    *enclen = l;
+    return 0;
+}