Commit | Line | Data |
---|---|---|
805e021f CE |
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 | } |