gss-serv-krb5.c revision 137015
1137015Sdes/*	$OpenBSD: gss-serv-krb5.c,v 1.3 2004/07/21 10:36:23 djm Exp $	*/
2124208Sdes
3124208Sdes/*
4124208Sdes * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
5124208Sdes *
6124208Sdes * Redistribution and use in source and binary forms, with or without
7124208Sdes * modification, are permitted provided that the following conditions
8124208Sdes * are met:
9124208Sdes * 1. Redistributions of source code must retain the above copyright
10124208Sdes *    notice, this list of conditions and the following disclaimer.
11124208Sdes * 2. Redistributions in binary form must reproduce the above copyright
12124208Sdes *    notice, this list of conditions and the following disclaimer in the
13124208Sdes *    documentation and/or other materials provided with the distribution.
14124208Sdes *
15124208Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
16124208Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17124208Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18124208Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19124208Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20124208Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21124208Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22124208Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23124208Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24124208Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25124208Sdes */
26124208Sdes
27124208Sdes#include "includes.h"
28124208Sdes
29124208Sdes#ifdef GSSAPI
30124208Sdes#ifdef KRB5
31124208Sdes
32124208Sdes#include "auth.h"
33124208Sdes#include "xmalloc.h"
34124208Sdes#include "log.h"
35124208Sdes#include "servconf.h"
36124208Sdes
37124208Sdes#include "ssh-gss.h"
38124208Sdes
39124208Sdesextern ServerOptions options;
40124208Sdes
41124208Sdes#ifdef HEIMDAL
42126274Sdes# include <krb5.h>
43124208Sdes#else
44126274Sdes# ifdef HAVE_GSSAPI_KRB5
45126274Sdes#  include <gssapi_krb5.h>
46126274Sdes# elif HAVE_GSSAPI_GSSAPI_KRB5
47126274Sdes#  include <gssapi/gssapi_krb5.h>
48126274Sdes# endif
49124208Sdes#endif
50124208Sdes
51124208Sdesstatic krb5_context krb_context = NULL;
52124208Sdes
53124208Sdes/* Initialise the krb5 library, for the stuff that GSSAPI won't do */
54124208Sdes
55126274Sdesstatic int
56137015Sdesssh_gssapi_krb5_init(void)
57124208Sdes{
58124208Sdes	krb5_error_code problem;
59124208Sdes
60124208Sdes	if (krb_context != NULL)
61124208Sdes		return 1;
62124208Sdes
63124208Sdes	problem = krb5_init_context(&krb_context);
64124208Sdes	if (problem) {
65124208Sdes		logit("Cannot initialize krb5 context");
66124208Sdes		return 0;
67124208Sdes	}
68128456Sdes#ifdef KRB5_INIT_ETS
69124208Sdes	krb5_init_ets(krb_context);
70128456Sdes#endif
71124208Sdes
72124208Sdes	return 1;
73124208Sdes}
74124208Sdes
75124208Sdes/* Check if this user is OK to login. This only works with krb5 - other
76124208Sdes * GSSAPI mechanisms will need their own.
77124208Sdes * Returns true if the user is OK to log in, otherwise returns 0
78124208Sdes */
79124208Sdes
80124208Sdesstatic int
81124208Sdesssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
82124208Sdes{
83124208Sdes	krb5_principal princ;
84124208Sdes	int retval;
85124208Sdes
86124208Sdes	if (ssh_gssapi_krb5_init() == 0)
87124208Sdes		return 0;
88124208Sdes
89124208Sdes	if ((retval = krb5_parse_name(krb_context, client->exportedname.value,
90124208Sdes	    &princ))) {
91124208Sdes		logit("krb5_parse_name(): %.100s",
92124208Sdes		    krb5_get_err_text(krb_context, retval));
93124208Sdes		return 0;
94124208Sdes	}
95124208Sdes	if (krb5_kuserok(krb_context, princ, name)) {
96124208Sdes		retval = 1;
97124208Sdes		logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
98124208Sdes		    name, (char *)client->displayname.value);
99124208Sdes	} else
100124208Sdes		retval = 0;
101124208Sdes
102124208Sdes	krb5_free_principal(krb_context, princ);
103124208Sdes	return retval;
104124208Sdes}
105124208Sdes
106124208Sdes
107124208Sdes/* This writes out any forwarded credentials from the structure populated
108124208Sdes * during userauth. Called after we have setuid to the user */
109124208Sdes
110124208Sdesstatic void
111124208Sdesssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
112124208Sdes{
113124208Sdes	krb5_ccache ccache;
114124208Sdes	krb5_error_code problem;
115124208Sdes	krb5_principal princ;
116124208Sdes	OM_uint32 maj_status, min_status;
117126274Sdes	int len;
118124208Sdes
119124208Sdes	if (client->creds == NULL) {
120124208Sdes		debug("No credentials stored");
121124208Sdes		return;
122124208Sdes	}
123124208Sdes
124124208Sdes	if (ssh_gssapi_krb5_init() == 0)
125124208Sdes		return;
126124208Sdes
127124208Sdes#ifdef HEIMDAL
128124208Sdes	if ((problem = krb5_cc_gen_new(krb_context, &krb5_fcc_ops, &ccache))) {
129124208Sdes		logit("krb5_cc_gen_new(): %.100s",
130124208Sdes		    krb5_get_err_text(krb_context, problem));
131124208Sdes		return;
132124208Sdes	}
133124208Sdes#else
134124208Sdes	{
135124208Sdes		int tmpfd;
136124208Sdes		char ccname[40];
137137015Sdes		mode_t old_umask;
138126274Sdes
139126274Sdes		snprintf(ccname, sizeof(ccname),
140124208Sdes		    "FILE:/tmp/krb5cc_%d_XXXXXX", geteuid());
141126274Sdes
142137015Sdes		old_umask = umask(0177);
143137015Sdes		tmpfd = mkstemp(ccname + strlen("FILE:"));
144137015Sdes		umask(old_umask);
145137015Sdes		if (tmpfd == -1) {
146124208Sdes			logit("mkstemp(): %.100s", strerror(errno));
147124208Sdes			problem = errno;
148124208Sdes			return;
149124208Sdes		}
150124208Sdes		if (fchmod(tmpfd, S_IRUSR | S_IWUSR) == -1) {
151124208Sdes			logit("fchmod(): %.100s", strerror(errno));
152124208Sdes			close(tmpfd);
153124208Sdes			problem = errno;
154124208Sdes			return;
155124208Sdes		}
156124208Sdes		close(tmpfd);
157124208Sdes		if ((problem = krb5_cc_resolve(krb_context, ccname, &ccache))) {
158124208Sdes			logit("krb5_cc_resolve(): %.100s",
159124208Sdes			    krb5_get_err_text(krb_context, problem));
160124208Sdes			return;
161124208Sdes		}
162124208Sdes	}
163124208Sdes#endif	/* #ifdef HEIMDAL */
164124208Sdes
165126274Sdes	if ((problem = krb5_parse_name(krb_context,
166124208Sdes	    client->exportedname.value, &princ))) {
167124208Sdes		logit("krb5_parse_name(): %.100s",
168124208Sdes		    krb5_get_err_text(krb_context, problem));
169124208Sdes		krb5_cc_destroy(krb_context, ccache);
170124208Sdes		return;
171124208Sdes	}
172124208Sdes
173124208Sdes	if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
174124208Sdes		logit("krb5_cc_initialize(): %.100s",
175124208Sdes		    krb5_get_err_text(krb_context, problem));
176124208Sdes		krb5_free_principal(krb_context, princ);
177124208Sdes		krb5_cc_destroy(krb_context, ccache);
178124208Sdes		return;
179124208Sdes	}
180124208Sdes
181124208Sdes	krb5_free_principal(krb_context, princ);
182124208Sdes
183126274Sdes	if ((maj_status = gss_krb5_copy_ccache(&min_status,
184124208Sdes	    client->creds, ccache))) {
185124208Sdes		logit("gss_krb5_copy_ccache() failed");
186124208Sdes		krb5_cc_destroy(krb_context, ccache);
187124208Sdes		return;
188124208Sdes	}
189124208Sdes
190124208Sdes	client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
191124208Sdes	client->store.envvar = "KRB5CCNAME";
192126274Sdes	len = strlen(client->store.filename) + 6;
193126274Sdes	client->store.envval = xmalloc(len);
194126274Sdes	snprintf(client->store.envval, len, "FILE:%s", client->store.filename);
195124208Sdes
196124208Sdes#ifdef USE_PAM
197124208Sdes	if (options.use_pam)
198126274Sdes		do_pam_putenv(client->store.envvar, client->store.envval);
199124208Sdes#endif
200124208Sdes
201124208Sdes	krb5_cc_close(krb_context, ccache);
202124208Sdes
203124208Sdes	return;
204124208Sdes}
205124208Sdes
206124208Sdesssh_gssapi_mech gssapi_kerberos_mech = {
207124208Sdes	"toWM5Slw5Ew8Mqkay+al2g==",
208124208Sdes	"Kerberos",
209124208Sdes	{9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"},
210124208Sdes	NULL,
211124208Sdes	&ssh_gssapi_krb5_userok,
212124208Sdes	NULL,
213124208Sdes	&ssh_gssapi_krb5_storecreds
214124208Sdes};
215124208Sdes
216124208Sdes#endif /* KRB5 */
217124208Sdes
218124208Sdes#endif /* GSSAPI */
219