2
* Copyright 2000, International Business Machines Corporation and others.
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
10
#include <afsconfig.h>
11
#include <afs/param.h>
14
#include <sys/types.h>
33
#include <afs/com_err.h>
35
#include <afs/afsutil.h>
36
#include <afs/cellconfig.h>
38
#include "rxk5_utilafs.h"
40
#include <afs/ptclient.h>
44
#ifdef HAVE_KRB5_CREDS_KEYBLOCK
47
#ifdef HAVE_KRB5_CREDS_SESSION
48
#define USING_HEIMDAL 1
54
/* This code borrowed heavily from the previous version of log. Here is the
55
intro comment for that program: */
58
log -- tell the Andrew Cache Manager your password
63
Further modified in August 1987 to understand cell IDs.
65
Further modified in October 2006 to understand kerberos 5.
69
klog [principal [password]] [-t] [-c cellname] [-k <k5realm>]
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
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
79
-k identifies an alternate kerberos realm to use provide
80
authentication services for the cell.
83
#define KLOGEXIT(code) rx_Finalize(); \
85
extern int CommandProc(struct cmd_syndesc *as, char *arock);
88
static char **zero_argv;
90
static krb5_context k5context;
91
static struct afsconf_dir *tdir;
92
static int always_evil = 2; /* gcc optimizes 0 into bss. fools. */
95
main(int argc, char *argv[])
97
struct cmd_syndesc *ts;
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.
106
struct sigaction nsa;
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);
117
ts = cmd_CreateSyntax(NULL, CommandProc, 0,
118
"obtain Kerberos authentication");
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");
153
cmd_AddParm(ts, "-k5", CMD_FLAG, CMD_OPTIONAL, "get rxk5 credentials");
154
cmd_AddParm(ts, "-k4", CMD_FLAG, CMD_OPTIONAL, "get rxkad credentials");
156
++ts->nParms; /* skip -k5 */
157
cmd_AddParm(ts, "-k4", CMD_FLAG, CMD_OPTIONAL|CMD_HIDDEN, 0);
160
code = cmd_Dispatch(argc, argv);
167
static char gpbuf[BUFSIZ];
168
/* read a password from stdin, stop on \n or eof */
170
memset(gpbuf, 0, sizeof(gpbuf));
171
for (i = 0; i < (sizeof(gpbuf) - 1); i++) {
173
if (tc == '\n' || tc == EOF)
181
silent_errors(const char *who,
186
/* ignore and don't print error */
189
#if defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size)
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
197
#elif defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
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))
206
#error "Must have either krb5_princ_size or krb5_principal_get_comp_string"
209
#if defined(HAVE_KRB5_CREDS_KEYBLOCK)
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
215
#elif defined(HAVE_KRB5_CREDS_SESSION)
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
222
#error "Must have either keyblock or session member of krb5_creds"
226
whoami(struct ktc_token *atoken,
227
struct afsconf_cell *cellconfig,
228
struct ktc_principal *aclient,
234
struct ubik_client *ptconn = 0;
235
struct rx_securityClass *sc;
236
struct rx_connection *conns[MAXSERVERS+1];
239
char tempname[PR_MAXNAMELEN + 1];
241
memset(lnames, 0, sizeof *lnames);
242
memset(lids, 0, sizeof *lids);
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);
252
if ((code = ubik_ClientInit(conns, &ptconn)))
254
if (*aclient->instance)
255
snprintf (tempname, sizeof tempname, "%s.%s",
256
aclient->name, aclient->instance);
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;
266
if (lids->idlist_val) free(lids->idlist_val);
267
if (ptconn) ubik_ClientDestroy(ptconn);
272
k5_to_k4_name(krb5_context k5context,
273
krb5_principal k5princ,
274
struct ktc_principal *ktcprinc)
278
switch(num_comp(k5context, k5princ)) {
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);
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);
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.
303
klog_prompter(krb5_context context,
308
krb5_prompt prompts[])
310
krb5_error_code code;
312
#if !defined(USING_HEIMDAL) && defined(HAVE_KRB5_GET_PROMPT_TYPES)
313
krb5_prompt_type *types;
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
#if !defined(USING_HEIMDAL) && defined(HAVE_KRB5_GET_PROMPT_TYPES)
319
if ((types = krb5_get_prompt_types(context)))
321
for (i = 0; i < num_prompts; ++i) {
322
#if !defined(USING_HEIMDAL)
323
#if defined(HAVE_KRB5_GET_PROMPT_TYPES)
325
#elif defined(HAVE_KRB5_PROMPT_TYPE)
326
type = prompts[i].type;
328
/* AIX 5.3 krb5_get_prompt_types is missing. Um... */
329
type = ((i == 1)&&(num_prompts == 2)) ?
330
KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN : KRB5_PROMPT_TYPE_PASSWORD;
333
type = prompts[i].type;
336
printf ("i%d t%d <%.*s>\n", i, type, prompts[i].reply->length,
337
prompts[i].reply->data);
340
case KRB5_PROMPT_TYPE_PASSWORD:
341
case KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN:
342
memcpy(kparg->pstore, prompts[i].reply->data, prompts[i].reply->length);
343
kparg->pstore[prompts[i].reply->length] = 0;
344
*kparg->pp = kparg->pstore;
351
CommandProc(struct cmd_syndesc *as, char *arock)
353
krb5_principal princ = 0;
354
char *cell, *pname, **hrealms, *service;
355
char service_temp[MAXKTCREALMLEN + 20];
356
krb5_creds incred[1], mcred[1], *outcred = 0, *afscred;
358
krb5_get_init_creds_opt gic_opts[1];
359
char *tofree, *outname;
362
int i, dosetpag, evil, noprdb, id;
366
krb5_data enc_part[1];
367
time_t lifetime; /* requested ticket lifetime */
368
krb5_prompter_fct pf = NULL;
371
struct kp_arg klog_arg[1];
374
struct afsconf_cell cellconfig[1];
376
static char rn[] = "klog"; /*Routine name */
377
static int Pipe = 0; /* reading from a pipe */
378
static int Silent = 0; /* Don't want error messages */
380
int writeTicketFile = 0; /* write ticket file to /tmp */
383
memset(incred, 0, sizeof *incred);
384
/* blow away command line arguments */
385
for (i = 1; i < zero_argc; i++)
386
memset(zero_argv[i], 0, strlen(zero_argv[i]));
388
memset(klog_arg, 0, sizeof *klog_arg);
390
/* first determine quiet flag based on -silent switch */
391
Silent = (as->parms[aSILENT].items ? 1 : 0);
394
afs_set_com_err_hook(silent_errors);
397
if ((code = krb5_init_context(&k5context))) {
398
afs_com_err(rn, code, "while initializing Kerberos 5 library");
401
if ((code = rx_Init(0))) {
402
afs_com_err(rn, code, "while initializing rx");
405
initialize_U_error_table();
406
/*initialize_krb5_error_table();*/
407
initialize_RXK_error_table();
408
initialize_KTC_error_table();
409
initialize_ACFG_error_table();
410
/* initialize_rx_error_table(); */
411
if (!(tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))) {
412
afs_com_err(rn, 0, "can't get afs configuration (afsconf_Open(%s))",
413
rn, AFSDIR_CLIENT_ETC_DIRPATH);
417
/* Parse remaining arguments. */
419
dosetpag = !! as->parms[aSETPAG].items;
420
Pipe = !! as->parms[aPIPE].items;
421
writeTicketFile = !! as->parms[aTMP].items;
422
noprdb = !! as->parms[aNOPRDB].items;
423
evil = (always_evil&1) || !! as->parms[aUNWRAP].items;
427
if (as->parms[aK5].items)
428
authtype |= FORCE_RXK5;
429
if (as->parms[aK4].items)
430
authtype |= FORCE_RXKAD;
432
authtype |= env_afs_rxk5_default();
435
cell = as->parms[aCELL].items ? as->parms[aCELL].items->data : 0;
436
if ((code = afsconf_GetCellInfo(tdir, cell, "afsprot", cellconfig))) {
438
afs_com_err(rn, code, "Can't get cell information for '%s'", cell);
440
afs_com_err(rn, code, "Can't get determine local cell!");
444
if (as->parms[aKRBREALM].items) {
445
code = krb5_set_default_realm(k5context,
446
(const char *) as->parms[aKRBREALM].items);
448
afs_com_err(rn, code, "Can't make <%s> the default realm",
449
as->parms[aKRBREALM].items);
453
else if ((code = krb5_get_host_realm(k5context, cellconfig->hostName[0], &hrealms))) {
454
afs_com_err(rn, code, "Can't get realm for host <%s> in cell <%s>\n",
455
cellconfig->hostName[0], cellconfig->name);
458
if (hrealms && *hrealms) {
459
code = krb5_set_default_realm(k5context,
462
afs_com_err(rn, code, "Can't make <%s> the default realm",
467
if (hrealms) krb5_free_host_realm(k5context, hrealms);
471
if (as->parms[aPRINCIPAL].items) {
472
pname = as->parms[aPRINCIPAL].items->data;
474
/* No explicit name provided: use Unix uid. */
479
"Can't figure out your name from your user id (%d).", id);
481
fprintf(stderr, "%s: Try providing the user name.\n", rn);
486
code = krb5_parse_name(k5context, pname, &princ);
488
afs_com_err(rn, code, "Can't parse principal <%s>", pname);
492
if (as->parms[aPASSWORD].items) {
494
* Current argument is the desired password string. Remember it in
495
* our local buffer, and zero out the argument string - anyone can
496
* see it there with ps!
498
strncpy(passwd, as->parms[aPASSWORD].items->data, sizeof(passwd));
499
memset(as->parms[aPASSWORD].items->data, 0,
500
strlen(as->parms[aPASSWORD].items->data));
504
if (as->parms[aLIFETIME].items) {
505
char *life = as->parms[aLIFETIME].items->data;
506
char *sp; /* string ptr to rest of life */
507
lifetime = 3600 * strtol(life, &sp, 0); /* hours */
511
fprintf(stderr, "%s: translating '%s' to lifetime failed\n",
516
life = sp + 1; /* skip the colon */
517
lifetime += 60 * strtol(life, &sp, 0); /* minutes */
522
lifetime += strtol(life, &sp, 0); /* seconds */
534
/* Get the password if it wasn't provided. */
537
strncpy(passwd, getpipepass(), sizeof(passwd));
541
pa = (char *)klog_arg;
547
if (authtype & FORCE_RXK5) {
548
tofree = get_afs_krb5_svc_princ(cellconfig);
549
snprintf(service_temp, sizeof service_temp, "%s", tofree);
552
snprintf (service_temp, sizeof service_temp, "afs/%s", cellconfig->name);
556
service = service_temp;
558
klog_arg->pp = &pass;
559
klog_arg->pstore = passwd;
560
/* XXX should allow k5 to prompt in most cases -- what about expired pw?*/
561
krb5_get_init_creds_opt_init(gic_opts);
563
code = krb5_get_init_creds_password(k5context,
570
service, /* in_tkt_service */
572
if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || service != service_temp) break;
574
if (authtype & FORCE_RXK5) break;
578
memset(passwd, 0, sizeof(passwd));
581
if (krb5_get_default_realm(k5context, &r))
584
afs_com_err(rn, code, "Unable to authenticate to use %s", service);
586
afs_com_err(rn, code, "Unable to authenticate in realm %s", r);
588
afs_com_err(rn, code, "Unable to authenticate to use cell %s",
597
for (;;writeTicketFile = 0) {
598
if (writeTicketFile) {
599
what = "getting default ccache";
600
code = krb5_cc_default(k5context, &cc);
602
what = "krb5_cc_resolve";
603
code = krb5_cc_resolve(k5context, "MEMORY:core", &cc);
604
if (code) goto Failed;
606
what = "initializing ccache";
607
code = krb5_cc_initialize(k5context, cc, princ);
608
if (code) goto Failed;
609
what = "writing Kerberos ticket file";
610
code = krb5_cc_store_cred(k5context, cc, incred);
611
if (code) goto Failed;
614
"Wrote ticket file to %s\n",
615
krb5_cc_get_name(k5context, cc));
619
afs_com_err(rn, code, what);
620
if (writeTicketFile) {
622
krb5_cc_close(k5context, cc);
630
for (service = service_temp;;service = "afs") {
631
memset(mcred, 0, sizeof *mcred);
632
mcred->client = princ;
633
code = krb5_parse_name(k5context, service, &mcred->server);
635
afs_com_err(rn, code, "Unable to parse service <%s>\n", service);
638
if (tofree) { free(tofree); tofree = 0; }
639
if (!(code = krb5_unparse_name(k5context, mcred->server, &outname)))
641
else outname = service;
642
code = krb5_get_credentials(k5context, 0, cc, mcred, &outcred);
643
krb5_free_principal(k5context, mcred->server);
644
if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || service != service_temp) break;
646
if (authtype & FORCE_RXK5) break;
652
afs_com_err(rn, code, "Unable to get credentials to use %s", outname);
657
if (authtype & FORCE_RXK5) {
658
struct ktc_principal aserver[1];
661
memset(aserver, 0, sizeof *aserver);
662
strncpy(aserver->cell, cellconfig->name, MAXKTCREALMLEN-1);
663
code = ktc_SetK5Token(k5context, aserver, afscred, viceid, dosetpag);
665
afs_com_err(rn, code, "Unable to store tokens for cell %s\n",
672
struct ktc_principal aserver[1], aclient[1];
673
struct ktc_token atoken[1];
675
memset(atoken, 0, sizeof *atoken);
677
atoken->kvno = RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY;
678
if (afs_krb5_skip_ticket_wrapper(afscred->ticket.data,
679
afscred->ticket.length, &enc_part->data,
680
&enc_part->length)) {
681
afs_com_err(rn, 0, "Can't unwrap %s AFS credential",
686
atoken->kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
687
*enc_part = afscred->ticket;
689
atoken->startTime = afscred->times.starttime;
690
atoken->endTime = afscred->times.endtime;
691
memcpy(&atoken->sessionKey, get_cred_keydata(afscred),
692
get_cred_keylen(afscred));
693
memcpy(atoken->ticket, enc_part->data,
694
atoken->ticketLen = enc_part->length);
695
memset(aserver, 0, sizeof *aserver);
696
strncpy(aserver->name, "afs", 4);
697
strncpy(aserver->cell, cellconfig->name, MAXKTCREALMLEN-1);
698
memset(aclient, 0, sizeof *aclient);
699
i = realm_len(k5context, afscred->client);
700
if (i > MAXKTCREALMLEN-1) i = MAXKTCREALMLEN-1;
701
memcpy(aclient->cell, realm_data(k5context, afscred->client), i);
704
k5_to_k4_name(k5context, afscred->client, aclient);
705
code = whoami(atoken, cellconfig, aclient, &viceid);
707
afs_com_err(rn, code, "Can't get your viceid", cellconfig->name);
710
snprintf(aclient->name, MAXKTCNAMELEN-1, "AFS ID %d", viceid);
713
k5_to_k4_name(k5context, afscred->client, aclient);
714
code = ktc_SetToken(aserver, atoken, aclient, dosetpag);
716
afs_com_err(rn, code, "Unable to store tokens for cell %s\n",
722
krb5_free_principal(k5context, princ);
723
krb5_free_cred_contents(k5context, incred);
724
if (outcred) krb5_free_creds(k5context, outcred);
726
krb5_cc_close(k5context, cc);
727
if (tofree) free(tofree);