Import Upstream version 1.8.5
[hcoop/debian/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 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
130 "ticket lifetime in hh[:mm[:ss]]");
131 cmd_AddParm(ts, "-setpag", CMD_FLAG, CMD_OPTIONAL,
132 "Create a new setpag before authenticating");
133 cmd_AddParm(ts, "-tmp", CMD_FLAG, CMD_OPTIONAL,
134 "write Kerberos-style ticket file in /tmp");
135 cmd_AddParm(ts, "-noprdb", CMD_FLAG, CMD_OPTIONAL, "don't consult pt");
136 cmd_AddParm(ts, "-unwrap", CMD_FLAG, CMD_OPTIONAL, "perform 524d conversion");
137 #ifdef AFS_RXK5
138 cmd_AddParm(ts, "-k5", CMD_FLAG, CMD_OPTIONAL, "get rxk5 credentials");
139 cmd_AddParm(ts, "-k4", CMD_FLAG, CMD_OPTIONAL, "get rxkad credentials");
140 #else
141 ++ts->nParms; /* skip -k5 */
142 cmd_AddParm(ts, "-k4", CMD_FLAG, CMD_OPTIONAL|CMD_HIDDEN, 0);
143 #endif
144
145 code = cmd_Dispatch(argc, argv);
146 KLOGEXIT(code);
147 }
148
149 static char *
150 getpipepass(void)
151 {
152 static char gpbuf[BUFSIZ];
153 /* read a password from stdin, stop on \n or eof */
154 int i, tc;
155 memset(gpbuf, 0, sizeof(gpbuf));
156 for (i = 0; i < (sizeof(gpbuf) - 1); i++) {
157 tc = fgetc(stdin);
158 if (tc == '\n' || tc == EOF)
159 break;
160 gpbuf[i] = tc;
161 }
162 return gpbuf;
163 }
164
165 void
166 silent_errors(const char *who,
167 afs_int32 code,
168 const char *fmt,
169 va_list ap)
170 {
171 /* ignore and don't print error */
172 }
173
174 #if defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size)
175
176 #define get_princ_str(c, p, n) krb5_princ_component(c, p, n)->data
177 #define get_princ_len(c, p, n) krb5_princ_component(c, p, n)->length
178 #define num_comp(c, p) (krb5_princ_size(c, p))
179 #define realm_data(c, p) krb5_princ_realm(c, p)->data
180 #define realm_len(c, p) krb5_princ_realm(c, p)->length
181
182 #elif defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
183
184 #define get_princ_str(c, p, n) krb5_principal_get_comp_string(c, p, n)
185 #define get_princ_len(c, p, n) strlen(krb5_principal_get_comp_string(c, p, n))
186 #define num_comp(c, p) ((p)->name.name_string.len)
187 #define realm_data(c, p) krb5_realm_data(krb5_principal_get_realm(c, p))
188 #define realm_len(c, p) krb5_realm_length(krb5_principal_get_realm(c, p))
189
190 #else
191 #error "Must have either krb5_princ_size or krb5_principal_get_comp_string"
192 #endif
193
194 #if defined(HAVE_KRB5_CREDS_KEYBLOCK)
195
196 #define get_cred_keydata(c) c->keyblock.contents
197 #define get_cred_keylen(c) c->keyblock.length
198 #define get_creds_enctype(c) c->keyblock.enctype
199
200 #elif defined(HAVE_KRB5_CREDS_SESSION)
201
202 #define get_cred_keydata(c) c->session.keyvalue.data
203 #define get_cred_keylen(c) c->session.keyvalue.length
204 #define get_creds_enctype(c) c->session.keytype
205
206 #else
207 #error "Must have either keyblock or session member of krb5_creds"
208 #endif
209
210 static int
211 whoami(struct ktc_token *atoken,
212 struct afsconf_cell *cellconfig,
213 struct ktc_principal *aclient,
214 int *vicep)
215 {
216 int code;
217 char tempname[2*PR_MAXNAMELEN];
218
219 code = pr_Initialize(0, AFSDIR_CLIENT_ETC_DIRPATH, cellconfig->name);
220 if (code)
221 goto Failed;
222
223 if (*aclient->instance)
224 snprintf (tempname, sizeof tempname, "%s.%s",
225 aclient->name, aclient->instance);
226 else
227 snprintf (tempname, sizeof tempname, "%s", aclient->name);
228 code = pr_SNameToId(tempname, vicep);
229 Failed:
230 return code;
231 }
232
233 static void
234 k5_to_k4_name(krb5_context k5context,
235 krb5_principal k5princ,
236 struct ktc_principal *ktcprinc)
237 {
238 int i;
239
240 switch(num_comp(k5context, k5princ)) {
241 default:
242 /* case 2: */
243 i = get_princ_len(k5context, k5princ, 1);
244 if (i > MAXKTCNAMELEN-1) i = MAXKTCNAMELEN-1;
245 memcpy(ktcprinc->instance, get_princ_str(k5context, k5princ, 1), i);
246 /* fall through */
247 case 1:
248 i = get_princ_len(k5context, k5princ, 0);
249 if (i > MAXKTCNAMELEN-1) i = MAXKTCNAMELEN-1;
250 memcpy(ktcprinc->name, get_princ_str(k5context, k5princ, 0), i);
251 /* fall through */
252 case 0:
253 break;
254 }
255 }
256
257 #if defined(USING_HEIMDAL) || defined(HAVE_KRB5_PROMPT_TYPE)
258 static int
259 klog_is_pass_prompt(int index, krb5_context context, krb5_prompt prompts[])
260 {
261 switch (prompts[index].type) {
262 case KRB5_PROMPT_TYPE_PASSWORD:
263 case KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN:
264 return 1;
265 default:
266 return 0;
267 }
268 }
269 #elif defined(HAVE_KRB5_GET_PROMPT_TYPES)
270 static int
271 klog_is_pass_prompt(int index, krb5_context context, krb5_prompt prompts[])
272 {
273 /* this isn't thread-safe or anything obviously; it just should be good
274 * enough to work with klog */
275 static krb5_prompt_type *types = NULL;
276 if (index == 0) {
277 types = NULL;
278 }
279 if (!types) {
280 types = krb5_get_prompt_types(context);
281 }
282 if (!types) {
283 return 0;
284 }
285 switch (types[index]) {
286 case KRB5_PROMPT_TYPE_PASSWORD:
287 case KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN:
288 return 1;
289 default:
290 return 0;
291 }
292 }
293 #else
294 static int
295 klog_is_pass_prompt(int index, krb5_context context, krb5_prompt prompts[])
296 {
297 /* AIX 5.3 doesn't have krb5_get_prompt_types. Neither does HP-UX, which
298 * also doesn't even define KRB5_PROMPT_TYPE_PASSWORD &co. We have no way
299 * of determining the the prompt type, so just assume it's a password */
300 return 1;
301 }
302 #endif
303
304 /* save and reuse password. This is necessary to make
305 * "direct to service" authentication work with most
306 * flavors of kerberos, when the afs principal has no instance.
307 */
308 struct kp_arg {
309 char **pp, *pstore;
310 size_t allocated;
311 };
312 krb5_error_code
313 klog_prompter(krb5_context context,
314 void *a,
315 const char *name,
316 const char *banner,
317 int num_prompts,
318 krb5_prompt prompts[])
319 {
320 krb5_error_code code;
321 int i;
322 struct kp_arg *kparg = (struct kp_arg *) a;
323 size_t length;
324
325 code = krb5_prompter_posix(context, a, name, banner, num_prompts, prompts);
326 if (code) return code;
327 for (i = 0; i < num_prompts; ++i) {
328 if (klog_is_pass_prompt(i, context, prompts)) {
329 length = prompts[i].reply->length;
330 if (length > kparg->allocated - 1)
331 length = kparg->allocated - 1;
332 memcpy(kparg->pstore, prompts[i].reply->data, length);
333 kparg->pstore[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 krb5_creds incred[1], mcred[1], *outcred = 0, *afscred;
347 krb5_ccache cc = 0;
348 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
349 krb5_get_init_creds_opt *gic_opts;
350 #else
351 krb5_get_init_creds_opt gic_opts[1];
352 #endif
353 char *tofree = NULL, *outname;
354 int code;
355 char *what;
356 int i, dosetpag, evil, noprdb, id;
357 #ifdef AFS_RXK5
358 int authtype;
359 #endif
360 krb5_data enc_part[1];
361 time_t lifetime; /* requested ticket lifetime */
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 if (as->parms[aLIFETIME].items) {
512 char *life = as->parms[aLIFETIME].items->data;
513 char *sp; /* string ptr to rest of life */
514 lifetime = 3600 * strtol(life, &sp, 0); /* hours */
515 if (sp == life) {
516 bad_lifetime:
517 if (!Silent)
518 fprintf(stderr, "%s: translating '%s' to lifetime failed\n",
519 rn, life);
520 return 1;
521 }
522 if (*sp == ':') {
523 life = sp + 1; /* skip the colon */
524 lifetime += 60 * strtol(life, &sp, 0); /* minutes */
525 if (sp == life)
526 goto bad_lifetime;
527 if (*sp == ':') {
528 life = sp + 1;
529 lifetime += strtol(life, &sp, 0); /* seconds */
530 if (sp == life)
531 goto bad_lifetime;
532 if (*sp)
533 goto bad_lifetime;
534 } else if (*sp)
535 goto bad_lifetime;
536 } else if (*sp)
537 goto bad_lifetime;
538 } else
539 lifetime = 0;
540
541 /* Get the password if it wasn't provided. */
542 if (!pass) {
543 if (Pipe) {
544 strncpy(passwd, getpipepass(), sizeof(passwd));
545 pass = passwd;
546 } else {
547 pf = klog_prompter;
548 pa = klog_arg;
549 }
550 }
551
552 service = 0;
553 #ifdef AFS_RXK5
554 if (authtype & FORCE_RXK5) {
555 tofree = get_afs_krb5_svc_princ(cellconfig);
556 snprintf(service_temp, sizeof service_temp, "%s", tofree);
557 } else
558 #endif
559 snprintf (service_temp, sizeof service_temp, "afs/%s", cellconfig->name);
560
561 klog_arg->pp = &pass;
562 klog_arg->pstore = passwd;
563 klog_arg->allocated = sizeof(passwd);
564 /* XXX should allow k5 to prompt in most cases -- what about expired pw?*/
565 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
566 code = krb5_get_init_creds_opt_alloc(k5context, &gic_opts);
567 if (code) {
568 afs_com_err(rn, code, "Can't allocate get_init_creds options");
569 KLOGEXIT(code);
570 }
571 #else
572 krb5_get_init_creds_opt_init(gic_opts);
573 #endif
574
575 for (;;) {
576 code = krb5_get_init_creds_password(k5context,
577 incred,
578 princ,
579 pass,
580 pf, /* prompter */
581 pa, /* data */
582 0, /* start_time */
583 0, /* in_tkt_service */
584 gic_opts);
585 if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
586 break;
587 }
588 memset(passwd, 0, sizeof(passwd));
589 if (code) {
590 char *r = 0;
591 if (krb5_get_default_realm(k5context, &r))
592 r = 0;
593 if (r)
594 afs_com_err(rn, code, "Unable to authenticate in realm %s", r);
595 else
596 afs_com_err(rn, code, "Unable to authenticate to use cell %s",
597 cellconfig->name);
598 if (r) free(r);
599 KLOGEXIT(code);
600 }
601
602 for (;;writeTicketFile = 0) {
603 if (writeTicketFile) {
604 what = "getting default ccache";
605 code = krb5_cc_default(k5context, &cc);
606 } else {
607 what = "krb5_cc_resolve";
608 code = krb5_cc_resolve(k5context, "MEMORY:core", &cc);
609 if (code) goto Failed;
610 }
611 what = "initializing ccache";
612 code = krb5_cc_initialize(k5context, cc, princ);
613 if (code) goto Failed;
614 what = "writing Kerberos ticket file";
615 code = krb5_cc_store_cred(k5context, cc, incred);
616 if (code) goto Failed;
617 if (writeTicketFile)
618 fprintf(stderr,
619 "Wrote ticket file to %s\n",
620 krb5_cc_get_name(k5context, cc));
621 break;
622 Failed:
623 if (code)
624 afs_com_err(rn, code, "%s", what);
625 if (writeTicketFile) {
626 if (cc) {
627 krb5_cc_close(k5context, cc);
628 cc = 0;
629 }
630 continue;
631 }
632 KLOGEXIT(code);
633 }
634
635 for (service = service_temp;;service = "afs") {
636 memset(mcred, 0, sizeof *mcred);
637 mcred->client = princ;
638 code = krb5_parse_name(k5context, service, &mcred->server);
639 if (code) {
640 afs_com_err(rn, code, "Unable to parse service <%s>\n", service);
641 KLOGEXIT(code);
642 }
643 if (tofree) { free(tofree); tofree = 0; }
644 if (!(code = krb5_unparse_name(k5context, mcred->server, &outname)))
645 tofree = outname;
646 else outname = service;
647 code = krb5_get_credentials(k5context, 0, cc, mcred, &outcred);
648 krb5_free_principal(k5context, mcred->server);
649 if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || service != service_temp) break;
650 #ifdef AFS_RXK5
651 if (authtype & FORCE_RXK5)
652 break;
653 #endif
654 }
655 afscred = outcred;
656
657 if (code) {
658 afs_com_err(rn, code, "Unable to get credentials to use %s", outname);
659 KLOGEXIT(code);
660 }
661
662 #ifdef AFS_RXK5
663 if (authtype & FORCE_RXK5) {
664 struct ktc_principal aserver[1];
665 int viceid = 555;
666
667 memset(aserver, 0, sizeof *aserver);
668 strncpy(aserver->cell, cellconfig->name, MAXKTCREALMLEN-1);
669 code = ktc_SetK5Token(k5context, aserver, afscred, viceid, dosetpag);
670 if (code) {
671 afs_com_err(rn, code, "Unable to store tokens for cell %s\n",
672 cellconfig->name);
673 KLOGEXIT(1);
674 }
675 } else
676 #endif
677 {
678 struct ktc_principal aserver[1], aclient[1];
679 struct ktc_token atoken[1];
680
681 memset(atoken, 0, sizeof *atoken);
682 if (evil) {
683 size_t elen = enc_part->length;
684 atoken->kvno = RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY;
685 if (afs_krb5_skip_ticket_wrapper(afscred->ticket.data,
686 afscred->ticket.length, (char **) &enc_part->data,
687 &elen)) {
688 afs_com_err(rn, 0, "Can't unwrap %s AFS credential",
689 cellconfig->name);
690 KLOGEXIT(1);
691 }
692 } else {
693 atoken->kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
694 *enc_part = afscred->ticket;
695 }
696 atoken->startTime = afscred->times.starttime;
697 atoken->endTime = afscred->times.endtime;
698 if (tkt_DeriveDesKey(get_creds_enctype(afscred),
699 get_cred_keydata(afscred),
700 get_cred_keylen(afscred), &atoken->sessionKey)) {
701 afs_com_err(rn, 0,
702 "Cannot derive DES key from enctype %i of length %u",
703 get_creds_enctype(afscred),
704 (unsigned)get_cred_keylen(afscred));
705 KLOGEXIT(1);
706 }
707 memcpy(atoken->ticket, enc_part->data,
708 atoken->ticketLen = enc_part->length);
709 memset(aserver, 0, sizeof *aserver);
710 strncpy(aserver->name, "afs", 4);
711 strncpy(aserver->cell, cellconfig->name, MAXKTCREALMLEN-1);
712 memset(aclient, 0, sizeof *aclient);
713 i = realm_len(k5context, afscred->client);
714 if (i > MAXKTCREALMLEN-1) i = MAXKTCREALMLEN-1;
715 memcpy(aclient->cell, realm_data(k5context, afscred->client), i);
716 if (!noprdb) {
717 int viceid = 0;
718 k5_to_k4_name(k5context, afscred->client, aclient);
719 code = whoami(atoken, cellconfig, aclient, &viceid);
720 if (code) {
721 afs_com_err(rn, code, "Can't get your viceid for cell %s", cellconfig->name);
722 *aclient->name = 0;
723 } else
724 snprintf(aclient->name, MAXKTCNAMELEN-1, "AFS ID %d", viceid);
725 }
726 if (!*aclient->name)
727 k5_to_k4_name(k5context, afscred->client, aclient);
728 code = ktc_SetToken(aserver, atoken, aclient, dosetpag);
729 if (code) {
730 afs_com_err(rn, code, "Unable to store tokens for cell %s\n",
731 cellconfig->name);
732 KLOGEXIT(1);
733 }
734 }
735
736 krb5_free_principal(k5context, princ);
737 krb5_free_cred_contents(k5context, incred);
738 if (outcred) krb5_free_creds(k5context, outcred);
739 if (cc)
740 krb5_cc_close(k5context, cc);
741 if (tofree) free(tofree);
742
743 return 0;
744 }