1*d91f98a8Spgoyette /* $NetBSD: gss-serv-krb5.c,v 1.12 2019/01/27 02:08:33 pgoyette Exp $ */
255a4608bSchristos /* $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*d91f98a8Spgoyette __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"
3955a4608bSchristos #include "sshkey.h"
40ca32bd8dSchristos #include "hostfile.h"
41ca32bd8dSchristos #include "auth.h"
42ca32bd8dSchristos #include "log.h"
438a4530f9Schristos #include "misc.h"
44313c6c94Schristos #include "servconf.h"
4555a4608bSchristos
46ca32bd8dSchristos #include "ssh-gss.h"
47ca32bd8dSchristos
48313c6c94Schristos extern ServerOptions options;
49313c6c94Schristos
5000a838c4Schristos #include <krb5.h>
51f8f7efe3Selric #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;
8700a838c4Schristos 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))) {
9400a838c4Schristos errmsg = krb5_get_error_message(krb_context, retval);
9500a838c4Schristos logit("krb5_parse_name(): %.100s", errmsg);
9600a838c4Schristos 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;
12100a838c4Schristos size_t len;
12200a838c4Schristos 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
13200a838c4Schristos if ((problem = krb5_cc_new_unique(krb_context, krb5_fcc_ops.prefix,
13300a838c4Schristos NULL, &ccache)) != 0) {
13400a838c4Schristos errmsg = krb5_get_error_message(krb_context, problem);
13500a838c4Schristos logit("krb5_cc_new_unique(): %.100s", errmsg);
13600a838c4Schristos krb5_free_error_message(krb_context, errmsg);
137ca32bd8dSchristos return;
138ca32bd8dSchristos }
139ca32bd8dSchristos
140ca32bd8dSchristos if ((problem = krb5_parse_name(krb_context,
141ca32bd8dSchristos client->exportedname.value, &princ))) {
14200a838c4Schristos errmsg = krb5_get_error_message(krb_context, problem);
14300a838c4Schristos logit("krb5_parse_name(): %.100s", errmsg);
14400a838c4Schristos 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))) {
15000a838c4Schristos errmsg = krb5_get_error_message(krb_context, problem);
15100a838c4Schristos logit("krb5_cc_initialize(): %.100s", errmsg);
15200a838c4Schristos 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));
168185c8f97Schristos 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",
186185c8f97Schristos {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