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