Avoid format truncation warnings
[openafs.git] / src / aklog / klog.c
index b48dd32..26e14c9 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,22 @@
 
 #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>
+
+#define KERBEROS_APPLE_DEPRECATED(x)
 #include <krb5.h>
 
 #ifdef HAVE_KRB5_CREDS_KEYBLOCK
@@ -42,7 +34,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 +83,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.
      */
@@ -108,7 +99,7 @@ main(int argc, char *argv[])
     zero_argc = argc;
     zero_argv = argv;
 
-    ts = cmd_CreateSyntax(NULL, CommandProc, NULL,
+    ts = cmd_CreateSyntax(NULL, CommandProc, NULL, 0,
                          "obtain Kerberos authentication");
 
 #define aXFLAG 0
@@ -126,7 +117,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");
@@ -135,6 +126,7 @@ main(int argc, char *argv[])
     cmd_AddParm(ts, "-pipe", CMD_FLAG, CMD_OPTIONAL,
                "read password from stdin");
     cmd_AddParm(ts, "-silent", CMD_FLAG, CMD_OPTIONAL, "silent operation");
+    /* Note: -lifetime is not implemented in this version of klog. */
     cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
                "ticket lifetime in hh[:mm[:ss]]");
     cmd_AddParm(ts, "-setpag", CMD_FLAG, CMD_OPTIONAL,
@@ -160,7 +152,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 +214,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)))
+    char tempname[2*PR_MAXNAMELEN];
+
+    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 +255,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 +319,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 +346,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;
@@ -358,7 +359,6 @@ CommandProc(struct cmd_syndesc *as, void *arock)
     int authtype;
 #endif
     krb5_data enc_part[1];
-    time_t lifetime;           /* requested ticket lifetime */
     krb5_prompter_fct pf = NULL;
     char *pass = 0;
     void *pa = 0;
@@ -397,17 +397,30 @@ 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();
     /* 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_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. */
 
     dosetpag = !! as->parms[aSETPAG].items;
@@ -437,10 +450,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);
        }
     }
@@ -495,36 +508,6 @@ CommandProc(struct cmd_syndesc *as, void *arock)
        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) {
@@ -544,39 +527,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",
@@ -585,63 +569,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, 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);
@@ -668,10 +650,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);
@@ -682,8 +665,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);
@@ -694,11 +684,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);