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