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