klog.krb5: Don't hide the -x option
[openafs.git] / src / aklog / klog.c
index 8120c0f..fd65ee1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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
@@ -9,30 +9,21 @@
 
 #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
-#include <string.h>
-#include <errno.h>
 
+#include <roken.h>
+
+#include <rx/xdr.h>
 #include <lock.h>
 #include <ubik.h>
-
-#include <stdio.h>
-#include <pwd.h>
 #include <afs/com_err.h>
 #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 <afs/ptuser.h>
+
 #include <krb5.h>
 
 #ifdef HAVE_KRB5_CREDS_KEYBLOCK
@@ -42,7 +33,6 @@
 #define USING_HEIMDAL 1
 #endif
 
-#include "assert.h"
 #include "skipwrap.h"
 
 /* This code borrowed heavily from the previous version of log.  Here is the
@@ -92,8 +82,8 @@ main(int argc, char *argv[])
     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 
+     * 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.
      */
@@ -126,7 +116,7 @@ main(int argc, char *argv[])
 #define aK5 12
 #define aK4 13
 
-    cmd_AddParm(ts, "-x", CMD_FLAG, CMD_OPTIONAL|CMD_HIDDEN, 0);
+    cmd_AddParm(ts, "-x", CMD_FLAG, CMD_OPTIONAL, "obsolete, noop");
     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");
@@ -160,7 +150,7 @@ getpipepass(void)
 {
     static char gpbuf[BUFSIZ];
     /* read a password from stdin, stop on \n or eof */
-    register int i, tc;
+    int i, tc;
     memset(gpbuf, 0, sizeof(gpbuf));
     for (i = 0; i < (sizeof(gpbuf) - 1); i++) {
        tc = fgetc(stdin);
@@ -222,43 +212,20 @@ whoami(struct ktc_token *atoken,
     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)))
+    code = pr_Initialize(0, AFSDIR_CLIENT_ETC_DIRPATH, cellconfig->name);
+    if (code)
        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;
-    }
+    code = pr_SNameToId(tempname, vicep);
 Failed:
-    if (lids->idlist_val) free(lids->idlist_val);
-    if (ptconn) ubik_ClientDestroy(ptconn);
     return code;
 }
 
@@ -286,12 +253,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,39 +317,19 @@ klog_prompter(krb5_context context,
     krb5_prompt prompts[])
 {
     krb5_error_code code;
-    int i, type;
-#if !defined(USING_HEIMDAL) && defined(HAVE_KRB5_GET_PROMPT_TYPES)
-    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;
-#if !defined(USING_HEIMDAL) && defined(HAVE_KRB5_GET_PROMPT_TYPES)
-    if ((types = krb5_get_prompt_types(context)))
-#endif
     for (i = 0; i < num_prompts; ++i) {
-#if !defined(USING_HEIMDAL) 
-#if defined(HAVE_KRB5_GET_PROMPT_TYPES)
-       type = types[i];
-#elif defined(HAVE_KRB5_PROMPT_TYPE)   
-       type = prompts[i].type;
-#else
-       /* AIX 5.3 krb5_get_prompt_types is missing. Um... */
-       type = ((i == 1)&&(num_prompts == 2)) ? 
-         KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN : KRB5_PROMPT_TYPE_PASSWORD;
-#endif
-#else
-       type = prompts[i].type;
-#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;
        }
     }
@@ -349,7 +344,11 @@ 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];
+#endif
     char *tofree = NULL, *outname;
     int code;
     char *what;
@@ -397,7 +396,7 @@ CommandProc(struct cmd_syndesc *as, void *arock)
        KLOGEXIT(code);
     }
     initialize_U_error_table();
-    /*initialize_krb5_error_table();*/ 
+    /*initialize_krb5_error_table();*/
     initialize_RXK_error_table();
     initialize_KTC_error_table();
     initialize_ACFG_error_table();
