klog: refactor klog_prompter
[openafs.git] / src / aklog / klog.c
index aed0e13..fa037d6 100644 (file)
@@ -222,7 +222,7 @@ whoami(struct ktc_token *atoken,
     struct ktc_principal *aclient,
     int *vicep)
 {
-    int scIndex;
+    rx_securityIndex scIndex;
     int code;
     int i;
     struct ubik_client *ptconn = 0;
@@ -234,7 +234,7 @@ whoami(struct ktc_token *atoken,
 
     memset(lnames, 0, sizeof *lnames);
     memset(lids, 0, sizeof *lids);
-    scIndex = 2;
+    scIndex = RX_SECIDX_KAD;
     sc = rxkad_NewClientSecurityObject(rxkad_auth,
        &atoken->sessionKey, atoken->kvno,
        atoken->ticketLen, atoken->ticket);
@@ -286,12 +286,60 @@ k5_to_k4_name(krb5_context k5context,
        }
 }
 
+#if defined(USING_HEIMDAL) || defined(HAVE_KRB5_PROMPT_TYPE)
+static int
+klog_is_pass_prompt(int index, krb5_context context, krb5_prompt prompts[])
+{
+    switch (prompts[index].type) {
+    case KRB5_PROMPT_TYPE_PASSWORD:
+    case KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN:
+       return 1;
+    default:
+       return 0;
+    }
+}
+#elif defined(HAVE_KRB5_GET_PROMPT_TYPES)
+static int
+klog_is_pass_prompt(int index, krb5_context context, krb5_prompt prompts[])
+{
+    /* this isn't thread-safe or anything obviously; it just should be good
+     * enough to work with klog */
+    static krb5_prompt_type *types = NULL;
+    if (index == 0) {
+       types = NULL;
+    }
+    if (!types) {
+       types = krb5_get_prompt_types(context);
+    }
+    if (!types) {
+       return 0;
+    }
+    switch (types[index]) {
+    case KRB5_PROMPT_TYPE_PASSWORD:
+    case KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN:
+       return 1;
+    default:
+       return 0;
+    }
+}
+#else
+static int
+klog_is_pass_prompt(int index, krb5_context context, krb5_prompt prompts[])
+{
+    /* AIX 5.3 doesn't have krb5_get_prompt_types. Neither does HP-UX, which
+     * also doesn't even define KRB5_PROMPT_TYPE_PASSWORD &co. We have no way
+     * of determining the the prompt type, so just assume it's a password */
+    return 1;
+}
+#endif
+
 /* 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;
+    size_t allocated;
 };
 krb5_error_code
 klog_prompter(krb5_context context,
@@ -302,33 +350,19 @@ klog_prompter(krb5_context context,
     krb5_prompt prompts[])
 {
     krb5_error_code code;
-    int i, type;
-#ifndef USING_HEIMDAL
-    krb5_prompt_type *types;
-#endif
+    int i;
     struct kp_arg *kparg = (struct kp_arg *) a;
+    size_t length;
+
     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;
+       if (klog_is_pass_prompt(i, context, prompts)) {
+           length = prompts[i].reply->length;
+           if (length > kparg->allocated - 1)
+               length = kparg->allocated - 1;
+           memcpy(kparg->pstore, prompts[i].reply->data, length);
+           kparg->pstore[length] = 0;
            *kparg->pp = kparg->pstore;
        }
     }
@@ -343,8 +377,12 @@ CommandProc(struct cmd_syndesc *as, void *arock)
     char service_temp[MAXKTCREALMLEN + 20];
     krb5_creds incred[1], mcred[1], *outcred = 0, *afscred;
     krb5_ccache cc = 0;
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
+    krb5_get_init_creds_opt *gic_opts;
+#else
     krb5_get_init_creds_opt gic_opts[1];
-    char *tofree, *outname;
+#endif
+    char *tofree = NULL, *outname;
     int code;
     char *what;
     int i, dosetpag, evil, noprdb, id;
@@ -398,10 +436,23 @@ CommandProc(struct cmd_syndesc *as, void *arock)
     /* initialize_rx_error_table(); */
     if (!(tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))) {
        afs_com_err(rn, 0, "can't get afs configuration (afsconf_Open(%s))",
-           rn, AFSDIR_CLIENT_ETC_DIRPATH);
+           AFSDIR_CLIENT_ETC_DIRPATH);
        KLOGEXIT(1);
     }
 
