2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * usr/src/cmd/cmd-inet/usr.bin/telnet/kerberos5.c
9 * Copyright (c) 1991, 1993
10 * The Regents of the University of California. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 /* based on @(#)kerberos5.c 8.1 (Berkeley) 6/4/93 */
44 * Copyright (C) 1990 by the Massachusetts Institute of Technology
46 * Export of this software from the United States of America may
47 * require a specific license from the United States Government.
48 * It is the responsibility of any person or organization contemplating
49 * export to obtain such a license before exporting.
51 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
52 * distribute this software and its documentation for any purpose and
53 * without fee is hereby granted, provided that the above copyright
54 * notice appear in all copies and that both that copyright notice and
55 * this permission notice appear in supporting documentation, and that
56 * the name of M.I.T. not be used in advertising or publicity pertaining
57 * to distribution of the software without specific, written prior
58 * permission. Furthermore if you modify this software you must label
59 * your software as modified software and not distribute it in such a
60 * fashion that it might be confused with the original M.I.T. software.
61 * M.I.T. makes no representations about the suitability of
62 * this software for any purpose. It is provided "as is" without express
63 * or implied warranty.
67 #include <arpa/telnet.h>
73 /* the following are from the kerberos tree */
77 #include <profile/prof_int.h>
78 #include <sys/param.h>
81 extern char *RemoteHostName
;
82 extern boolean_t auth_debug_mode
;
85 #define ACCEPTED_ENCTYPE(a) \
86 (a == ENCTYPE_DES_CBC_CRC || a == ENCTYPE_DES_CBC_MD5)
87 /* for comapatibility with non-Solaris KDC's, this has to be big enough */
88 #define KERBEROS_BUFSIZ 8192
90 int forward_flags
= 0; /* Flags get set in telnet/main.c on -f and -F */
91 static void kerberos5_forward(Authenticator
*);
93 static unsigned char str_data
[KERBEROS_BUFSIZ
] = { IAC
, SB
,
94 TELOPT_AUTHENTICATION
, 0, AUTHTYPE_KERBEROS_V5
, };
95 static char *appdef
[] = { "appdefaults", "telnet", NULL
};
96 static char *realmdef
[] = { "realms", NULL
, "telnet", NULL
};
98 static krb5_auth_context auth_context
= 0;
100 static krb5_data auth
; /* telnetd gets session key from here */
101 static krb5_ticket
*ticket
= NULL
;
102 /* telnet matches the AP_REQ and AP_REP with this */
104 static krb5_keyblock
*session_key
= 0;
105 char *telnet_krb5_realm
= NULL
;
108 * Change the kerberos realm
111 set_krb5_realm(char *name
)
114 (void) fprintf(stderr
, gettext("Could not set Kerberos realm, "
115 "no realm provided.\n"));
119 free(telnet_krb5_realm
);
121 telnet_krb5_realm
= (char *)strdup(name
);
123 if (telnet_krb5_realm
== NULL
)
124 (void) fprintf(stderr
, gettext(
125 "Could not set Kerberos realm, malloc failed\n"));
128 #define RETURN_NOMEM { errno = ENOMEM; return (-1); }
131 krb5_send_data(Authenticator
*ap
, int type
, krb5_pointer d
, int c
)
133 /* the first 3 bytes are control chars */
134 unsigned char *p
= str_data
+ 4;
135 unsigned char *cd
= (unsigned char *)d
;
136 /* spaceleft is incremented whenever p is decremented */
137 size_t spaceleft
= sizeof (str_data
) - 4;
140 c
= strlen((char *)cd
);
142 if (auth_debug_mode
) {
143 (void) printf("%s:%d: [%d] (%d)",
144 str_data
[3] == TELQUAL_IS
? ">>>IS" : ">>>REPLY",
145 str_data
[3], type
, c
);
147 (void) printf("\r\n");
160 if ((*p
++ = *cd
++) == IAC
) {
170 if (str_data
[3] == TELQUAL_IS
)
171 printsub('>', &str_data
[2], p
- &str_data
[2]);
172 return (net_write(str_data
, p
- str_data
));
175 krb5_context telnet_context
= 0;
179 kerberos5_init(Authenticator
*ap
)
181 krb5_error_code retval
;
183 str_data
[3] = TELQUAL_IS
;
184 if (krb5auth_flag
&& (telnet_context
== 0)) {
185 retval
= krb5_init_context(&telnet_context
);
193 kerberos5_send(Authenticator
*ap
)
195 krb5_error_code retval
;
197 krb5_creds creds
; /* telnet gets session key from here */
198 krb5_creds
*new_creds
= 0;
201 krb5_data check_data
;
203 krb5_keyblock
*newkey
= 0;
206 krb5_enctype
*ktypes
;
208 if (!UserNameRequested
) {
210 (void) printf(gettext("telnet: Kerberos V5: "
211 "no user name supplied\r\n"));
215 if ((retval
= krb5_cc_default(telnet_context
, &ccache
))) {
217 (void) printf(gettext("telnet: Kerberos V5: "
218 "could not get default ccache\r\n"));
222 (void) memset((char *)&creds
, 0, sizeof (creds
));
224 printf("telnet: calling krb5_sname_to_principal\n");
225 if ((retval
= krb5_sname_to_principal(telnet_context
, RemoteHostName
,
226 "host", KRB5_NT_SRV_HST
, &creds
.server
))) {
228 (void) printf(gettext("telnet: Kerberos V5: error "
229 "while constructing service name: %s\r\n"),
230 error_message(retval
));
234 printf("telnet: done calling krb5_sname_to_principal\n");
236 if (telnet_krb5_realm
!= NULL
) {
240 rdata
.length
= strlen(telnet_krb5_realm
);
241 rdata
.data
= (char *)malloc(rdata
.length
+ 1);
242 if (rdata
.data
== NULL
) {
243 (void) fprintf(stderr
, gettext("malloc failed\n"));
246 (void) strcpy(rdata
.data
, telnet_krb5_realm
);
247 krb5_princ_set_realm(telnet_context
, creds
.server
, &rdata
);
249 (void) printf(gettext(
250 "telnet: Kerberos V5: set kerberos realm to %s\r\n"),
254 if ((retval
= krb5_cc_get_principal(telnet_context
, ccache
,
255 &creds
.client
)) != 0) {
256 if (auth_debug_mode
) {
257 (void) printf(gettext(
258 "telnet: Kerberos V5: failure on principal "
259 "(%s)\r\n"), error_message(retval
));
261 krb5_free_cred_contents(telnet_context
, &creds
);
265 * Check to to confirm that at least one of the supported
266 * encryption types (des-cbc-md5, des-cbc-crc is available. If
267 * one is available then use it to obtain credentials.
270 if ((retval
= krb5_get_tgs_ktypes(telnet_context
, creds
.server
,
272 if (auth_debug_mode
) {
273 (void) printf(gettext(
274 "telnet: Kerberos V5: could not determine "
275 "TGS encryption types "
276 "(see default_tgs_enctypes in krb5.conf) "
277 "(%s)\r\n"), error_message(retval
));
279 krb5_free_cred_contents(telnet_context
, &creds
);
283 for (i
= 0; ktypes
[i
]; i
++) {
284 if (ACCEPTED_ENCTYPE(ktypes
[i
]))
288 if (ktypes
[i
] == 0) {
289 if (auth_debug_mode
) {
290 (void) printf(gettext(
291 "telnet: Kerberos V5: "
292 "failure on encryption types. "
293 "Cannot find des-cbc-md5 or des-cbc-crc "
294 "in list of TGS encryption types "
295 "(see default_tgs_enctypes in krb5.conf)\n"));
297 krb5_free_cred_contents(telnet_context
, &creds
);
301 creds
.keyblock
.enctype
= ktypes
[i
];
302 if ((retval
= krb5_get_credentials(telnet_context
, 0,
303 ccache
, &creds
, &new_creds
))) {
304 if (auth_debug_mode
) {
305 (void) printf(gettext(
306 "telnet: Kerberos V5: failure on credentials "
307 "(%s)\r\n"), error_message(retval
));
309 krb5_free_cred_contents(telnet_context
, &creds
);
313 ap_opts
= ((ap
->way
& AUTH_HOW_MASK
) == AUTH_HOW_MUTUAL
) ?
314 AP_OPTS_MUTUAL_REQUIRED
: 0;
316 ap_opts
|= AP_OPTS_USE_SUBKEY
;
319 krb5_auth_con_free(telnet_context
, auth_context
);
322 if ((retval
= krb5_auth_con_init(telnet_context
, &auth_context
))) {
323 if (auth_debug_mode
) {
324 (void) printf(gettext(
325 "Kerberos V5: failed to init auth_context "
326 "(%s)\r\n"), error_message(retval
));
331 krb5_auth_con_setflags(telnet_context
, auth_context
,
332 KRB5_AUTH_CONTEXT_RET_TIME
);
334 type_check
[0] = ap
->type
;
335 type_check
[1] = ap
->way
;
336 check_data
.magic
= KV5M_DATA
;
337 check_data
.length
= 2;
338 check_data
.data
= (char *)&type_check
;
340 retval
= krb5_mk_req_extended(telnet_context
, &auth_context
, ap_opts
,
341 &check_data
, new_creds
, &auth
);
343 krb5_auth_con_getlocalsubkey(telnet_context
, auth_context
, &newkey
);
345 krb5_free_keyblock(telnet_context
, session_key
);
351 * keep the key in our private storage, but don't use it
352 * yet---see kerberos5_reply() below
354 if (!(ACCEPTED_ENCTYPE(newkey
->enctype
))) {
355 if (!(ACCEPTED_ENCTYPE(new_creds
->keyblock
.enctype
)))
356 /* use the session key in credentials instead */
357 krb5_copy_keyblock(telnet_context
,
358 &new_creds
->keyblock
, &session_key
);
360 krb5_copy_keyblock(telnet_context
,
361 newkey
, &session_key
);
363 krb5_free_keyblock(telnet_context
, newkey
);
366 krb5_free_cred_contents(telnet_context
, &creds
);
367 krb5_free_creds(telnet_context
, new_creds
);
371 (void) printf(gettext(
372 "telnet: Kerberos V5: mk_req failed (%s)\r\n"),
373 error_message(retval
));
377 if ((auth_sendname((uchar_t
*)UserNameRequested
,
378 strlen(UserNameRequested
))) == 0) {
380 (void) printf(gettext(
381 "telnet: Not enough room for user name\r\n"));
384 retval
= krb5_send_data(ap
, KRB_AUTH
, auth
.data
, auth
.length
);
385 if (auth_debug_mode
&& retval
) {
386 (void) printf(gettext(
387 "telnet: Sent Kerberos V5 credentials to server\r\n"));
388 } else if (auth_debug_mode
) {
389 (void) printf(gettext(
390 "telnet: Not enough room for authentication data\r\n"));
397 kerberos5_reply(Authenticator
*ap
, unsigned char *data
, int cnt
)
400 static boolean_t mutual_complete
= B_FALSE
;
407 (void) printf(gettext(
408 "[ Kerberos V5 refuses authentication because "
409 "%.*s ]\r\n"), cnt
, data
);
411 (void) printf(gettext(
412 "[ Kerberos V5 refuses authentication ]\r\n"));
416 if (!mutual_complete
) {
417 if ((ap
->way
& AUTH_HOW_MASK
) == AUTH_HOW_MUTUAL
) {
418 (void) printf(gettext(
419 "[ Kerberos V5 accepted you, but didn't "
420 "provide mutual authentication! ]\r\n"));
428 skey
.data
= session_key
->contents
;
429 encrypt_session_key(&skey
);
433 (void) printf(gettext(
434 "[ Kerberos V5 accepts you as ``%.*s'' ]\r\n"),
437 (void) printf(gettext(
438 "[ Kerberos V5 accepts you ]\r\n"));
439 auth_finished(ap
, AUTH_USER
);
441 if (forward_flags
& OPTS_FORWARD_CREDS
)
442 kerberos5_forward(ap
);
446 if ((ap
->way
& AUTH_HOW_MASK
) == AUTH_HOW_MUTUAL
) {
447 /* the rest of the reply should contain a krb_ap_rep */
448 krb5_ap_rep_enc_part
*reply
;
450 krb5_error_code retval
;
453 inbuf
.data
= (char *)data
;
455 retval
= krb5_rd_rep(telnet_context
, auth_context
,
458 (void) printf(gettext(
459 "[ Mutual authentication failed: "
460 "%s ]\r\n"), error_message(retval
));
464 krb5_free_ap_rep_enc_part(telnet_context
, reply
);
469 skey
.data
= session_key
->contents
;
470 encrypt_session_key(&skey
);
472 mutual_complete
= B_TRUE
;
475 case KRB_FORWARD_ACCEPT
:
476 (void) printf(gettext(
477 "[ Kerberos V5 accepted forwarded credentials ]\r\n"));
479 case KRB_FORWARD_REJECT
:
480 (void) printf(gettext(
481 "[ Kerberos V5 refuses forwarded credentials because "
482 "%.*s ]\r\n"), cnt
, data
);
486 (void) printf(gettext(
487 "Unknown Kerberos option %d\r\n"), data
[-1]);
494 kerberos5_status(Authenticator
*ap
, char *name
, int level
)
496 if (level
< AUTH_USER
)
499 if (UserNameRequested
&& krb5_kuserok(telnet_context
,
500 ticket
->enc_part2
->client
, UserNameRequested
)) {
502 /* the name buffer comes from telnetd/telnetd{-ktd}.c */
503 (void) strncpy(name
, UserNameRequested
, MAXNAMELEN
);
504 name
[MAXNAMELEN
-1] = '\0';
510 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len); }
511 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len); }
514 * Used with the set opt command to print suboptions
517 kerberos5_printsub(unsigned char *data
, int cnt
, unsigned char *buf
, int buflen
)
519 char lbuf
[AUTH_LBUF_BUFSIZ
];
522 buf
[buflen
-1] = '\0'; /* make sure its NULL terminated */
526 case KRB_REJECT
: /* Rejected (reason might follow) */
527 (void) strncpy((char *)buf
, " REJECT ", buflen
);
530 case KRB_ACCEPT
: /* Accepted (name might follow) */
531 (void) strncpy((char *)buf
, " ACCEPT ", buflen
);
536 ADDC(buf
, buflen
, '"');
537 for (i
= 4; i
< cnt
; i
++)
538 ADDC(buf
, buflen
, data
[i
]);
539 ADDC(buf
, buflen
, '"');
540 ADDC(buf
, buflen
, '\0');
543 case KRB_AUTH
: /* Authentication data follows */
544 (void) strncpy((char *)buf
, " AUTH", buflen
);
548 (void) strncpy((char *)buf
, " RESPONSE", buflen
);
551 case KRB_FORWARD
: /* Forwarded credentials follow */
552 (void) strncpy((char *)buf
, " FORWARD", buflen
);
555 case KRB_FORWARD_ACCEPT
: /* Forwarded credentials accepted */
556 (void) strncpy((char *)buf
, " FORWARD_ACCEPT", buflen
);
559 case KRB_FORWARD_REJECT
: /* Forwarded credentials rejected */
560 /* (reason might follow) */
561 (void) strncpy((char *)buf
, " FORWARD_REJECT", buflen
);
565 (void) snprintf(lbuf
, AUTH_LBUF_BUFSIZ
,
566 gettext(" %d (unknown)"),
568 (void) strncpy((char *)buf
, lbuf
, buflen
);
571 for (i
= 4; i
< cnt
; i
++) {
572 (void) snprintf(lbuf
, AUTH_LBUF_BUFSIZ
, " %d", data
[i
]);
573 (void) strncpy((char *)buf
, lbuf
, buflen
);
581 krb5_profile_get_options(char *host
, char *realm
,
582 profile_options_boolean
*optionsp
)
584 char **realms
= NULL
;
585 krb5_error_code err
= 0;
587 if (!telnet_context
) {
588 err
= krb5_init_context(&telnet_context
);
590 (void) fprintf(stderr
, gettext(
591 "Error initializing Kerberos 5 library: %s\n"),
597 if ((realmdef
[1] = realm
) == NULL
) {
598 err
= krb5_get_host_realm(telnet_context
, host
, &realms
);
600 (void) fprintf(stderr
, gettext(
601 "Error getting Kerberos 5 realms for: %s (%s)\n"),
602 host
, error_message(err
));
605 realmdef
[1] = realms
[0];
608 profile_get_options_boolean(telnet_context
->profile
,
610 profile_get_options_boolean(telnet_context
->profile
,
615 kerberos5_forward(Authenticator
*ap
)
617 krb5_error_code retval
;
619 krb5_principal client
= 0;
620 krb5_principal server
= 0;
621 krb5_data forw_creds
;
625 if ((retval
= krb5_cc_default(telnet_context
, &ccache
))) {
627 (void) printf(gettext(
628 "Kerberos V5: could not get default ccache - %s\r\n"),
629 error_message(retval
));
633 retval
= krb5_cc_get_principal(telnet_context
, ccache
, &client
);
636 (void) printf(gettext(
637 "Kerberos V5: could not get default "
638 "principal - %s\r\n"), error_message(retval
));
642 retval
= krb5_sname_to_principal(telnet_context
, RemoteHostName
,
643 "host", KRB5_NT_SRV_HST
, &server
);
646 (void) printf(gettext(
647 "Kerberos V5: could not make server "
648 "principal - %s\r\n"), error_message(retval
));
652 retval
= krb5_auth_con_genaddrs(telnet_context
, auth_context
, net
,
653 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR
);
656 (void) printf(gettext(
657 "Kerberos V5: could not gen local full "
658 "address - %s\r\n"), error_message(retval
));
662 retval
= krb5_fwd_tgt_creds(telnet_context
, auth_context
, 0, client
,
663 server
, ccache
, forward_flags
& OPTS_FORWARDABLE_CREDS
,
667 (void) printf(gettext(
668 "Kerberos V5: error getting forwarded "
669 "creds - %s\r\n"), error_message(retval
));
673 /* Send forwarded credentials */
674 if (!krb5_send_data(ap
, KRB_FORWARD
, forw_creds
.data
,
675 forw_creds
.length
)) {
677 (void) printf(gettext(
678 "Not enough room for authentication data\r\n"));
679 } else if (auth_debug_mode
)
680 (void) printf(gettext(
681 "Forwarded local Kerberos V5 credentials to server\r\n"));
684 krb5_free_principal(telnet_context
, client
);
686 krb5_free_principal(telnet_context
, server
);
687 free(forw_creds
.data
);
689 krb5_cc_close(telnet_context
, ccache
);