2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 #pragma ident "%Z%%M% %I% %E% SMI"
9 * usr/src/cmd/cmd-inet/usr.bin/telnet/kerberos5.c
11 * Copyright (c) 1991, 1993
12 * The Regents of the University of California. All rights reserved.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by the University of
25 * California, Berkeley and its contributors.
26 * 4. Neither the name of the University nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 /* based on @(#)kerberos5.c 8.1 (Berkeley) 6/4/93 */
46 * Copyright (C) 1990 by the Massachusetts Institute of Technology
48 * Export of this software from the United States of America may
49 * require a specific license from the United States Government.
50 * It is the responsibility of any person or organization contemplating
51 * export to obtain such a license before exporting.
53 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
54 * distribute this software and its documentation for any purpose and
55 * without fee is hereby granted, provided that the above copyright
56 * notice appear in all copies and that both that copyright notice and
57 * this permission notice appear in supporting documentation, and that
58 * the name of M.I.T. not be used in advertising or publicity pertaining
59 * to distribution of the software without specific, written prior
60 * permission. Furthermore if you modify this software you must label
61 * your software as modified software and not distribute it in such a
62 * fashion that it might be confused with the original M.I.T. software.
63 * M.I.T. makes no representations about the suitability of
64 * this software for any purpose. It is provided "as is" without express
65 * or implied warranty.
69 #include <arpa/telnet.h>
75 /* the following are from the kerberos tree */
79 #include <profile/prof_int.h>
80 #include <sys/param.h>
83 extern char *RemoteHostName
;
84 extern boolean_t auth_debug_mode
;
87 #define ACCEPTED_ENCTYPE(a) \
88 (a == ENCTYPE_DES_CBC_CRC || a == ENCTYPE_DES_CBC_MD5)
89 /* for comapatibility with non-Solaris KDC's, this has to be big enough */
90 #define KERBEROS_BUFSIZ 8192
92 int forward_flags
= 0; /* Flags get set in telnet/main.c on -f and -F */
93 static void kerberos5_forward(Authenticator
*);
95 static unsigned char str_data
[KERBEROS_BUFSIZ
] = { IAC
, SB
,
96 TELOPT_AUTHENTICATION
, 0, AUTHTYPE_KERBEROS_V5
, };
97 static char *appdef
[] = { "appdefaults", "telnet", NULL
};
98 static char *realmdef
[] = { "realms", NULL
, "telnet", NULL
};
100 static krb5_auth_context auth_context
= 0;
102 static krb5_data auth
; /* telnetd gets session key from here */
103 static krb5_ticket
*ticket
= NULL
;
104 /* telnet matches the AP_REQ and AP_REP with this */
106 static krb5_keyblock
*session_key
= 0;
107 char *telnet_krb5_realm
= NULL
;
110 * Change the kerberos realm
113 set_krb5_realm(char *name
)
116 (void) fprintf(stderr
, gettext("Could not set Kerberos realm, "
117 "no realm provided.\n"));
121 if (telnet_krb5_realm
)
122 free(telnet_krb5_realm
);
124 telnet_krb5_realm
= (char *)strdup(name
);
126 if (telnet_krb5_realm
== NULL
)
127 (void) fprintf(stderr
, gettext(
128 "Could not set Kerberos realm, malloc failed\n"));
131 #define RETURN_NOMEM { errno = ENOMEM; return (-1); }
134 krb5_send_data(Authenticator
*ap
, int type
, krb5_pointer d
, int c
)
136 /* the first 3 bytes are control chars */
137 unsigned char *p
= str_data
+ 4;
138 unsigned char *cd
= (unsigned char *)d
;
139 /* spaceleft is incremented whenever p is decremented */
140 size_t spaceleft
= sizeof (str_data
) - 4;
143 c
= strlen((char *)cd
);
145 if (auth_debug_mode
) {
146 (void) printf("%s:%d: [%d] (%d)",
147 str_data
[3] == TELQUAL_IS
? ">>>IS" : ">>>REPLY",
148 str_data
[3], type
, c
);
150 (void) printf("\r\n");
163 if ((*p
++ = *cd
++) == IAC
) {
173 if (str_data
[3] == TELQUAL_IS
)
174 printsub('>', &str_data
[2], p
- &str_data
[2]);
175 return (net_write(str_data
, p
- str_data
));
178 krb5_context telnet_context
= 0;
182 kerberos5_init(Authenticator
*ap
)
184 krb5_error_code retval
;
186 str_data
[3] = TELQUAL_IS
;
187 if (krb5auth_flag
&& (telnet_context
== 0)) {
188 retval
= krb5_init_context(&telnet_context
);
196 kerberos5_send(Authenticator
*ap
)
198 krb5_error_code retval
;
200 krb5_creds creds
; /* telnet gets session key from here */
201 krb5_creds
*new_creds
= 0;
204 krb5_data check_data
;
206 krb5_keyblock
*newkey
= 0;
209 krb5_enctype
*ktypes
;
211 if (!UserNameRequested
) {
213 (void) printf(gettext("telnet: Kerberos V5: "
214 "no user name supplied\r\n"));
218 if ((retval
= krb5_cc_default(telnet_context
, &ccache
))) {
220 (void) printf(gettext("telnet: Kerberos V5: "
221 "could not get default ccache\r\n"));
225 (void) memset((char *)&creds
, 0, sizeof (creds
));
227 printf("telnet: calling krb5_sname_to_principal\n");
228 if ((retval
= krb5_sname_to_principal(telnet_context
, RemoteHostName
,
229 "host", KRB5_NT_SRV_HST
, &creds
.server
))) {
231 (void) printf(gettext("telnet: Kerberos V5: error "
232 "while constructing service name: %s\r\n"),
233 error_message(retval
));
237 printf("telnet: done calling krb5_sname_to_principal\n");
239 if (telnet_krb5_realm
!= NULL
) {
243 rdata
.length
= strlen(telnet_krb5_realm
);
244 rdata
.data
= (char *)malloc(rdata
.length
+ 1);
245 if (rdata
.data
== NULL
) {
246 (void) fprintf(stderr
, gettext("malloc failed\n"));
249 (void) strcpy(rdata
.data
, telnet_krb5_realm
);
250 krb5_princ_set_realm(telnet_context
, creds
.server
, &rdata
);
252 (void) printf(gettext(
253 "telnet: Kerberos V5: set kerberos realm to %s\r\n"),
257 if ((retval
= krb5_cc_get_principal(telnet_context
, ccache
,
258 &creds
.client
)) != NULL
) {
259 if (auth_debug_mode
) {
260 (void) printf(gettext(
261 "telnet: Kerberos V5: failure on principal "
262 "(%s)\r\n"), error_message(retval
));
264 krb5_free_cred_contents(telnet_context
, &creds
);
268 * Check to to confirm that at least one of the supported
269 * encryption types (des-cbc-md5, des-cbc-crc is available. If
270 * one is available then use it to obtain credentials.
273 if ((retval
= krb5_get_tgs_ktypes(telnet_context
, creds
.server
,
275 if (auth_debug_mode
) {
276 (void) printf(gettext(
277 "telnet: Kerberos V5: could not determine "
278 "TGS encryption types "
279 "(see default_tgs_enctypes in krb5.conf) "
280 "(%s)\r\n"), error_message(retval
));
282 krb5_free_cred_contents(telnet_context
, &creds
);
286 for (i
= 0; ktypes
[i
]; i
++) {
287 if (ACCEPTED_ENCTYPE(ktypes
[i
]))
291 if (ktypes
[i
] == 0) {
292 if (auth_debug_mode
) {
293 (void) printf(gettext(
294 "telnet: Kerberos V5: "
295 "failure on encryption types. "
296 "Cannot find des-cbc-md5 or des-cbc-crc "
297 "in list of TGS encryption types "
298 "(see default_tgs_enctypes in krb5.conf)\n"));
300 krb5_free_cred_contents(telnet_context
, &creds
);
304 creds
.keyblock
.enctype
= ktypes
[i
];
305 if ((retval
= krb5_get_credentials(telnet_context
, 0,
306 ccache
, &creds
, &new_creds
))) {
307 if (auth_debug_mode
) {
308 (void) printf(gettext(
309 "telnet: Kerberos V5: failure on credentials "
310 "(%s)\r\n"), error_message(retval
));
312 krb5_free_cred_contents(telnet_context
, &creds
);
316 ap_opts
= ((ap
->way
& AUTH_HOW_MASK
) == AUTH_HOW_MUTUAL
) ?
317 AP_OPTS_MUTUAL_REQUIRED
: 0;
319 ap_opts
|= AP_OPTS_USE_SUBKEY
;
322 krb5_auth_con_free(telnet_context
, auth_context
);
325 if ((retval
= krb5_auth_con_init(telnet_context
, &auth_context
))) {
326 if (auth_debug_mode
) {
327 (void) printf(gettext(
328 "Kerberos V5: failed to init auth_context "
329 "(%s)\r\n"), error_message(retval
));
334 krb5_auth_con_setflags(telnet_context
, auth_context
,
335 KRB5_AUTH_CONTEXT_RET_TIME
);
337 type_check
[0] = ap
->type
;
338 type_check
[1] = ap
->way
;
339 check_data
.magic
= KV5M_DATA
;
340 check_data
.length
= 2;
341 check_data
.data
= (char *)&type_check
;
343 retval
= krb5_mk_req_extended(telnet_context
, &auth_context
, ap_opts
,
344 &check_data
, new_creds
, &auth
);
346 krb5_auth_con_getlocalsubkey(telnet_context
, auth_context
, &newkey
);
348 krb5_free_keyblock(telnet_context
, session_key
);
354 * keep the key in our private storage, but don't use it
355 * yet---see kerberos5_reply() below
357 if (!(ACCEPTED_ENCTYPE(newkey
->enctype
))) {
358 if (!(ACCEPTED_ENCTYPE(new_creds
->keyblock
.enctype
)))
359 /* use the session key in credentials instead */
360 krb5_copy_keyblock(telnet_context
,
361 &new_creds
->keyblock
, &session_key
);
363 krb5_copy_keyblock(telnet_context
,
364 newkey
, &session_key
);
366 krb5_free_keyblock(telnet_context
, newkey
);
369 krb5_free_cred_contents(telnet_context
, &creds
);
370 krb5_free_creds(telnet_context
, new_creds
);
374 (void) printf(gettext(
375 "telnet: Kerberos V5: mk_req failed (%s)\r\n"),
376 error_message(retval
));
380 if ((auth_sendname((uchar_t
*)UserNameRequested
,
381 strlen(UserNameRequested
))) == NULL
) {
383 (void) printf(gettext(
384 "telnet: Not enough room for user name\r\n"));
387 retval
= krb5_send_data(ap
, KRB_AUTH
, auth
.data
, auth
.length
);
388 if (auth_debug_mode
&& retval
) {
389 (void) printf(gettext(
390 "telnet: Sent Kerberos V5 credentials to server\r\n"));
391 } else if (auth_debug_mode
) {
392 (void) printf(gettext(
393 "telnet: Not enough room for authentication data\r\n"));
400 kerberos5_reply(Authenticator
*ap
, unsigned char *data
, int cnt
)
403 static boolean_t mutual_complete
= B_FALSE
;
410 (void) printf(gettext(
411 "[ Kerberos V5 refuses authentication because "
412 "%.*s ]\r\n"), cnt
, data
);
414 (void) printf(gettext(
415 "[ Kerberos V5 refuses authentication ]\r\n"));
419 if (!mutual_complete
) {
420 if ((ap
->way
& AUTH_HOW_MASK
) == AUTH_HOW_MUTUAL
) {
421 (void) printf(gettext(
422 "[ Kerberos V5 accepted you, but didn't "
423 "provide mutual authentication! ]\r\n"));
431 skey
.data
= session_key
->contents
;
432 encrypt_session_key(&skey
);
436 (void) printf(gettext(
437 "[ Kerberos V5 accepts you as ``%.*s'' ]\r\n"),
440 (void) printf(gettext(
441 "[ Kerberos V5 accepts you ]\r\n"));
442 auth_finished(ap
, AUTH_USER
);
444 if (forward_flags
& OPTS_FORWARD_CREDS
)
445 kerberos5_forward(ap
);
449 if ((ap
->way
& AUTH_HOW_MASK
) == AUTH_HOW_MUTUAL
) {
450 /* the rest of the reply should contain a krb_ap_rep */
451 krb5_ap_rep_enc_part
*reply
;
453 krb5_error_code retval
;
456 inbuf
.data
= (char *)data
;
458 retval
= krb5_rd_rep(telnet_context
, auth_context
,
461 (void) printf(gettext(
462 "[ Mutual authentication failed: "
463 "%s ]\r\n"), error_message(retval
));
467 krb5_free_ap_rep_enc_part(telnet_context
, reply
);
472 skey
.data
= session_key
->contents
;
473 encrypt_session_key(&skey
);
475 mutual_complete
= B_TRUE
;
478 case KRB_FORWARD_ACCEPT
:
479 (void) printf(gettext(
480 "[ Kerberos V5 accepted forwarded credentials ]\r\n"));
482 case KRB_FORWARD_REJECT
:
483 (void) printf(gettext(
484 "[ Kerberos V5 refuses forwarded credentials because "
485 "%.*s ]\r\n"), cnt
, data
);
489 (void) printf(gettext(
490 "Unknown Kerberos option %d\r\n"), data
[-1]);
497 kerberos5_status(Authenticator
*ap
, char *name
, int level
)
499 if (level
< AUTH_USER
)
502 if (UserNameRequested
&& krb5_kuserok(telnet_context
,
503 ticket
->enc_part2
->client
, UserNameRequested
)) {
505 /* the name buffer comes from telnetd/telnetd{-ktd}.c */
506 (void) strncpy(name
, UserNameRequested
, MAXNAMELEN
);
507 name
[MAXNAMELEN
-1] = '\0';
513 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len); }
514 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len); }
517 * Used with the set opt command to print suboptions
520 kerberos5_printsub(unsigned char *data
, int cnt
, unsigned char *buf
, int buflen
)
522 char lbuf
[AUTH_LBUF_BUFSIZ
];
525 buf
[buflen
-1] = '\0'; /* make sure its NULL terminated */
529 case KRB_REJECT
: /* Rejected (reason might follow) */
530 (void) strncpy((char *)buf
, " REJECT ", buflen
);
533 case KRB_ACCEPT
: /* Accepted (name might follow) */
534 (void) strncpy((char *)buf
, " ACCEPT ", buflen
);
539 ADDC(buf
, buflen
, '"');
540 for (i
= 4; i
< cnt
; i
++)
541 ADDC(buf
, buflen
, data
[i
]);
542 ADDC(buf
, buflen
, '"');
543 ADDC(buf
, buflen
, '\0');
546 case KRB_AUTH
: /* Authentication data follows */
547 (void) strncpy((char *)buf
, " AUTH", buflen
);
551 (void) strncpy((char *)buf
, " RESPONSE", buflen
);
554 case KRB_FORWARD
: /* Forwarded credentials follow */
555 (void) strncpy((char *)buf
, " FORWARD", buflen
);
558 case KRB_FORWARD_ACCEPT
: /* Forwarded credentials accepted */
559 (void) strncpy((char *)buf
, " FORWARD_ACCEPT", buflen
);
562 case KRB_FORWARD_REJECT
: /* Forwarded credentials rejected */
563 /* (reason might follow) */
564 (void) strncpy((char *)buf
, " FORWARD_REJECT", buflen
);
568 (void) snprintf(lbuf
, AUTH_LBUF_BUFSIZ
,
569 gettext(" %d (unknown)"),
571 (void) strncpy((char *)buf
, lbuf
, buflen
);
574 for (i
= 4; i
< cnt
; i
++) {
575 (void) snprintf(lbuf
, AUTH_LBUF_BUFSIZ
, " %d", data
[i
]);
576 (void) strncpy((char *)buf
, lbuf
, buflen
);
584 krb5_profile_get_options(char *host
, char *realm
,
585 profile_options_boolean
*optionsp
)
587 char **realms
= NULL
;
588 krb5_error_code err
= 0;
590 if (!telnet_context
) {
591 err
= krb5_init_context(&telnet_context
);
593 (void) fprintf(stderr
, gettext(
594 "Error initializing Kerberos 5 library: %s\n"),
600 if ((realmdef
[1] = realm
) == NULL
) {
601 err
= krb5_get_host_realm(telnet_context
, host
, &realms
);
603 (void) fprintf(stderr
, gettext(
604 "Error getting Kerberos 5 realms for: %s (%s)\n"),
605 host
, error_message(err
));
608 realmdef
[1] = realms
[0];
611 profile_get_options_boolean(telnet_context
->profile
,
613 profile_get_options_boolean(telnet_context
->profile
,
618 kerberos5_forward(Authenticator
*ap
)
620 krb5_error_code retval
;
622 krb5_principal client
= 0;
623 krb5_principal server
= 0;
624 krb5_data forw_creds
;
628 if ((retval
= krb5_cc_default(telnet_context
, &ccache
))) {
630 (void) printf(gettext(
631 "Kerberos V5: could not get default ccache - %s\r\n"),
632 error_message(retval
));
636 retval
= krb5_cc_get_principal(telnet_context
, ccache
, &client
);
639 (void) printf(gettext(
640 "Kerberos V5: could not get default "
641 "principal - %s\r\n"), error_message(retval
));
645 retval
= krb5_sname_to_principal(telnet_context
, RemoteHostName
,
646 "host", KRB5_NT_SRV_HST
, &server
);
649 (void) printf(gettext(
650 "Kerberos V5: could not make server "
651 "principal - %s\r\n"), error_message(retval
));
655 retval
= krb5_auth_con_genaddrs(telnet_context
, auth_context
, net
,
656 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR
);
659 (void) printf(gettext(
660 "Kerberos V5: could not gen local full "
661 "address - %s\r\n"), error_message(retval
));
665 retval
= krb5_fwd_tgt_creds(telnet_context
, auth_context
, 0, client
,
666 server
, ccache
, forward_flags
& OPTS_FORWARDABLE_CREDS
,
670 (void) printf(gettext(
671 "Kerberos V5: error getting forwarded "
672 "creds - %s\r\n"), error_message(retval
));
676 /* Send forwarded credentials */
677 if (!krb5_send_data(ap
, KRB_FORWARD
, forw_creds
.data
,
678 forw_creds
.length
)) {
680 (void) printf(gettext(
681 "Not enough room for authentication data\r\n"));
682 } else if (auth_debug_mode
)
683 (void) printf(gettext(
684 "Forwarded local Kerberos V5 credentials to server\r\n"));
687 krb5_free_principal(telnet_context
, client
);
689 krb5_free_principal(telnet_context
, server
);
691 free(forw_creds
.data
);
693 krb5_cc_close(telnet_context
, ccache
);