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>
19 #include <afs/com_err.h>
21 #include <afs/afsutil.h>
22 #include <afs/cellconfig.h>
23 #include <afs/ptclient.h>
25 #include <afs/ptuser.h>
27 #define KERBEROS_APPLE_DEPRECATED(x)
30 #ifdef HAVE_KRB5_CREDS_KEYBLOCK
33 #ifdef HAVE_KRB5_CREDS_SESSION
34 #define USING_HEIMDAL 1
39 /* This code borrowed heavily from the previous version of log. Here is the
40 intro comment for that program: */
43 log -- tell the Andrew Cache Manager your password
48 Further modified in August 1987 to understand cell IDs.
50 Further modified in October 2006 to understand kerberos 5.
54 klog [principal [password]] [-t] [-c cellname] [-k <k5realm>]
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
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
64 -k identifies an alternate kerberos realm to use provide
65 authentication services for the cell.
68 #define KLOGEXIT(code) rx_Finalize(); \
70 static int CommandProc(struct cmd_syndesc *as, void *arock);
73 static char **zero_argv;
75 static krb5_context k5context;
76 static struct afsconf_dir *tdir;
77 static int always_evil = 2; /* gcc optimizes 0 into bss. fools. */
80 main(int argc, char *argv[])
82 struct cmd_syndesc *ts;
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.
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);
102 ts = cmd_CreateSyntax(NULL, CommandProc, NULL, 0,
103 "obtain Kerberos authentication");
121 cmd_AddParm(ts, "-x", CMD_FLAG, CMD_OPTIONAL, "obsolete, noop");
122 cmd_Seek(ts, aPRINCIPAL);
123 cmd_AddParm(ts, "-principal", CMD_SINGLE, CMD_OPTIONAL, "user name");
124 cmd_AddParm(ts, "-password", CMD_SINGLE, CMD_OPTIONAL, "user's password");
125 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
126 cmd_AddParm(ts, "-k", CMD_SINGLE, CMD_OPTIONAL, "krb5 realm");
127 cmd_AddParm(ts, "-pipe", CMD_FLAG, CMD_OPTIONAL,
128 "read password from stdin");
129 cmd_AddParm(ts, "-silent", CMD_FLAG, CMD_OPTIONAL, "silent operation");
130 /* Note: -lifetime is not implemented in this version of klog. */
131 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
132 "ticket lifetime in hh[:mm[:ss]]");
133 cmd_AddParm(ts, "-setpag", CMD_FLAG, CMD_OPTIONAL,
134 "Create a new setpag before authenticating");
135 cmd_AddParm(ts, "-tmp", CMD_FLAG, CMD_OPTIONAL,
136 "write Kerberos-style ticket file in /tmp");
137 cmd_AddParm(ts, "-noprdb", CMD_FLAG, CMD_OPTIONAL, "don't consult pt");
138 cmd_AddParm(ts, "-unwrap", CMD_FLAG, CMD_OPTIONAL, "perform 524d conversion");
140 cmd_AddParm(ts, "-k5", CMD_FLAG, CMD_OPTIONAL, "get rxk5 credentials");
141 cmd_AddParm(ts, "-k4", CMD_FLAG, CMD_OPTIONAL, "get rxkad credentials");
143 ++ts->nParms; /* skip -k5 */
144 cmd_AddParm(ts, "-k4", CMD_FLAG, CMD_OPTIONAL|CMD_HIDDEN, 0);
146 cmd_AddParm(ts, "-insecure_des", CMD_FLAG, CMD_OPTIONAL,
147 "enable insecure single-DES for krb5");
149 code = cmd_Dispatch(argc, argv);
156 static char gpbuf[BUFSIZ];
157 /* read a password from stdin, stop on \n or eof */
159 memset(gpbuf, 0, sizeof(gpbuf));
160 for (i = 0; i < (sizeof(gpbuf) - 1); i++) {
162 if (tc == '\n' || tc == EOF)
170 silent_errors(const char *who,
175 /* ignore and don't print error */
178 #if defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size)
180 #define get_princ_str(c, p, n) krb5_princ_component(c, p, n)->data
181 #define get_princ_len(c, p, n) krb5_princ_component(c, p, n)->length
182 #define num_comp(c, p) (krb5_princ_size(c, p))
183 #define realm_data(c, p) krb5_princ_realm(c, p)->data
184 #define realm_len(c, p) krb5_princ_realm(c, p)->length
186 #elif defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
188 #define get_princ_str(c, p, n) krb5_principal_get_comp_string(c, p, n)
189 #define get_princ_len(c, p, n) strlen(krb5_principal_get_comp_string(c, p, n))
190 #define num_comp(c, p) ((p)->name.name_string.len)
191 #define realm_data(c, p) krb5_realm_data(krb5_principal_get_realm(c, p))
192 #define realm_len(c, p) krb5_realm_length(krb5_principal_get_realm(c, p))
195 #error "Must have either krb5_princ_size or krb5_principal_get_comp_string"
198 #if defined(HAVE_KRB5_CREDS_KEYBLOCK)
200 #define get_cred_keydata(c) c->keyblock.contents
201 #define get_cred_keylen(c) c->keyblock.length
202 #define get_creds_enctype(c) c->keyblock.enctype
204 #elif defined(HAVE_KRB5_CREDS_SESSION)
206 #define get_cred_keydata(c) c->session.keyvalue.data
207 #define get_cred_keylen(c) c->session.keyvalue.length
208 #define get_creds_enctype(c) c->session.keytype
211 #error "Must have either keyblock or session member of krb5_creds"
215 whoami(struct ktc_token *atoken,
216 struct afsconf_cell *cellconfig,
217 struct ktc_principal *aclient,
221 char tempname[2*PR_MAXNAMELEN];
223 code = pr_Initialize(0, AFSDIR_CLIENT_ETC_DIRPATH, cellconfig->name);
227 if (*aclient->instance)
228 snprintf (tempname, sizeof tempname, "%s.%s",
229 aclient->name, aclient->instance);
231 snprintf (tempname, sizeof tempname, "%s", aclient->name);
232 code = pr_SNameToId(tempname, vicep);
238 k5_to_k4_name(krb5_context k5context,
239 krb5_principal k5princ,
240 struct ktc_principal *ktcprinc)
244 switch(num_comp(k5context, k5princ)) {
247 i = get_princ_len(k5context, k5princ, 1);
248 if (i > MAXKTCNAMELEN-1) i = MAXKTCNAMELEN-1;
249 memcpy(ktcprinc->instance, get_princ_str(k5context, k5princ, 1), i);
252 i = get_princ_len(k5context, k5princ, 0);
253 if (i > MAXKTCNAMELEN-1) i = MAXKTCNAMELEN-1;
254 memcpy(ktcprinc->name, get_princ_str(k5context, k5princ, 0), i);
262 CommandProc(struct cmd_syndesc *as, void *arock)
264 krb5_principal princ = 0;
265 char *cell, *pname, **hrealms, *service;
266 char service_temp[MAXKTCREALMLEN + 20];
267 krb5_creds incred[1], mcred[1], *outcred = 0, *afscred;
269 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
270 krb5_get_init_creds_opt *gic_opts;
272 krb5_get_init_creds_opt gic_opts[1];
274 char *tofree = NULL, *outname;
277 int i, dosetpag, evil, noprdb, id;
281 krb5_data enc_part[1];
285 struct afsconf_cell cellconfig[1];
287 static char rn[] = "klog"; /*Routine name */
288 static int Pipe = 0; /* reading from a pipe */
289 static int Silent = 0; /* Don't want error messages */
291 int writeTicketFile = 0; /* write ticket file to /tmp */
294 memset(incred, 0, sizeof *incred);
295 /* blow away command line arguments */
296 for (i = 1; i < zero_argc; i++)
297 memset(zero_argv[i], 0, strlen(zero_argv[i]));
300 /* first determine quiet flag based on -silent switch */
301 Silent = (as->parms[aSILENT].items ? 1 : 0);
304 afs_set_com_err_hook(silent_errors);
307 if ((code = krb5_init_context(&k5context))) {
308 afs_com_err(rn, code, "while initializing Kerberos 5 library");
311 if ((code = rx_Init(0))) {
312 afs_com_err(rn, code, "while initializing rx");
315 initialize_U_error_table();
316 /*initialize_krb5_error_table();*/
317 initialize_RXK_error_table();
318 initialize_KTC_error_table();
319 initialize_ACFG_error_table();
320 /* initialize_rx_error_table(); */
321 if (!(tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))) {
322 afs_com_err(rn, 0, "can't get afs configuration (afsconf_Open(%s))",
323 AFSDIR_CLIENT_ETC_DIRPATH);
328 * Enable DES enctypes, which are currently still required for AFS.
329 * krb5_allow_weak_crypto is MIT Kerberos 1.8. krb5_enctype_enable is
332 if (as->parms[aDES].items) {
333 #if defined(HAVE_KRB5_ENCTYPE_ENABLE)
334 i = krb5_enctype_valid(k5context, ETYPE_DES_CBC_CRC);
336 krb5_enctype_enable(k5context, ETYPE_DES_CBC_CRC);
337 #elif defined(HAVE_KRB5_ALLOW_WEAK_CRYPTO)
338 krb5_allow_weak_crypto(k5context, 1);
342 /* Parse remaining arguments. */
344 dosetpag = !! as->parms[aSETPAG].items;
345 Pipe = !! as->parms[aPIPE].items;
346 writeTicketFile = !! as->parms[aTMP].items;
347 noprdb = !! as->parms[aNOPRDB].items;
348 evil = (always_evil&1) || !! as->parms[aUNWRAP].items;
352 if (as->parms[aK5].items)
353 authtype |= FORCE_RXK5;
354 if (as->parms[aK4].items)
355 authtype |= FORCE_RXKAD;
357 authtype |= env_afs_rxk5_default();
360 cell = as->parms[aCELL].items ? as->parms[aCELL].items->data : 0;
361 if ((code = afsconf_GetCellInfo(tdir, cell, "afsprot", cellconfig))) {
363 afs_com_err(rn, code, "Can't get cell information for '%s'", cell);
365 afs_com_err(rn, code, "Can't get determine local cell!");
369 if (as->parms[aKRBREALM].items) {
370 code = krb5_set_default_realm(k5context,
371 as->parms[aKRBREALM].items->data);
373 afs_com_err(rn, code, "Can't make <%s> the default realm",
374 as->parms[aKRBREALM].items->data);
378 else if ((code = krb5_get_host_realm(k5context, cellconfig->hostName[0], &hrealms))) {
379 afs_com_err(rn, code, "Can't get realm for host <%s> in cell <%s>\n",
380 cellconfig->hostName[0], cellconfig->name);
383 if (hrealms && *hrealms) {
384 code = krb5_set_default_realm(k5context,
387 afs_com_err(rn, code, "Can't make <%s> the default realm",
392 if (hrealms) krb5_free_host_realm(k5context, hrealms);
396 if (as->parms[aPRINCIPAL].items) {
397 pname = as->parms[aPRINCIPAL].items->data;
399 /* No explicit name provided: use Unix uid. */
404 "Can't figure out your name from your user id (%d).", id);
406 fprintf(stderr, "%s: Try providing the user name.\n", rn);
411 code = krb5_parse_name(k5context, pname, &princ);
413 afs_com_err(rn, code, "Can't parse principal <%s>", pname);
417 if (as->parms[aPASSWORD].items) {
419 * Current argument is the desired password string. Remember it in
420 * our local buffer, and zero out the argument string - anyone can
421 * see it there with ps!
423 strncpy(passwd, as->parms[aPASSWORD].items->data, sizeof(passwd));
424 memset(as->parms[aPASSWORD].items->data, 0,
425 strlen(as->parms[aPASSWORD].items->data));
429 /* Get the password from stdin if it wasn't provided. */
431 strncpy(passwd, getpipepass(), sizeof(passwd));
437 if (authtype & FORCE_RXK5) {
438 tofree = get_afs_krb5_svc_princ(cellconfig);
439 snprintf(service_temp, sizeof service_temp, "%s", tofree);
442 snprintf (service_temp, sizeof service_temp, "afs/%s", cellconfig->name);
444 /* XXX should allow k5 to prompt in most cases -- what about expired pw?*/
445 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
446 code = krb5_get_init_creds_opt_alloc(k5context, &gic_opts);
448 afs_com_err(rn, code, "Can't allocate get_init_creds options");
452 krb5_get_init_creds_opt_init(gic_opts);
456 code = krb5_get_init_creds_password(k5context,
460 krb5_prompter_posix, /* prompter */
463 0, /* in_tkt_service */
465 if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
468 memset(passwd, 0, sizeof(passwd));
471 if (krb5_get_default_realm(k5context, &r))
474 afs_com_err(rn, code, "Unable to authenticate in realm %s", r);
476 afs_com_err(rn, code, "Unable to authenticate to use cell %s",
482 for (;;writeTicketFile = 0) {
483 if (writeTicketFile) {
484 what = "getting default ccache";
485 code = krb5_cc_default(k5context, &cc);
487 what = "krb5_cc_resolve";
488 code = krb5_cc_resolve(k5context, "MEMORY:core", &cc);
489 if (code) goto Failed;
491 what = "initializing ccache";
492 code = krb5_cc_initialize(k5context, cc, princ);
493 if (code) goto Failed;
494 what = "writing Kerberos ticket file";
495 code = krb5_cc_store_cred(k5context, cc, incred);
496 if (code) goto Failed;
499 "Wrote ticket file to %s\n",
500 krb5_cc_get_name(k5context, cc));
504 afs_com_err(rn, code, "%s", what);
505 if (writeTicketFile) {
507 krb5_cc_close(k5context, cc);
515 for (service = service_temp;;service = "afs") {
516 memset(mcred, 0, sizeof *mcred);
517 mcred->client = princ;
518 code = krb5_parse_name(k5context, service, &mcred->server);
520 afs_com_err(rn, code, "Unable to parse service <%s>\n", service);
523 if (tofree) { free(tofree); tofree = 0; }
524 if (!(code = krb5_unparse_name(k5context, mcred->server, &outname)))
526 else outname = service;
527 code = krb5_get_credentials(k5context, 0, cc, mcred, &outcred);
528 krb5_free_principal(k5context, mcred->server);
529 if (code != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || service != service_temp) break;
531 if (authtype & FORCE_RXK5)
538 afs_com_err(rn, code, "Unable to get credentials to use %s", outname);
543 if (authtype & FORCE_RXK5) {
544 struct ktc_principal aserver[1];
547 memset(aserver, 0, sizeof *aserver);
548 strncpy(aserver->cell, cellconfig->name, MAXKTCREALMLEN-1);
549 code = ktc_SetK5Token(k5context, aserver, afscred, viceid, dosetpag);
551 afs_com_err(rn, code, "Unable to store tokens for cell %s\n",
558 struct ktc_principal aserver[1], aclient[1];
559 struct ktc_token atoken[1];
561 memset(atoken, 0, sizeof *atoken);
563 size_t elen = enc_part->length;
564 atoken->kvno = RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY;
565 if (afs_krb5_skip_ticket_wrapper(afscred->ticket.data,
566 afscred->ticket.length, (char **) &enc_part->data,
568 afs_com_err(rn, 0, "Can't unwrap %s AFS credential",
573 atoken->kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
574 *enc_part = afscred->ticket;
576 atoken->startTime = afscred->times.starttime;
577 atoken->endTime = afscred->times.endtime;
578 if (tkt_DeriveDesKey(get_creds_enctype(afscred),
579 get_cred_keydata(afscred),
580 get_cred_keylen(afscred), &atoken->sessionKey)) {
582 "Cannot derive DES key from enctype %i of length %u",
583 get_creds_enctype(afscred),
584 (unsigned)get_cred_keylen(afscred));
587 memcpy(atoken->ticket, enc_part->data,
588 atoken->ticketLen = enc_part->length);
589 memset(aserver, 0, sizeof *aserver);
590 strncpy(aserver->name, "afs", 4);
591 strncpy(aserver->cell, cellconfig->name, MAXKTCREALMLEN-1);
592 memset(aclient, 0, sizeof *aclient);
593 i = realm_len(k5context, afscred->client);
594 if (i > MAXKTCREALMLEN-1) i = MAXKTCREALMLEN-1;
595 memcpy(aclient->cell, realm_data(k5context, afscred->client), i);
598 k5_to_k4_name(k5context, afscred->client, aclient);
599 code = whoami(atoken, cellconfig, aclient, &viceid);
601 afs_com_err(rn, code, "Can't get your viceid for cell %s", cellconfig->name);
604 snprintf(aclient->name, MAXKTCNAMELEN-1, "AFS ID %d", viceid);
607 k5_to_k4_name(k5context, afscred->client, aclient);
608 code = ktc_SetToken(aserver, atoken, aclient, dosetpag);
610 afs_com_err(rn, code, "Unable to store tokens for cell %s\n",
616 krb5_free_principal(k5context, princ);
617 krb5_free_cred_contents(k5context, incred);
618 if (outcred) krb5_free_creds(k5context, outcred);
620 krb5_cc_close(k5context, cc);
621 if (tofree) free(tofree);