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