xref: /freebsd/crypto/openssh/auth-krb5.c (revision 19261079b74319502c6ffa1249920079f0f69a72)
1*19261079SEd Maste /* $OpenBSD: auth-krb5.c,v 1.24 2021/04/03 06:18:40 djm Exp $ */
2fe5fd017SMark Murray /*
3fe5fd017SMark Murray  *    Kerberos v5 authentication and ticket-passing routines.
480628bacSDag-Erling Smørgrav  *
5acc1a9efSDag-Erling Smørgrav  * From: FreeBSD: src/crypto/openssh/auth-krb5.c,v 1.6 2001/02/13 16:58:04 assar
680628bacSDag-Erling Smørgrav  */
780628bacSDag-Erling Smørgrav /*
880628bacSDag-Erling Smørgrav  * Copyright (c) 2002 Daniel Kouril.  All rights reserved.
980628bacSDag-Erling Smørgrav  *
1080628bacSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
1180628bacSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
1280628bacSDag-Erling Smørgrav  * are met:
1380628bacSDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
1480628bacSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
1580628bacSDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
1680628bacSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
1780628bacSDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
1880628bacSDag-Erling Smørgrav  *
1980628bacSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2080628bacSDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2180628bacSDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2280628bacSDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2380628bacSDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2480628bacSDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2580628bacSDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2680628bacSDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2780628bacSDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2880628bacSDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29fe5fd017SMark Murray  */
30fe5fd017SMark Murray 
31fe5fd017SMark Murray #include "includes.h"
32af12a3e7SDag-Erling Smørgrav 
33333ee039SDag-Erling Smørgrav #include <sys/types.h>
34333ee039SDag-Erling Smørgrav #include <pwd.h>
35333ee039SDag-Erling Smørgrav #include <stdarg.h>
36333ee039SDag-Erling Smørgrav 
37333ee039SDag-Erling Smørgrav #include "xmalloc.h"
38fe5fd017SMark Murray #include "ssh.h"
39fe5fd017SMark Murray #include "packet.h"
40af12a3e7SDag-Erling Smørgrav #include "log.h"
41190cef3dSDag-Erling Smørgrav #include "sshbuf.h"
42190cef3dSDag-Erling Smørgrav #include "sshkey.h"
43a0ee8cc6SDag-Erling Smørgrav #include "misc.h"
44af12a3e7SDag-Erling Smørgrav #include "servconf.h"
45af12a3e7SDag-Erling Smørgrav #include "uidswap.h"
46333ee039SDag-Erling Smørgrav #include "hostfile.h"
47af12a3e7SDag-Erling Smørgrav #include "auth.h"
48fe5fd017SMark Murray 
49fe5fd017SMark Murray #ifdef KRB5
50333ee039SDag-Erling Smørgrav #include <errno.h>
51333ee039SDag-Erling Smørgrav #include <unistd.h>
52333ee039SDag-Erling Smørgrav #include <string.h>
53af12a3e7SDag-Erling Smørgrav #include <krb5.h>
54fe5fd017SMark Murray 
55af12a3e7SDag-Erling Smørgrav extern ServerOptions	 options;
56fe5fd017SMark Murray 
57af12a3e7SDag-Erling Smørgrav static int
krb5_init(void * context)58af12a3e7SDag-Erling Smørgrav krb5_init(void *context)
59af12a3e7SDag-Erling Smørgrav {
60af12a3e7SDag-Erling Smørgrav 	Authctxt *authctxt = (Authctxt *)context;
61af12a3e7SDag-Erling Smørgrav 	krb5_error_code problem;
62af12a3e7SDag-Erling Smørgrav 
63af12a3e7SDag-Erling Smørgrav 	if (authctxt->krb5_ctx == NULL) {
64af12a3e7SDag-Erling Smørgrav 		problem = krb5_init_context(&authctxt->krb5_ctx);
65af12a3e7SDag-Erling Smørgrav 		if (problem)
66af12a3e7SDag-Erling Smørgrav 			return (problem);
67af12a3e7SDag-Erling Smørgrav 	}
68af12a3e7SDag-Erling Smørgrav 	return (0);
69af12a3e7SDag-Erling Smørgrav }
70af12a3e7SDag-Erling Smørgrav 
71fe5fd017SMark Murray int
auth_krb5_password(Authctxt * authctxt,const char * password)72af12a3e7SDag-Erling Smørgrav auth_krb5_password(Authctxt *authctxt, const char *password)
73fe5fd017SMark Murray {
74989dd127SDag-Erling Smørgrav #ifndef HEIMDAL
75989dd127SDag-Erling Smørgrav 	krb5_creds creds;
76989dd127SDag-Erling Smørgrav 	krb5_principal server;
77989dd127SDag-Erling Smørgrav #endif
78fe5fd017SMark Murray 	krb5_error_code problem;
79cf2b5f3bSDag-Erling Smørgrav 	krb5_ccache ccache = NULL;
805962c0e9SDag-Erling Smørgrav 	int len;
81b15c8340SDag-Erling Smørgrav 	char *client, *platform_client;
82e4a9863fSDag-Erling Smørgrav 	const char *errmsg;
83b15c8340SDag-Erling Smørgrav 
84b15c8340SDag-Erling Smørgrav 	/* get platform-specific kerberos client principal name (if it exists) */
85b15c8340SDag-Erling Smørgrav 	platform_client = platform_krb5_get_principal_name(authctxt->pw->pw_name);
86b15c8340SDag-Erling Smørgrav 	client = platform_client ? platform_client : authctxt->pw->pw_name;
87fe5fd017SMark Murray 
88af12a3e7SDag-Erling Smørgrav 	temporarily_use_uid(authctxt->pw);
89af12a3e7SDag-Erling Smørgrav 
90af12a3e7SDag-Erling Smørgrav 	problem = krb5_init(authctxt);
91fe5fd017SMark Murray 	if (problem)
92fe5fd017SMark Murray 		goto out;
93fe5fd017SMark Murray 
94b15c8340SDag-Erling Smørgrav 	problem = krb5_parse_name(authctxt->krb5_ctx, client,
95af12a3e7SDag-Erling Smørgrav 		    &authctxt->krb5_user);
96af12a3e7SDag-Erling Smørgrav 	if (problem)
97fe5fd017SMark Murray 		goto out;
98fe5fd017SMark Murray 
99989dd127SDag-Erling Smørgrav #ifdef HEIMDAL
100e4a9863fSDag-Erling Smørgrav # ifdef HAVE_KRB5_CC_NEW_UNIQUE
101e4a9863fSDag-Erling Smørgrav 	problem = krb5_cc_new_unique(authctxt->krb5_ctx,
102e4a9863fSDag-Erling Smørgrav 	    krb5_mcc_ops.prefix, NULL, &ccache);
103e4a9863fSDag-Erling Smørgrav # else
104cf2b5f3bSDag-Erling Smørgrav 	problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache);
105e4a9863fSDag-Erling Smørgrav # endif
106af12a3e7SDag-Erling Smørgrav 	if (problem)
107fe5fd017SMark Murray 		goto out;
108fe5fd017SMark Murray 
109cf2b5f3bSDag-Erling Smørgrav 	problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache,
110cf2b5f3bSDag-Erling Smørgrav 		authctxt->krb5_user);
111af12a3e7SDag-Erling Smørgrav 	if (problem)
112fe5fd017SMark Murray 		goto out;
113fe5fd017SMark Murray 
114af12a3e7SDag-Erling Smørgrav 	restore_uid();
115cf2b5f3bSDag-Erling Smørgrav 
116af12a3e7SDag-Erling Smørgrav 	problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user,
117cf2b5f3bSDag-Erling Smørgrav 	    ccache, password, 1, NULL);
118cf2b5f3bSDag-Erling Smørgrav 
119af12a3e7SDag-Erling Smørgrav 	temporarily_use_uid(authctxt->pw);
120af12a3e7SDag-Erling Smørgrav 
121af12a3e7SDag-Erling Smørgrav 	if (problem)
122fe5fd017SMark Murray 		goto out;
1231ec0d754SDag-Erling Smørgrav 
124e4a9863fSDag-Erling Smørgrav # ifdef HAVE_KRB5_CC_NEW_UNIQUE
125e4a9863fSDag-Erling Smørgrav 	problem = krb5_cc_new_unique(authctxt->krb5_ctx,
126e4a9863fSDag-Erling Smørgrav 	    krb5_fcc_ops.prefix, NULL, &authctxt->krb5_fwd_ccache);
127e4a9863fSDag-Erling Smørgrav # else
128cf2b5f3bSDag-Erling Smørgrav 	problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops,
129cf2b5f3bSDag-Erling Smørgrav 	    &authctxt->krb5_fwd_ccache);
130e4a9863fSDag-Erling Smørgrav # endif
131cf2b5f3bSDag-Erling Smørgrav 	if (problem)
132cf2b5f3bSDag-Erling Smørgrav 		goto out;
133cf2b5f3bSDag-Erling Smørgrav 
134cf2b5f3bSDag-Erling Smørgrav 	problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache,
135cf2b5f3bSDag-Erling Smørgrav 	    authctxt->krb5_fwd_ccache);
136cf2b5f3bSDag-Erling Smørgrav 	krb5_cc_destroy(authctxt->krb5_ctx, ccache);
137cf2b5f3bSDag-Erling Smørgrav 	ccache = NULL;
138cf2b5f3bSDag-Erling Smørgrav 	if (problem)
139cf2b5f3bSDag-Erling Smørgrav 		goto out;
140fe5fd017SMark Murray 
141989dd127SDag-Erling Smørgrav #else
142989dd127SDag-Erling Smørgrav 	problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds,
143989dd127SDag-Erling Smørgrav 	    authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL);
144989dd127SDag-Erling Smørgrav 	if (problem)
145989dd127SDag-Erling Smørgrav 		goto out;
146989dd127SDag-Erling Smørgrav 
147989dd127SDag-Erling Smørgrav 	problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL,
148989dd127SDag-Erling Smørgrav 	    KRB5_NT_SRV_HST, &server);
149989dd127SDag-Erling Smørgrav 	if (problem)
150989dd127SDag-Erling Smørgrav 		goto out;
151989dd127SDag-Erling Smørgrav 
152989dd127SDag-Erling Smørgrav 	restore_uid();
153989dd127SDag-Erling Smørgrav 	problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server,
154989dd127SDag-Erling Smørgrav 	    NULL, NULL, NULL);
155989dd127SDag-Erling Smørgrav 	krb5_free_principal(authctxt->krb5_ctx, server);
156989dd127SDag-Erling Smørgrav 	temporarily_use_uid(authctxt->pw);
157989dd127SDag-Erling Smørgrav 	if (problem)
158989dd127SDag-Erling Smørgrav 		goto out;
159989dd127SDag-Erling Smørgrav 
160f7167e0eSDag-Erling Smørgrav 	if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
161f7167e0eSDag-Erling Smørgrav 	    authctxt->pw->pw_name)) {
162989dd127SDag-Erling Smørgrav 		problem = -1;
163989dd127SDag-Erling Smørgrav 		goto out;
164989dd127SDag-Erling Smørgrav 	}
165989dd127SDag-Erling Smørgrav 
166*19261079SEd Maste 	problem = ssh_krb5_cc_gen(authctxt->krb5_ctx,
167*19261079SEd Maste 	    &authctxt->krb5_fwd_ccache);
168989dd127SDag-Erling Smørgrav 	if (problem)
169989dd127SDag-Erling Smørgrav 		goto out;
170989dd127SDag-Erling Smørgrav 
171*19261079SEd Maste 	problem = krb5_cc_initialize(authctxt->krb5_ctx,
172*19261079SEd Maste 	    authctxt->krb5_fwd_ccache, authctxt->krb5_user);
173989dd127SDag-Erling Smørgrav 	if (problem)
174989dd127SDag-Erling Smørgrav 		goto out;
175989dd127SDag-Erling Smørgrav 
176*19261079SEd Maste 	problem = krb5_cc_store_cred(authctxt->krb5_ctx,
177*19261079SEd Maste 	    authctxt->krb5_fwd_ccache, &creds);
178989dd127SDag-Erling Smørgrav 	if (problem)
179989dd127SDag-Erling Smørgrav 		goto out;
180989dd127SDag-Erling Smørgrav #endif
181989dd127SDag-Erling Smørgrav 
182af12a3e7SDag-Erling Smørgrav 	authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
183af12a3e7SDag-Erling Smørgrav 
1845962c0e9SDag-Erling Smørgrav 	len = strlen(authctxt->krb5_ticket_file) + 6;
1855962c0e9SDag-Erling Smørgrav 	authctxt->krb5_ccname = xmalloc(len);
1865962c0e9SDag-Erling Smørgrav 	snprintf(authctxt->krb5_ccname, len, "FILE:%s",
1875962c0e9SDag-Erling Smørgrav 	    authctxt->krb5_ticket_file);
1885962c0e9SDag-Erling Smørgrav 
189aa49c926SDag-Erling Smørgrav #ifdef USE_PAM
190aa49c926SDag-Erling Smørgrav 	if (options.use_pam)
191aa49c926SDag-Erling Smørgrav 		do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname);
192aa49c926SDag-Erling Smørgrav #endif
193aa49c926SDag-Erling Smørgrav 
194fe5fd017SMark Murray  out:
195af12a3e7SDag-Erling Smørgrav 	restore_uid();
196af12a3e7SDag-Erling Smørgrav 
197e4a9863fSDag-Erling Smørgrav 	free(platform_client);
198b15c8340SDag-Erling Smørgrav 
199af12a3e7SDag-Erling Smørgrav 	if (problem) {
200cf2b5f3bSDag-Erling Smørgrav 		if (ccache)
201cf2b5f3bSDag-Erling Smørgrav 			krb5_cc_destroy(authctxt->krb5_ctx, ccache);
202cf2b5f3bSDag-Erling Smørgrav 
203e4a9863fSDag-Erling Smørgrav 		if (authctxt->krb5_ctx != NULL && problem!=-1) {
204e4a9863fSDag-Erling Smørgrav 			errmsg = krb5_get_error_message(authctxt->krb5_ctx,
205e4a9863fSDag-Erling Smørgrav 			    problem);
206af12a3e7SDag-Erling Smørgrav 			debug("Kerberos password authentication failed: %s",
207e4a9863fSDag-Erling Smørgrav 			    errmsg);
208e4a9863fSDag-Erling Smørgrav 			krb5_free_error_message(authctxt->krb5_ctx, errmsg);
209e4a9863fSDag-Erling Smørgrav 		} else
210af12a3e7SDag-Erling Smørgrav 			debug("Kerberos password authentication failed: %d",
211af12a3e7SDag-Erling Smørgrav 			    problem);
212af12a3e7SDag-Erling Smørgrav 
213af12a3e7SDag-Erling Smørgrav 		krb5_cleanup_proc(authctxt);
214af12a3e7SDag-Erling Smørgrav 
215af12a3e7SDag-Erling Smørgrav 		if (options.kerberos_or_local_passwd)
216af12a3e7SDag-Erling Smørgrav 			return (-1);
217af12a3e7SDag-Erling Smørgrav 		else
218af12a3e7SDag-Erling Smørgrav 			return (0);
219af12a3e7SDag-Erling Smørgrav 	}
220b74df5b2SDag-Erling Smørgrav 	return (authctxt->valid ? 1 : 0);
221fe5fd017SMark Murray }
222fe5fd017SMark Murray 
223fe5fd017SMark Murray void
krb5_cleanup_proc(Authctxt * authctxt)2241ec0d754SDag-Erling Smørgrav krb5_cleanup_proc(Authctxt *authctxt)
225fe5fd017SMark Murray {
226af12a3e7SDag-Erling Smørgrav 	debug("krb5_cleanup_proc called");
227af12a3e7SDag-Erling Smørgrav 	if (authctxt->krb5_fwd_ccache) {
228af12a3e7SDag-Erling Smørgrav 		krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
229af12a3e7SDag-Erling Smørgrav 		authctxt->krb5_fwd_ccache = NULL;
230fe5fd017SMark Murray 	}
231af12a3e7SDag-Erling Smørgrav 	if (authctxt->krb5_user) {
232af12a3e7SDag-Erling Smørgrav 		krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
233af12a3e7SDag-Erling Smørgrav 		authctxt->krb5_user = NULL;
234fe5fd017SMark Murray 	}
235af12a3e7SDag-Erling Smørgrav 	if (authctxt->krb5_ctx) {
236af12a3e7SDag-Erling Smørgrav 		krb5_free_context(authctxt->krb5_ctx);
237af12a3e7SDag-Erling Smørgrav 		authctxt->krb5_ctx = NULL;
238af12a3e7SDag-Erling Smørgrav 	}
239fe5fd017SMark Murray }
240fe5fd017SMark Murray 
241d4ecd108SDag-Erling Smørgrav #ifndef HEIMDAL
242d4ecd108SDag-Erling Smørgrav krb5_error_code
ssh_krb5_cc_gen(krb5_context ctx,krb5_ccache * ccache)243d4ecd108SDag-Erling Smørgrav ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
244462c32cbSDag-Erling Smørgrav 	int tmpfd, ret, oerrno;
245d4ecd108SDag-Erling Smørgrav 	char ccname[40];
246d4ecd108SDag-Erling Smørgrav 	mode_t old_umask;
247d4ecd108SDag-Erling Smørgrav 
248d4ecd108SDag-Erling Smørgrav 	ret = snprintf(ccname, sizeof(ccname),
249d4ecd108SDag-Erling Smørgrav 	    "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
250b74df5b2SDag-Erling Smørgrav 	if (ret < 0 || (size_t)ret >= sizeof(ccname))
251d4ecd108SDag-Erling Smørgrav 		return ENOMEM;
252d4ecd108SDag-Erling Smørgrav 
253d4ecd108SDag-Erling Smørgrav 	old_umask = umask(0177);
254d4ecd108SDag-Erling Smørgrav 	tmpfd = mkstemp(ccname + strlen("FILE:"));
255462c32cbSDag-Erling Smørgrav 	oerrno = errno;
256d4ecd108SDag-Erling Smørgrav 	umask(old_umask);
257d4ecd108SDag-Erling Smørgrav 	if (tmpfd == -1) {
258462c32cbSDag-Erling Smørgrav 		logit("mkstemp(): %.100s", strerror(oerrno));
259462c32cbSDag-Erling Smørgrav 		return oerrno;
260d4ecd108SDag-Erling Smørgrav 	}
261d4ecd108SDag-Erling Smørgrav 
262d4ecd108SDag-Erling Smørgrav 	if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
263462c32cbSDag-Erling Smørgrav 		oerrno = errno;
264462c32cbSDag-Erling Smørgrav 		logit("fchmod(): %.100s", strerror(oerrno));
265d4ecd108SDag-Erling Smørgrav 		close(tmpfd);
266462c32cbSDag-Erling Smørgrav 		return oerrno;
267d4ecd108SDag-Erling Smørgrav 	}
268d4ecd108SDag-Erling Smørgrav 	close(tmpfd);
269d4ecd108SDag-Erling Smørgrav 
270d4ecd108SDag-Erling Smørgrav 	return (krb5_cc_resolve(ctx, ccname, ccache));
271d4ecd108SDag-Erling Smørgrav }
272d4ecd108SDag-Erling Smørgrav #endif /* !HEIMDAL */
273fe5fd017SMark Murray #endif /* KRB5 */
274