1*cc17ee2eSpgoyette /*	$NetBSD: gss-serv-krb5.c,v 1.12 2019/01/27 02:08:33 pgoyette Exp $	*/
20357011aSchristos /* $OpenBSD: gss-serv-krb5.c,v 1.9 2018/07/09 21:37:55 markus Exp $ */
3ca32bd8dSchristos 
4ca32bd8dSchristos /*
5ca32bd8dSchristos  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
6ca32bd8dSchristos  *
7ca32bd8dSchristos  * Redistribution and use in source and binary forms, with or without
8ca32bd8dSchristos  * modification, are permitted provided that the following conditions
9ca32bd8dSchristos  * are met:
10ca32bd8dSchristos  * 1. Redistributions of source code must retain the above copyright
11ca32bd8dSchristos  *    notice, this list of conditions and the following disclaimer.
12ca32bd8dSchristos  * 2. Redistributions in binary form must reproduce the above copyright
13ca32bd8dSchristos  *    notice, this list of conditions and the following disclaimer in the
14ca32bd8dSchristos  *    documentation and/or other materials provided with the distribution.
15ca32bd8dSchristos  *
16ca32bd8dSchristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
17ca32bd8dSchristos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18ca32bd8dSchristos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19ca32bd8dSchristos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20ca32bd8dSchristos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21ca32bd8dSchristos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22ca32bd8dSchristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23ca32bd8dSchristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24ca32bd8dSchristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25ca32bd8dSchristos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26ca32bd8dSchristos  */
27ca32bd8dSchristos 
28313c6c94Schristos #include "includes.h"
29*cc17ee2eSpgoyette __RCSID("$NetBSD: gss-serv-krb5.c,v 1.12 2019/01/27 02:08:33 pgoyette Exp $");
30ca32bd8dSchristos #ifdef GSSAPI
31ca32bd8dSchristos #ifdef KRB5
32ca32bd8dSchristos 
33ca32bd8dSchristos #include <sys/types.h>
34ca32bd8dSchristos 
35313c6c94Schristos #include <stdarg.h>
36313c6c94Schristos #include <string.h>
37313c6c94Schristos 
38ca32bd8dSchristos #include "xmalloc.h"
390357011aSchristos #include "sshkey.h"
40ca32bd8dSchristos #include "hostfile.h"
41ca32bd8dSchristos #include "auth.h"
42ca32bd8dSchristos #include "log.h"
43e8f89eebSchristos #include "misc.h"
44313c6c94Schristos #include "servconf.h"
450357011aSchristos 
46ca32bd8dSchristos #include "ssh-gss.h"
47ca32bd8dSchristos 
48313c6c94Schristos extern ServerOptions options;
49313c6c94Schristos 
504ec0b1fcSchristos #include <krb5.h>
5106ba98a8Selric #include <gssapi/gssapi_krb5.h>
52ca32bd8dSchristos 
53ca32bd8dSchristos static krb5_context krb_context = NULL;
54ca32bd8dSchristos 
55ca32bd8dSchristos /* Initialise the krb5 library, for the stuff that GSSAPI won't do */
56ca32bd8dSchristos 
57ca32bd8dSchristos static int
ssh_gssapi_krb5_init(void)58ca32bd8dSchristos ssh_gssapi_krb5_init(void)
59ca32bd8dSchristos {
60ca32bd8dSchristos 	krb5_error_code problem;
61ca32bd8dSchristos 
62ca32bd8dSchristos 	if (krb_context != NULL)
63ca32bd8dSchristos 		return 1;
64ca32bd8dSchristos 
65ca32bd8dSchristos 	problem = krb5_init_context(&krb_context);
66ca32bd8dSchristos 	if (problem) {
67ca32bd8dSchristos 		logit("Cannot initialize krb5 context");
68ca32bd8dSchristos 		return 0;
69ca32bd8dSchristos 	}
70313c6c94Schristos #ifdef isneeded
71ca32bd8dSchristos 	krb5_init_ets(krb_context);
72313c6c94Schristos #endif
73ca32bd8dSchristos 
74ca32bd8dSchristos 	return 1;
75ca32bd8dSchristos }
76ca32bd8dSchristos 
77ca32bd8dSchristos /* Check if this user is OK to login. This only works with krb5 - other
78ca32bd8dSchristos  * GSSAPI mechanisms will need their own.
79ca32bd8dSchristos  * Returns true if the user is OK to log in, otherwise returns 0
80ca32bd8dSchristos  */
81ca32bd8dSchristos 
82ca32bd8dSchristos static int
ssh_gssapi_krb5_userok(ssh_gssapi_client * client,char * name)83ca32bd8dSchristos ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
84ca32bd8dSchristos {
85ca32bd8dSchristos 	krb5_principal princ;
86ca32bd8dSchristos 	int retval;
874ec0b1fcSchristos 	const char *errmsg;
88ca32bd8dSchristos 
89ca32bd8dSchristos 	if (ssh_gssapi_krb5_init() == 0)
90ca32bd8dSchristos 		return 0;
91ca32bd8dSchristos 
92ca32bd8dSchristos 	if ((retval = krb5_parse_name(krb_context, client->exportedname.value,
93ca32bd8dSchristos 	    &princ))) {
944ec0b1fcSchristos 		errmsg = krb5_get_error_message(krb_context, retval);
954ec0b1fcSchristos 		logit("krb5_parse_name(): %.100s", errmsg);
964ec0b1fcSchristos 		krb5_free_error_message(krb_context, errmsg);
97ca32bd8dSchristos 		return 0;
98ca32bd8dSchristos 	}
99ca32bd8dSchristos 	if (krb5_kuserok(krb_context, princ, name)) {
100ca32bd8dSchristos 		retval = 1;
101ca32bd8dSchristos 		logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
102ca32bd8dSchristos 		    name, (char *)client->displayname.value);
103ca32bd8dSchristos 	} else
104ca32bd8dSchristos 		retval = 0;
105ca32bd8dSchristos 
106ca32bd8dSchristos 	krb5_free_principal(krb_context, princ);
107ca32bd8dSchristos 	return retval;
108ca32bd8dSchristos }
109ca32bd8dSchristos 
110ca32bd8dSchristos 
111ca32bd8dSchristos /* This writes out any forwarded credentials from the structure populated
112ca32bd8dSchristos  * during userauth. Called after we have setuid to the user */
113ca32bd8dSchristos 
114ca32bd8dSchristos static void
ssh_gssapi_krb5_storecreds(ssh_gssapi_client * client)115ca32bd8dSchristos ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
116ca32bd8dSchristos {
117ca32bd8dSchristos 	krb5_ccache ccache;
118ca32bd8dSchristos 	krb5_error_code problem;
119ca32bd8dSchristos 	krb5_principal princ;
120ca32bd8dSchristos 	OM_uint32 maj_status, min_status;
1214ec0b1fcSchristos 	size_t len;
1224ec0b1fcSchristos 	const char *errmsg;
123ca32bd8dSchristos 
124ca32bd8dSchristos 	if (client->creds == NULL) {
125ca32bd8dSchristos 		debug("No credentials stored");
126ca32bd8dSchristos 		return;
127ca32bd8dSchristos 	}
128ca32bd8dSchristos 
129ca32bd8dSchristos 	if (ssh_gssapi_krb5_init() == 0)
130ca32bd8dSchristos 		return;
131ca32bd8dSchristos 
1324ec0b1fcSchristos 	if ((problem = krb5_cc_new_unique(krb_context, krb5_fcc_ops.prefix,
1334ec0b1fcSchristos 	    NULL, &ccache)) != 0) {
1344ec0b1fcSchristos 		errmsg = krb5_get_error_message(krb_context, problem);
1354ec0b1fcSchristos 		logit("krb5_cc_new_unique(): %.100s", errmsg);
1364ec0b1fcSchristos 		krb5_free_error_message(krb_context, errmsg);
137ca32bd8dSchristos 		return;
138ca32bd8dSchristos 	}
139ca32bd8dSchristos 
140ca32bd8dSchristos 	if ((problem = krb5_parse_name(krb_context,
141ca32bd8dSchristos 	    client->exportedname.value, &princ))) {
1424ec0b1fcSchristos 		errmsg = krb5_get_error_message(krb_context, problem);
1434ec0b1fcSchristos 		logit("krb5_parse_name(): %.100s", errmsg);
1444ec0b1fcSchristos 		krb5_free_error_message(krb_context, errmsg);
145ca32bd8dSchristos 		krb5_cc_destroy(krb_context, ccache);
146ca32bd8dSchristos 		return;
147ca32bd8dSchristos 	}
148ca32bd8dSchristos 
149ca32bd8dSchristos 	if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
1504ec0b1fcSchristos 		errmsg = krb5_get_error_message(krb_context, problem);
1514ec0b1fcSchristos 		logit("krb5_cc_initialize(): %.100s", errmsg);
1524ec0b1fcSchristos 		krb5_free_error_message(krb_context, errmsg);
153ca32bd8dSchristos 		krb5_free_principal(krb_context, princ);
154ca32bd8dSchristos 		krb5_cc_destroy(krb_context, ccache);
155ca32bd8dSchristos 		return;
156ca32bd8dSchristos 	}
157ca32bd8dSchristos 
158ca32bd8dSchristos 	krb5_free_principal(krb_context, princ);
159ca32bd8dSchristos 
160ca32bd8dSchristos 	if ((maj_status = gss_krb5_copy_ccache(&min_status,
161ca32bd8dSchristos 	    client->creds, ccache))) {
162ca32bd8dSchristos 		logit("gss_krb5_copy_ccache() failed");
163ca32bd8dSchristos 		krb5_cc_destroy(krb_context, ccache);
164ca32bd8dSchristos 		return;
165ca32bd8dSchristos 	}
166ca32bd8dSchristos 
167ca32bd8dSchristos 	client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
1688983daf9Schristos 	client->store.envvar = __UNCONST("KRB5CCNAME");
169313c6c94Schristos 	len = strlen(client->store.filename) + 6;
170313c6c94Schristos 	client->store.envval = xmalloc(len);
171313c6c94Schristos 	snprintf(client->store.envval, len, "FILE:%s", client->store.filename);
172313c6c94Schristos 
173313c6c94Schristos #ifdef USE_PAM
174313c6c94Schristos 	if (options.use_pam)
175313c6c94Schristos 		do_pam_putenv(client->store.envvar, client->store.envval);
176313c6c94Schristos #endif
177ca32bd8dSchristos 
178ca32bd8dSchristos 	krb5_cc_close(krb_context, ccache);
179ca32bd8dSchristos 
180ca32bd8dSchristos 	return;
181ca32bd8dSchristos }
182ca32bd8dSchristos 
183ca32bd8dSchristos ssh_gssapi_mech gssapi_kerberos_mech = {
184ca32bd8dSchristos 	"toWM5Slw5Ew8Mqkay+al2g==",
185ca32bd8dSchristos 	"Kerberos",
1868983daf9Schristos 	{9, __UNCONST("\x2A\x86\x48\x86\xF7\x12\x01\x02\x02")},
187ca32bd8dSchristos 	NULL,
188ca32bd8dSchristos 	&ssh_gssapi_krb5_userok,
189ca32bd8dSchristos 	NULL,
190ca32bd8dSchristos 	&ssh_gssapi_krb5_storecreds
191ca32bd8dSchristos };
192ca32bd8dSchristos 
193ca32bd8dSchristos #endif /* KRB5 */
194ca32bd8dSchristos 
195ca32bd8dSchristos #endif /* GSSAPI */
196