+    /*
+     * Enable DES enctypes, which are currently still required for AFS.
+     * krb5_allow_weak_crypto is MIT Kerberos 1.8.  krb5_enctype_enable is
+     * Heimdal.
+     */
+#if defined(HAVE_KRB5_ALLOW_WEAK_CRYPTO)
+    krb5_allow_weak_crypto(k5context, 1);
+#elif defined(HAVE_KRB5_ENCTYPE_ENABLE)
+    i = krb5_enctype_valid(k5context, ETYPE_DES_CBC_CRC);
+    if (i)
+        krb5_enctype_enable(k5context, ETYPE_DES_CBC_CRC);
+#endif
+
     /* Parse remaining arguments. */
 
     dosetpag = !! as->parms[aSETPAG].items;
@@ -431,10 +482,10 @@ CommandProc(struct cmd_syndesc *as, void *arock)
 
     if (as->parms[aKRBREALM].items) {
        code = krb5_set_default_realm(k5context,
-               (const char *) as->parms[aKRBREALM].items);
+               as->parms[aKRBREALM].items->data);
        if (code) {
            afs_com_err(rn, code, "Can't make <%s> the default realm",
-               as->parms[aKRBREALM].items);
+               as->parms[aKRBREALM].items->data);
            KLOGEXIT(code);
        }
     }
@@ -545,8 +596,17 @@ CommandProc(struct cmd_syndesc *as, void *arock)
 
     klog_arg->pp = &pass;
     klog_arg->pstore = passwd;
+    klog_arg->allocated = sizeof(passwd);
     /* XXX should allow k5 to prompt in most cases -- what about expired pw?*/
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
+    code = krb5_get_init_creds_opt_alloc(k5context, &gic_opts);
+    if (code) {
+       afs_com_err(rn, code, "Can't allocate get_init_creds options");
+       KLOGEXIT(code);
+    }
+#else
     krb5_get_init_creds_opt_init(gic_opts);
+#endif
     for (;;) {
        code = krb5_get_init_creds_password(k5context,
            incred,
@@ -604,7 +664,7 @@ CommandProc(struct cmd_syndesc *as, void *arock)
            break;
        Failed:
            if (code)
-               afs_com_err(rn, code, what);
+               afs_com_err(rn, code, "%s", what);
            if (writeTicketFile) {
                if (cc) {
                    krb5_cc_close(k5context, cc);
@@ -662,10 +722,11 @@ CommandProc(struct cmd_syndesc *as, void *arock)
 
        memset(atoken, 0, sizeof *atoken);
        if (evil) {
+           size_t elen = enc_part->length;
            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)) {
+                       afscred->ticket.length, (char **) &enc_part->data,
+                       &elen)) {
                afs_com_err(rn, 0, "Can't unwrap %s AFS credential",
                    cellconfig->name);
                KLOGEXIT(1);
@@ -688,11 +749,11 @@ CommandProc(struct cmd_syndesc *as, void *arock)
        if (i > MAXKTCREALMLEN-1) i = MAXKTCREALMLEN-1;
        memcpy(aclient->cell, realm_data(k5context, afscred->client), i);
        if (!noprdb) {
-           int viceid;
+           int viceid = 0;
            k5_to_k4_name(k5context, afscred->client, aclient);
            code = whoami(atoken, cellconfig, aclient, &viceid);
            if (code) {
-               afs_com_err(rn, code, "Can't get your viceid", cellconfig->name);
+               afs_com_err(rn, code, "Can't get your viceid for cell %s", cellconfig->name);
                *aclient->name = 0;
            } else
                snprintf(aclient->name, MAXKTCNAMELEN-1, "AFS ID %d", viceid);