aklog: Fix some format warnings
[openafs.git] / src / aklog / klog.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <afs/stds.h>
14 #include <sys/types.h>
15 #include <rx/xdr.h>
16 #ifdef  AFS_AIX32_ENV
17 #include <signal.h>
18 #endif
19 #include <string.h>
20 #include <errno.h>
21
22 #include <lock.h>
23 #include <ubik.h>
24
25 #include <stdio.h>
26 #include <pwd.h>
27 #include <afs/com_err.h>
28 #include <afs/auth.h>
29 #include <afs/afsutil.h>
30 #include <afs/cellconfig.h>
31 #ifdef AFS_RXK5
32 #include "rxk5_utilafs.h"
33 #endif
34 #include <afs/ptclient.h>
35 #include <afs/cmd.h>
36 #include <krb5.h>
37
38 #ifdef HAVE_KRB5_CREDS_KEYBLOCK
39 #define USING_MIT 1
40 #endif
41 #ifdef HAVE_KRB5_CREDS_SESSION
42 #define USING_HEIMDAL 1
43 #endif
44
45 #include "assert.h"
46 #include "skipwrap.h"
47
48 /* This code borrowed heavily from the previous version of log.  Here is the
49    intro comment for that program: */
50
51 /*
52         log -- tell the Andrew Cache Manager your password
53         5 June 1985
54         modified
55         February 1986
56
57         Further modified in August 1987 to understand cell IDs.
58
59         Further modified in October 2006 to understand kerberos 5.
60  */
61
62 /* Current Usage:
63      klog [principal [password]] [-t] [-c cellname] [-k <k5realm>]
64
65      where:
66        principal is of the form 'name' or 'name@cell' which provides the
67           cellname.  See the -c option below.
68        password is the user's password.  This form is NOT recommended for
69           interactive users.
70        -t advises klog to write a Kerberos style ticket file in /tmp.
71        -c identifies cellname as the cell in which authentication is to take
72           place.
73        -k identifies an alternate kerberos realm to use provide
74           authentication services for the cell.
75  */
76
77 #define KLOGEXIT(code) rx_Finalize(); \
78                        (exit(!!code))
79 static int CommandProc(struct cmd_syndesc *as, void *arock);
80
81 static int zero_argc;
82 static char **zero_argv;
83
84 static krb5_context k5context;
85 static struct afsconf_dir *tdir;
86 static int always_evil = 2;     /* gcc optimizes 0 into bss.  fools. */
87
88 int
89 main(int argc, char *argv[])
90 {
91     struct cmd_syndesc *ts;
92     afs_int32 code;
93 #ifdef  AFS_AIX32_ENV
94     /*
95      * The following signal action for AIX is necessary so that in case of a
96      * crash (i.e. core is generated) we can include the user's data section
97      * in the core dump. Unfortunately, by default, only a partial core is
98      * generated which, in many cases, isn't too useful.
99      */
100     struct sigaction nsa;
101
102     sigemptyset(&nsa.sa_mask);
103     nsa.sa_handler = SIG_DFL;
104     nsa.sa_flags = SA_FULLDUMP;
105     sigaction(SIGABRT, &nsa, NULL);
106     sigaction(SIGSEGV, &nsa, NULL);
107 #endif
108     zero_argc = argc;
109     zero_argv = argv;
110
111     ts = cmd_CreateSyntax(NULL, CommandProc, NULL,
112                           "obtain Kerberos authentication");
113
114 #define aXFLAG 0
115 #define aPRINCIPAL 1
116 #define aPASSWORD 2
117 #define aCELL 3
118 #define aKRBREALM 4
119 #define aPIPE 5
120 #define aSILENT 6
121 #define aLIFETIME 7
122 #define aSETPAG 8
123 #define aTMP 9
124 #define aNOPRDB 10
125 #define aUNWRAP 11
126 #define aK5 12
127 #define aK4 13
128
129     cmd_AddParm(ts, "-x", CMD_FLAG, CMD_OPTIONAL|CMD_HIDDEN, 0);
130     cmd_Seek(ts, aPRINCIPAL);
131     cmd_AddParm(ts, "-principal", CMD_SINGLE, CMD_OPTIONAL, "user name");
132     cmd_AddParm(ts, "-password", CMD_SINGLE, CMD_OPTIONAL, "user's password");
133     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
134     cmd_AddParm(ts, "-k", CMD_SINGLE, CMD_OPTIONAL, "krb5 realm");
135     cmd_AddParm(ts, "-pipe", CMD_FLAG, CMD_OPTIONAL,
136                 "read password from stdin");
137     cmd_AddParm(ts, "-silent", CMD_FLAG, CMD_OPTIONAL, "silent operation");
138     cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
139                 "ticket lifetime in hh[:mm[:ss]]");
140     cmd_AddParm(ts, "-setpag", CMD_FLAG, CMD_OPTIONAL,
141                 "Create a new setpag before authenticating");
142     cmd_AddParm(ts, "-tmp", CMD_FLAG, CMD_OPTIONAL,
143                 "write Kerberos-style ticket file in /tmp");
144     cmd_AddParm(ts, "-noprdb", CMD_FLAG, CMD_OPTIONAL, "don't consult pt");
145     cmd_AddParm(ts, "-unwrap", CMD_FLAG, CMD_OPTIONAL, "perform 524d conversion");
146 #ifdef AFS_RXK5
147     cmd_AddParm(ts, "-k5", CMD_FLAG, CMD_OPTIONAL, "get rxk5 credentials");
148     cmd_AddParm(ts, "-k4", CMD_FLAG, CMD_OPTIONAL, "get rxkad credentials");
149 #else
150     ++ts->nParms;       /* skip -k5 */
151     cmd_AddParm(ts, "-k4", CMD_FLAG, CMD_OPTIONAL|CMD_HIDDEN, 0);
152 #endif
153
154     code = cmd_Dispatch(argc, argv);
155     KLOGEXIT(code);
156 }
157
158 static char *
159 getpipepass(void)
160 {
161     static char gpbuf[BUFSIZ];
162     /* read a password from stdin, stop on \n or eof */
163     int i, tc;
164     memset(gpbuf, 0, sizeof(gpbuf));
165     for (i = 0; i < (sizeof(gpbuf) - 1); i++) {
166         tc = fgetc(stdin);
167         if (tc == '\n' || tc == EOF)
168             break;
169         gpbuf[i] = tc;
170     }
171     return gpbuf;
172 }
173
174 void
175 silent_errors(const char *who,
176     afs_int32 code,
177     const char *fmt,
178     va_list ap)
179 {
180     /* ignore and don't print error */
181 }
182
183 #if defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size)
184
185 #define get_princ_str(c, p, n) krb5_princ_component(c, p, n)->data
186 #define get_princ_len(c, p, n) krb5_princ_component(c, p, n)->length
187 #define num_comp(c, p) (krb5_princ_size(c, p))
188 #define realm_data(c, p) krb5_princ_realm(c, p)->data
189 #define realm_len(c, p) krb5_princ_realm(c, p)->length
190
191 #elif defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
192
193 #define get_princ_str(c, p, n) krb5_principal_get_comp_string(c, p, n)
194 #define get_princ_len(c, p, n) strlen(krb5_principal_get_comp_string(c, p, n))
195 #define num_comp(c, p) ((p)->name.name_string.len)
196 #define realm_data(c, p) krb5_realm_data(krb5_principal_get_realm(c, p))
197 #define realm_len(c, p) krb5_realm_length(krb5_principal_get_realm(c, p))
198
199 #else
200 #error "Must have either krb5_princ_size or krb5_principal_get_comp_string"
201 #endif
202
203 #if defined(HAVE_KRB5_CREDS_KEYBLOCK)
204
205 #define get_cred_keydata(c) c->keyblock.contents
206 #define get_cred_keylen(c) c->keyblock.length
207 #define get_creds_enctype(c) c->keyblock.enctype
208
209 #elif defined(HAVE_KRB5_CREDS_SESSION)
210
211 #define get_cred_keydata(c) c->session.keyvalue.data
212 #define get_cred_keylen(c) c->session.keyvalue.length
213 #define get_creds_enctype(c) c->session.keytype
214
215 #else
216 #error "Must have either keyblock or session member of krb5_creds"
217 #endif
218
219 static int
220 whoami(struct ktc_token *atoken,
221     struct afsconf_cell *cellconfig,
222     struct ktc_principal *aclient,
223     int *vicep)
224 {
225     rx_securityIndex scIndex;
226     int code;
227     int i;
228     struct ubik_client *ptconn = 0;
229     struct rx_securityClass *sc;
230     struct rx_connection *conns[MAXSERVERS+1];
231     idlist lids[1];
232     namelist lnames[1];
233     char tempname[PR_MAXNAMELEN + 1];
234
235     memset(lnames, 0, sizeof *lnames);
236     memset(lids, 0, sizeof *lids);
237     scIndex = RX_SECIDX_KAD;
238     sc = rxkad_NewClientSecurityObject(rxkad_auth,
239         &atoken->sessionKey, atoken->kvno,
240         atoken->ticketLen, atoken->ticket);
241     for (i = 0; i < cellconfig->numServers; ++i)
242         conns[i] = rx_NewConnection(cellconfig->hostAddr[i].sin_addr.s_addr,
243                 cellconfig->hostAddr[i].sin_port, PRSRV, sc, scIndex);
244     conns[i] = 0;
245     ptconn = 0;
246     if ((code = ubik_ClientInit(conns, &ptconn)))
247         goto Failed;
248     if (*aclient->instance)
249         snprintf (tempname, sizeof tempname, "%s.%s",
250             aclient->name, aclient->instance);
251     else
252         snprintf (tempname, sizeof tempname, "%s", aclient->name);
253     lnames->namelist_len = 1;
254     lnames->namelist_val = (prname *) tempname;
255     code = ubik_PR_NameToID(ptconn, 0, lnames, lids);
256     if (lids->idlist_val) {
257         *vicep = *lids->idlist_val;
258     }
259 Failed:
260     if (lids->idlist_val) free(lids->idlist_val);
261     if (ptconn) ubik_ClientDestroy(ptconn);
262     return code;
263 }
264
265 static void
266 k5_to_k4_name(krb5_context k5context,
267     krb5_principal k5princ,
268     struct ktc_principal *ktcprinc)
269 {
270     int i;
271
272     switch(num_comp(k5context, k5princ)) {
273         default:
274         /* case 2: */
275             i = get_princ_len(k5context, k5princ, 1);
276             if (i > MAXKTCNAMELEN-1) i = MAXKTCNAMELEN-1;
277             memcpy(ktcprinc->instance, get_princ_str(k5context, k5princ, 1), i);
278             /* fall through */
279         case 1:
280             i = get_princ_len(k5context, k5princ, 0);
281             if (i > MAXKTCNAMELEN-1) i = MAXKTCNAMELEN-1;
282             memcpy(ktcprinc->name, get_princ_str(k5context, k5princ, 0), i);
283             /* fall through */
284         case 0:
285             break;
286         }
287 }
288
289 #if defined(USING_HEIMDAL) || defined(HAVE_KRB5_PROMPT_TYPE)
290 static int
291 klog_is_pass_prompt(int index, krb5_context context, krb5_prompt prompts[])
292 {
293     switch (prompts[index].type) {
294     case KRB5_PROMPT_TYPE_PASSWORD:
295     case KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN:
296         return 1;
297     default:
298         return 0;
299     }
300 }
301 #elif defined(HAVE_KRB5_GET_PROMPT_TYPES)
302 static int
303 klog_is_pass_prompt(int index, krb5_context context, krb5_prompt prompts[])
304 {
305     /* this isn't thread-safe or anything obviously; it just should be good
306      * enough to work with klog */
307     static krb5_prompt_type *types = NULL;
308     if (index == 0) {
309         types = NULL;
310     }
311     if (!types) {
312         types = krb5_get_prompt_types(context);
313     }
314     if (!types) {
315         return 0;
316     }
317     switch (types[index]) {
318     case KRB5_PROMPT_TYPE_PASSWORD:
319     case KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN:
320         return 1;
321     default:
322         return 0;
323     }
324 }
325 #else
326 static int
327 klog_is_pass_prompt(int index, krb5_context context, krb5_prompt prompts[])
328 {
329     /* AIX 5.3 doesn't have krb5_get_prompt_types. Neither does HP-UX, which
330      * also doesn't even define KRB5_PROMPT_TYPE_PASSWORD &co. We have no way
331      * of determining the the prompt type, so just assume it's a password */
332     return 1;
333 }
334 #endif
335
336 /* save and reuse password.  This is necessary to make
337  *  "direct to service" authentication work with most
338  *  flavors of kerberos, when the afs principal has no instance.
339  */
340 struct kp_arg {
341     char **pp, *pstore;
342     size_t allocated;
343 };
344 krb5_error_code
345 klog_prompter(krb5_context context,
346     void *a,
347     const char *name,
348     const char *banner,
349     int num_prompts,
350     krb5_prompt prompts[])
351 {
352     krb5_error_code code;
353     int i;
354     struct kp_arg *kparg = (struct kp_arg *) a;
355     size_t length;
356
357     code = krb5_prompter_posix(context, a, name, banner, num_prompts, prompts);
358     if (code) return code;
359     for (i = 0; i < num_prompts; ++i) {
360         if (klog_is_pass_prompt(i, context, prompts)) {
361             length = prompts[i].reply->length;
362             if (length > kparg->allocated - 1)
363                 length = kparg->allocated - 1;
364             memcpy(kparg->pstore, prompts[i].reply->data, length);
365             kparg->pstore[length] = 0;
366             *kparg->pp = kparg->pstore;
367         }
368     }
369     return 0;
370 }
371
372 static int
373 CommandProc(struct cmd_syndesc *as, void *arock)
374 {
375     krb5_principal princ = 0;
376     char *cell, *pname, **hrealms, *service;
377     char service_temp[MAXKTCREALMLEN + 20];
378     krb5_creds incred[1], mcred[1], *outcred = 0, *afscred;
379     krb5_ccache cc = 0;
380 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
381     krb5_get_init_creds_opt *gic_opts;
382 #else
383     krb5_get_init_creds_opt gic_opts[1];
384 #endif
385     char *tofree = NULL, *outname;
386     int code;
387     char *what;
388     int i, dosetpag, evil, noprdb, id;
389 #ifdef AFS_RXK5
390     int authtype;
391 #endif
392     krb5_data enc_part[1];
393     time_t lifetime;            /* requested ticket lifetime */
394     krb5_prompter_fct pf = NULL;
395     char *pass = 0;
396     void *pa = 0;
397     struct kp_arg klog_arg[1];
398
399     char passwd[BUFSIZ];
400     struct afsconf_cell cellconfig[1];
401
402     static char rn[] = "klog";  /*Routine name */
403     static int Pipe = 0;        /* reading from a pipe */
404     static int Silent = 0;      /* Don't want error messages */
405
406     int writeTicketFile = 0;    /* write ticket file to /tmp */
407
408     service = 0;
409     memset(incred, 0, sizeof *incred);
410     /* blow away command line arguments */
411     for (i = 1; i < zero_argc; i++)
412         memset(zero_argv[i], 0, strlen(zero_argv[i]));
413     zero_argc = 0;
414     memset(klog_arg, 0, sizeof *klog_arg);
415
416     /* first determine quiet flag based on -silent switch */
417     Silent = (as->parms[aSILENT].items ? 1 : 0);
418
419     if (Silent) {
420         afs_set_com_err_hook(silent_errors);
421     }
422
423     if ((code = krb5_init_context(&k5context))) {
424         afs_com_err(rn, code, "while initializing Kerberos 5 library");
425         KLOGEXIT(code);
426     }
427     if ((code = rx_Init(0))) {
428         afs_com_err(rn, code, "while initializing rx");
429         KLOGEXIT(code);
430     }
431     initialize_U_error_table();
432     /*initialize_krb5_error_table();*/
433     initialize_RXK_error_table();
434     initialize_KTC_error_table();
435     initialize_ACFG_error_table();
436     /* initialize_rx_error_table(); */
437     if (!(tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))) {
438         afs_com_err(rn, 0, "can't get afs configuration (afsconf_Open(%s))",
439             AFSDIR_CLIENT_ETC_DIRPATH);
440         KLOGEXIT(1);
441     }
442
443     /*
444      * Enable DES enctypes, which are currently still required for AFS.
445      * krb5_allow_weak_crypto is MIT Kerberos 1.8.  krb5_enctype_enable is
446      * Heimdal.
447      */
448 #if defined(HAVE_KRB5_ENCTYPE_ENABLE)
449     i = krb5_enctype_valid(k5context, ETYPE_DES_CBC_CRC);
450     if (i)
451         krb5_enctype_enable(k5context, ETYPE_DES_CBC_CRC);
452 #elif defined(HAVE_KRB5_ALLOW_WEAK_CRYPTO)
453     krb5_allow_weak_crypto(k5context, 1);
454 #endif
455
456     /* Parse remaining arguments. */
457
458     dosetpag = !! as->parms[aSETPAG].items;
459     Pipe = !! as->parms[aPIPE].items;
460     writeTicketFile = !! as->parms[aTMP].items;
461     noprdb = !! as->parms[aNOPRDB].items;
462     evil = (always_evil&1) || !! as->parms[aUNWRAP].items;
463
464 #ifdef AFS_RXK5
465     authtype = 0;
466     if (as->parms[aK5].items)
467         authtype |= FORCE_RXK5;
468     if (as->parms[aK4].items)
469         authtype |= FORCE_RXKAD;
470     if (!authtype)
471         authtype |= env_afs_rxk5_default();
472 #endif
473
474     cell = as->parms[aCELL].items ? as->parms[aCELL].items->data : 0;
475     if ((code = afsconf_GetCellInfo(tdir, cell, "afsprot", cellconfig))) {
476         if (cell)
477             afs_com_err(rn, code, "Can't get cell information for '%s'", cell);
478         else
479             afs_com_err(rn, code, "Can't get determine local cell!");
480         KLOGEXIT(code);
481     }
482
483     if (as->parms[aKRBREALM].items) {
484         code = krb5_set_default_realm(k5context,
485                 as->parms[aKRBREALM].items->data);
486         if (code) {
487             afs_com_err(rn, code, "Can't make <%s> the default realm",
488                 as->parms[aKRBREALM].items->data);
489             KLOGEXIT(code);
490         }
491     }
492     else if ((code = krb5_get_host_realm(k5context, cellconfig->hostName[0], &hrealms))) {
493         afs_com_err(rn, code, "Can't get realm for host <%s> in cell <%s>\n",
494                 cellconfig->hostName[0], cellconfig->name);
495         KLOGEXIT(code);
496     } else {
497         if (hrealms && *hrealms) {
498             code = krb5_set_default_realm(k5context,
499                     *hrealms);
500             if (code) {
501                 afs_com_err(rn, code, "Can't make <%s> the default realm",
502                     *hrealms);
503                 KLOGEXIT(code);
504             }
505         }
506         if (hrealms) krb5_free_host_realm(k5context, hrealms);
507     }
508
509     id = getuid();
510     if (as->parms[aPRINCIPAL].items) {
511         pname = as->parms[aPRINCIPAL].items->data;
512     } else {
513         /* No explicit name provided: use Unix uid. */
514         struct passwd *pw;
515         pw = getpwuid(id);
516         if (pw == 0) {
517             afs_com_err(rn, 0,
518                 "Can't figure out your name from your user id (%d).", id);
519             if (!Silent)
520                 fprintf(stderr, "%s: Try providing the user name.\n", rn);
521             KLOGEXIT(1);
522         }
523         pname = pw->pw_name;
524     }
525     code = krb5_parse_name(k5context, pname, &princ);
526     if (code) {
527         afs_com_err(rn, code, "Can't parse principal <%s>", pname);
528         KLOGEXIT(code);
529     }
530
531     if (as->parms[aPASSWORD].items) {
532         /*
533          * Current argument is the desired password string.  Remember it in
534          * our local buffer, and zero out the argument string - anyone can
535          * see it there with ps!
536          */
537         strncpy(passwd, as->parms[aPASSWORD].items->data, sizeof(passwd));
538         memset(as->parms[aPASSWORD].items->data, 0,
539                strlen(as->parms[aPASSWORD].items->data));
540         pass = passwd;
541     }
542
543     if (as->parms[aLIFETIME].items) {
544         char *life = as->parms[aLIFETIME].items->data;
545         char *sp;               /* string ptr to rest of life */
546         lifetime = 3600 * strtol(life, &sp, 0); /* hours */
547         if (sp == life) {
548           bad_lifetime:
549             if (!Silent)
550                 fprintf(stderr, "%s: translating '%s' to lifetime failed\n",
551                         rn, life);
552             return 1;
553         }
554         if (*sp == ':') {
555             life = sp + 1;      /* skip the colon */
556             lifetime += 60 * strtol(life, &sp, 0);      /* minutes */
557             if (sp == life)
558                 goto bad_lifetime;
559             if (*sp == ':') {
560                 life = sp + 1;
561                 lifetime += strtol(life, &sp, 0);       /* seconds */
562                 if (sp == life)
563                     goto bad_lifetime;
564                 if (*sp)
565                     goto bad_lifetime;
566             } else if (*sp)
567                 goto bad_lifetime;
568         } else if (*sp)
569             goto bad_lifetime;
570     } else
571         lifetime = 0;
572
573     /* Get the password if it wasn't provided. */
574     if (!pass) {
575         if (Pipe) {
576             strncpy(passwd, getpipepass(), sizeof(passwd));
577             pass = passwd;
578         } else {
579             pf = klog_prompter;
580             pa = klog_arg;
581         }
582     }
583
584     service = 0;
585 #ifdef AFS_RXK5
586     if (authtype & FORCE_RXK5) {
587         tofree = get_afs_krb5_svc_princ(cellconfig);
588         snprintf(service_temp, sizeof service_temp, "%s", tofree);
589     } else
590 #endif
591     snprintf (service_temp, sizeof service_temp, "afs/%s", cellconfig->name);
592     if (writeTicketFile)
593         service = 0;
594     else
595         service = service_temp;
596
597     klog_arg->pp = &pass;
598     klog_arg->pstore = passwd;
599     klog_arg->allocated = sizeof(passwd);
600     /* XXX should allow k5 to prompt in most cases -- what about expired pw?*/
601 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
602     code = krb5_get_init_creds_opt_alloc(k5context, &gic_opts);
603     if (code) {
604         afs_com_err(rn, code, "Can't allocate get_init_creds options");
605         KLOGEXIT(code);
606     }
607 #else
608     krb5_get_init_creds_opt_init(gic_opts);
609 #endif
610     for (;;) {
611         code = krb5_get_init_creds_password(k5context,
612             incred,
613             princ,
614             pass,
615             pf, /* prompter */
616             pa, /* data */
617             0,  /* start_time */
618             service,    /* in_tkt_service */
619             gic_opts);
620         if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || service != service_temp) break;
621 #ifdef AFS_RXK5
622         if (authtype & FORCE_RXK5) break;
623 #endif
624         service = "afs";
625     }
626     memset(passwd, 0, sizeof(passwd));
627     if (code) {
628         char *r = 0;
629         if (krb5_get_default_realm(k5context, &r))
630             r = 0;
631         if (service)
632             afs_com_err(rn, code, "Unable to authenticate to use %s", service);
633         else if (r)
634             afs_com_err(rn, code, "Unable to authenticate in realm %s", r);
635         else
636             afs_com_err(rn, code, "Unable to authenticate to use cell %s",
637                 cellconfig->name);
638         if (r) free(r);
639         KLOGEXIT(code);
640     }
641
642     if (service) {
643         afscred = incred;
644     } else {
645         for (;;writeTicketFile = 0) {
646             if (writeTicketFile) {
647                 what = "getting default ccache";
648                 code = krb5_cc_default(k5context, &cc);
649             } else {
650                 what = "krb5_cc_resolve";
651                 code = krb5_cc_resolve(k5context, "MEMORY:core", &cc);
652                 if (code) goto Failed;
653             }
654             what = "initializing ccache";
655             code = krb5_cc_initialize(k5context, cc, princ);
656             if (code) goto Failed;
657             what = "writing Kerberos ticket file";
658             code = krb5_cc_store_cred(k5context, cc, incred);
659             if (code) goto Failed;
660             if (writeTicketFile)
661                 fprintf(stderr,
662                     "Wrote ticket file to %s\n",
663                     krb5_cc_get_name(k5context, cc));
664             break;
665         Failed:
666             if (code)
667                 afs_com_err(rn, code, "%s", what);
668             if (writeTicketFile) {
669                 if (cc) {
670                     krb5_cc_close(k5context, cc);
671                     cc = 0;
672                 }
673                 continue;
674             }
675             KLOGEXIT(code);
676         }
677
678         for (service = service_temp;;service = "afs") {
679             memset(mcred, 0, sizeof *mcred);
680             mcred->client = princ;
681             code = krb5_parse_name(k5context, service, &mcred->server);
682             if (code) {
683                 afs_com_err(rn, code, "Unable to parse service <%s>\n", service);
684                 KLOGEXIT(code);
685             }
686             if (tofree) { free(tofree); tofree = 0; }
687             if (!(code = krb5_unparse_name(k5context, mcred->server, &outname)))
688                 tofree = outname;
689             else outname = service;
690             code = krb5_get_credentials(k5context, 0, cc, mcred, &outcred);
691             krb5_free_principal(k5context, mcred->server);
692             if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || service != service_temp) break;
693 #ifdef AFS_RXK5
694             if (authtype & FORCE_RXK5) break;
695 #endif
696         }
697         afscred = outcred;
698     }
699     if (code) {
700         afs_com_err(rn, code, "Unable to get credentials to use %s", outname);
701         KLOGEXIT(code);
702     }
703
704 #ifdef AFS_RXK5
705     if (authtype & FORCE_RXK5) {
706         struct ktc_principal aserver[1];
707         int viceid = 555;
708
709         memset(aserver, 0, sizeof *aserver);
710         strncpy(aserver->cell, cellconfig->name, MAXKTCREALMLEN-1);
711         code = ktc_SetK5Token(k5context, aserver, afscred, viceid, dosetpag);
712         if (code) {
713             afs_com_err(rn, code, "Unable to store tokens for cell %s\n",
714                 cellconfig->name);
715             KLOGEXIT(1);
716         }
717     } else
718 #endif
719     {
720         struct ktc_principal aserver[1], aclient[1];
721         struct ktc_token atoken[1];
722
723         memset(atoken, 0, sizeof *atoken);
724         if (evil) {
725             size_t elen = enc_part->length;
726             atoken->kvno = RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY;
727             if (afs_krb5_skip_ticket_wrapper(afscred->ticket.data,
728                         afscred->ticket.length, (char **) &enc_part->data,
729                         &elen)) {
730                 afs_com_err(rn, 0, "Can't unwrap %s AFS credential",
731                     cellconfig->name);
732                 KLOGEXIT(1);
733             }
734         } else {
735             atoken->kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
736             *enc_part = afscred->ticket;
737         }
738         atoken->startTime = afscred->times.starttime;
739         atoken->endTime = afscred->times.endtime;
740         memcpy(&atoken->sessionKey, get_cred_keydata(afscred),
741             get_cred_keylen(afscred));
742         memcpy(atoken->ticket, enc_part->data,
743             atoken->ticketLen = enc_part->length);
744         memset(aserver, 0, sizeof *aserver);
745         strncpy(aserver->name, "afs", 4);
746         strncpy(aserver->cell, cellconfig->name, MAXKTCREALMLEN-1);
747         memset(aclient, 0, sizeof *aclient);
748         i = realm_len(k5context, afscred->client);
749         if (i > MAXKTCREALMLEN-1) i = MAXKTCREALMLEN-1;
750         memcpy(aclient->cell, realm_data(k5context, afscred->client), i);
751         if (!noprdb) {
752             int viceid = 0;
753             k5_to_k4_name(k5context, afscred->client, aclient);
754             code = whoami(atoken, cellconfig, aclient, &viceid);
755             if (code) {
756                 afs_com_err(rn, code, "Can't get your viceid for cell %s", cellconfig->name);
757                 *aclient->name = 0;
758             } else
759                 snprintf(aclient->name, MAXKTCNAMELEN-1, "AFS ID %d", viceid);
760         }
761         if (!*aclient->name)
762             k5_to_k4_name(k5context, afscred->client, aclient);
763         code = ktc_SetToken(aserver, atoken, aclient, dosetpag);
764         if (code) {
765             afs_com_err(rn, code, "Unable to store tokens for cell %s\n",
766                 cellconfig->name);
767             KLOGEXIT(1);
768         }
769     }
770
771     krb5_free_principal(k5context, princ);
772     krb5_free_cred_contents(k5context, incred);
773     if (outcred) krb5_free_creds(k5context, outcred);
774     if (cc)
775         krb5_cc_close(k5context, cc);
776     if (tofree) free(tofree);
777
778     return 0;
779 }