@@ -413,12 +412,12 @@ CommandProc(struct cmd_syndesc *as, void *arock)
      * 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)
+#if defined(HAVE_KRB5_ENCTYPE_ENABLE)
     i = krb5_enctype_valid(k5context, ETYPE_DES_CBC_CRC);
     if (i)
         krb5_enctype_enable(k5context, ETYPE_DES_CBC_CRC);
+#elif defined(HAVE_KRB5_ALLOW_WEAK_CRYPTO)
+    krb5_allow_weak_crypto(k5context, 1);
 #endif
 
     /* Parse remaining arguments. */
@@ -557,39 +556,40 @@ CommandProc(struct cmd_syndesc *as, void *arock)
     } 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;
+    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,
+        code = krb5_get_init_creds_password(k5context,
            incred,
            princ,
            pass,
            pf, /* prompter */
            pa, /* data */
            0,  /* start_time */
-           service,    /* in_tkt_service */
+           0,  /* 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";
+       if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
+            break;
     }
     memset(passwd, 0, sizeof(passwd));
     if (code) {
        char *r = 0;
        if (krb5_get_default_realm(k5context, &r))
            r = 0;
-       if (service)
-           afs_com_err(rn, code, "Unable to authenticate to use %s", service);
-       else if (r)
+       if (r)
            afs_com_err(rn, code, "Unable to authenticate in realm %s", r);
        else
            afs_com_err(rn, code, "Unable to authenticate to use cell %s",
@@ -598,63 +598,61 @@ CommandProc(struct cmd_syndesc *as, void *arock)
        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_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)
-               afs_com_err(rn, code, "%s", what);
-           if (writeTicketFile) {
-               if (cc) {
-                   krb5_cc_close(k5context, cc);
-                   cc = 0;
-               }
-               continue;
-           }
-           KLOGEXIT(code);
-       }
+    for (;;writeTicketFile = 0) {
+        if (writeTicketFile) {
+            what = "getting default ccache";
+            code = krb5_cc_default(k5context, &cc);
+        } else {
+            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)
+            afs_com_err(rn, code, "%s", 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) {
-               afs_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;
+    for (service = service_temp;;service = "afs") {
+        memset(mcred, 0, sizeof *mcred);
+        mcred->client = princ;
+        code = krb5_parse_name(k5context, service, &mcred->server);
+        if (code) {
+            afs_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;
+        if (authtype & FORCE_RXK5)
+            break;
 #endif
-       }
-       afscred = outcred;
     }
+    afscred = outcred;
+
     if (code) {
        afs_com_err(rn, code, "Unable to get credentials to use %s", outname);
        KLOGEXIT(code);
@@ -684,7 +682,7 @@ CommandProc(struct cmd_syndesc *as, void *arock)
            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,
+                       afscred->ticket.length, (char **) &enc_part->data,
                        &elen)) {
                afs_com_err(rn, 0, "Can't unwrap %s AFS credential",
                    cellconfig->name);
@@ -696,8 +694,15 @@ CommandProc(struct cmd_syndesc *as, void *arock)
        }
        atoken->startTime = afscred->times.starttime;
        atoken->endTime = afscred->times.endtime;
-       memcpy(&atoken->sessionKey, get_cred_keydata(afscred),
-           get_cred_keylen(afscred));
+       if (tkt_DeriveDesKey(get_creds_enctype(afscred),
+                            get_cred_keydata(afscred),
+                            get_cred_keylen(afscred), &atoken->sessionKey)) {
+           afs_com_err(rn, 0,
+                       "Cannot derive DES key from enctype %i of length %u",
+                       get_creds_enctype(afscred),
+                       (unsigned)get_cred_keylen(afscred));
+           KLOGEXIT(1);
+       }
        memcpy(atoken->ticket, enc_part->data,
            atoken->ticketLen = enc_part->length);
        memset(aserver, 0, sizeof *aserver);
@@ -708,7 +713,7 @@ 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) {