diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | auth.h | 3 | ||||
-rw-r--r-- | auth2-gss.c | 243 | ||||
-rw-r--r-- | auth2.c | 18 | ||||
-rw-r--r-- | compat.c | 8 | ||||
-rw-r--r-- | compat.h | 3 | ||||
-rw-r--r-- | gss-genr.c | 256 | ||||
-rw-r--r-- | gss-serv-krb5.c | 168 | ||||
-rw-r--r-- | gss-serv.c | 291 | ||||
-rw-r--r-- | monitor.c | 92 | ||||
-rw-r--r-- | monitor.h | 5 | ||||
-rw-r--r-- | monitor_wrap.c | 73 | ||||
-rw-r--r-- | monitor_wrap.h | 10 | ||||
-rw-r--r-- | readconf.c | 26 | ||||
-rw-r--r-- | readconf.h | 4 | ||||
-rw-r--r-- | servconf.c | 24 | ||||
-rw-r--r-- | servconf.h | 4 | ||||
-rw-r--r-- | session.c | 31 | ||||
-rw-r--r-- | session.h | 5 | ||||
-rw-r--r-- | ssh-gss.h | 109 | ||||
-rw-r--r-- | ssh_config.5 | 14 | ||||
-rw-r--r-- | sshconnect2.c | 252 | ||||
-rw-r--r-- | sshd_config | 6 | ||||
-rw-r--r-- | sshd_config.5 | 15 |
24 files changed, 1646 insertions, 24 deletions
@@ -2,6 +2,14 @@ | |||
2 | - (djm) Bug #629: Mark ssh_config option "pamauthenticationviakbdint" | 2 | - (djm) Bug #629: Mark ssh_config option "pamauthenticationviakbdint" |
3 | as deprecated. Remove mention from README.privsep. Patch from | 3 | as deprecated. Remove mention from README.privsep. Patch from |
4 | aet AT cc.hut.fi | 4 | aet AT cc.hut.fi |
5 | - (dtucker) OpenBSD CVS Sync | ||
6 | - markus@cvs.openbsd.org 2003/08/22 10:56:09 | ||
7 | [auth2.c auth2-gss.c auth.h compat.c compat.h gss-genr.c gss-serv-krb5.c | ||
8 | gss-serv.c monitor.c monitor.h monitor_wrap.c monitor_wrap.h readconf.c | ||
9 | readconf.h servconf.c servconf.h session.c session.h ssh-gss.h | ||
10 | ssh_config.5 sshconnect2.c sshd_config sshd_config.5] | ||
11 | support GSS API user authentication; patches from Simon Wilkinson, | ||
12 | stripped down and tested by Jakob and myself. | ||
5 | 13 | ||
6 | 20030825 | 14 | 20030825 |
7 | - (djm) Bug #621: Select OpenSC keys by usage attributes. Patch from | 15 | - (djm) Bug #621: Select OpenSC keys by usage attributes. Patch from |
@@ -874,4 +882,4 @@ | |||
874 | - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo. | 882 | - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo. |
875 | Report from murple@murple.net, diagnosis from dtucker@zip.com.au | 883 | Report from murple@murple.net, diagnosis from dtucker@zip.com.au |
876 | 884 | ||
877 | $Id: ChangeLog,v 1.2906 2003/08/26 00:48:14 djm Exp $ | 885 | $Id: ChangeLog,v 1.2907 2003/08/26 01:49:55 dtucker Exp $ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth.h,v 1.43 2003/07/22 13:35:22 markus Exp $ */ | 1 | /* $OpenBSD: auth.h,v 1.44 2003/08/22 10:56:08 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
@@ -67,6 +67,7 @@ struct Authctxt { | |||
67 | krb5_principal krb5_user; | 67 | krb5_principal krb5_user; |
68 | char *krb5_ticket_file; | 68 | char *krb5_ticket_file; |
69 | #endif | 69 | #endif |
70 | void *methoddata; | ||
70 | }; | 71 | }; |
71 | /* | 72 | /* |
72 | * Every authentication method has to handle authentication requests for | 73 | * Every authentication method has to handle authentication requests for |
diff --git a/auth2-gss.c b/auth2-gss.c new file mode 100644 index 000000000..c7651112d --- /dev/null +++ b/auth2-gss.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /* $OpenBSD: auth2-gss.c,v 1.1 2003/08/22 10:56:08 markus Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR | ||
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | */ | ||
26 | |||
27 | #include "includes.h" | ||
28 | |||
29 | #ifdef GSSAPI | ||
30 | |||
31 | #include "auth.h" | ||
32 | #include "ssh2.h" | ||
33 | #include "xmalloc.h" | ||
34 | #include "log.h" | ||
35 | #include "dispatch.h" | ||
36 | #include "servconf.h" | ||
37 | #include "compat.h" | ||
38 | #include "packet.h" | ||
39 | #include "monitor_wrap.h" | ||
40 | |||
41 | #include "ssh-gss.h" | ||
42 | |||
43 | extern ServerOptions options; | ||
44 | |||
45 | static void input_gssapi_token(int type, u_int32_t plen, void *ctxt); | ||
46 | static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); | ||
47 | static void input_gssapi_errtok(int, u_int32_t, void *); | ||
48 | |||
49 | /* | ||
50 | * We only support those mechanisms that we know about (ie ones that we know | ||
51 | * how to check local user kuserok and the like | ||
52 | */ | ||
53 | static int | ||
54 | userauth_gssapi(Authctxt *authctxt) | ||
55 | { | ||
56 | gss_OID_desc oid = {0, NULL}; | ||
57 | Gssctxt *ctxt = NULL; | ||
58 | int mechs; | ||
59 | gss_OID_set supported; | ||
60 | int present; | ||
61 | OM_uint32 ms; | ||
62 | u_int len; | ||
63 | char *doid = NULL; | ||
64 | |||
65 | if (!authctxt->valid || authctxt->user == NULL) | ||
66 | return (0); | ||
67 | |||
68 | mechs = packet_get_int(); | ||
69 | if (mechs == 0) { | ||
70 | debug("Mechanism negotiation is not supported"); | ||
71 | return (0); | ||
72 | } | ||
73 | |||
74 | ssh_gssapi_supported_oids(&supported); | ||
75 | do { | ||
76 | mechs--; | ||
77 | |||
78 | if (doid) | ||
79 | xfree(doid); | ||
80 | |||
81 | doid = packet_get_string(&len); | ||
82 | |||
83 | if (doid[0] != SSH_GSS_OIDTYPE || doid[1] != len-2) { | ||
84 | logit("Mechanism OID received using the old encoding form"); | ||
85 | oid.elements = doid; | ||
86 | oid.length = len; | ||
87 | } else { | ||
88 | oid.elements = doid + 2; | ||
89 | oid.length = len - 2; | ||
90 | } | ||
91 | gss_test_oid_set_member(&ms, &oid, supported, &present); | ||
92 | } while (mechs > 0 && !present); | ||
93 | |||
94 | gss_release_oid_set(&ms, &supported); | ||
95 | |||
96 | if (!present) { | ||
97 | xfree(doid); | ||
98 | return (0); | ||
99 | } | ||
100 | |||
101 | if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &oid)))) | ||
102 | return (0); | ||
103 | |||
104 | authctxt->methoddata=(void *)ctxt; | ||
105 | |||
106 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE); | ||
107 | |||
108 | /* Return OID in same format as we received it*/ | ||
109 | packet_put_string(doid, len); | ||
110 | |||
111 | packet_send(); | ||
112 | xfree(doid); | ||
113 | |||
114 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); | ||
115 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); | ||
116 | authctxt->postponed = 1; | ||
117 | |||
118 | return (0); | ||
119 | } | ||
120 | |||
121 | static void | ||
122 | input_gssapi_token(int type, u_int32_t plen, void *ctxt) | ||
123 | { | ||
124 | Authctxt *authctxt = ctxt; | ||
125 | Gssctxt *gssctxt; | ||
126 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
127 | gss_buffer_desc recv_tok; | ||
128 | OM_uint32 maj_status, min_status; | ||
129 | u_int len; | ||
130 | |||
131 | if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) | ||
132 | fatal("No authentication or GSSAPI context"); | ||
133 | |||
134 | gssctxt = authctxt->methoddata; | ||
135 | recv_tok.value = packet_get_string(&len); | ||
136 | recv_tok.length = len; /* u_int vs. size_t */ | ||
137 | |||
138 | packet_check_eom(); | ||
139 | |||
140 | maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, | ||
141 | &send_tok, NULL)); | ||
142 | |||
143 | xfree(recv_tok.value); | ||
144 | |||
145 | if (GSS_ERROR(maj_status)) { | ||
146 | if (send_tok.length != 0) { | ||
147 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); | ||
148 | packet_put_string(send_tok.value, send_tok.length); | ||
149 | packet_send(); | ||
150 | } | ||
151 | authctxt->postponed = 0; | ||
152 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); | ||
153 | userauth_finish(authctxt, 0, "gssapi"); | ||
154 | } else { | ||
155 | if (send_tok.length != 0) { | ||
156 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); | ||
157 | packet_put_string(send_tok.value, send_tok.length); | ||
158 | packet_send(); | ||
159 | } | ||
160 | if (maj_status == GSS_S_COMPLETE) { | ||
161 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); | ||
162 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, | ||
163 | &input_gssapi_exchange_complete); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | gss_release_buffer(&min_status, &send_tok); | ||
168 | } | ||
169 | |||
170 | static void | ||
171 | input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) | ||
172 | { | ||
173 | Authctxt *authctxt = ctxt; | ||
174 | Gssctxt *gssctxt; | ||
175 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
176 | gss_buffer_desc recv_tok; | ||
177 | OM_uint32 maj_status; | ||
178 | |||
179 | if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) | ||
180 | fatal("No authentication or GSSAPI context"); | ||
181 | |||
182 | gssctxt = authctxt->methoddata; | ||
183 | recv_tok.value = packet_get_string(&recv_tok.length); | ||
184 | |||
185 | packet_check_eom(); | ||
186 | |||
187 | /* Push the error token into GSSAPI to see what it says */ | ||
188 | maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, | ||
189 | &send_tok, NULL)); | ||
190 | |||
191 | xfree(recv_tok.value); | ||
192 | |||
193 | /* We can't return anything to the client, even if we wanted to */ | ||
194 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); | ||
195 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); | ||
196 | |||
197 | /* The client will have already moved on to the next auth */ | ||
198 | |||
199 | gss_release_buffer(&maj_status, &send_tok); | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * This is called when the client thinks we've completed authentication. | ||
204 | * It should only be enabled in the dispatch handler by the function above, | ||
205 | * which only enables it once the GSSAPI exchange is complete. | ||
206 | */ | ||
207 | |||
208 | static void | ||
209 | input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) | ||
210 | { | ||
211 | Authctxt *authctxt = ctxt; | ||
212 | Gssctxt *gssctxt; | ||
213 | int authenticated; | ||
214 | |||
215 | if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) | ||
216 | fatal("No authentication or GSSAPI context"); | ||
217 | |||
218 | gssctxt = authctxt->methoddata; | ||
219 | |||
220 | /* | ||
221 | * We don't need to check the status, because the stored credentials | ||
222 | * which userok uses are only populated once the context init step | ||
223 | * has returned complete. | ||
224 | */ | ||
225 | |||
226 | packet_check_eom(); | ||
227 | |||
228 | authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); | ||
229 | |||
230 | authctxt->postponed = 0; | ||
231 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); | ||
232 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); | ||
233 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); | ||
234 | userauth_finish(authctxt, authenticated, "gssapi"); | ||
235 | } | ||
236 | |||
237 | Authmethod method_gssapi = { | ||
238 | "gssapi", | ||
239 | userauth_gssapi, | ||
240 | &options.gss_authentication | ||
241 | }; | ||
242 | |||
243 | #endif /* GSSAPI */ | ||
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: auth2.c,v 1.99 2003/06/24 08:23:46 markus Exp $"); | 26 | RCSID("$OpenBSD: auth2.c,v 1.100 2003/08/22 10:56:08 markus Exp $"); |
27 | 27 | ||
28 | #include "ssh2.h" | 28 | #include "ssh2.h" |
29 | #include "xmalloc.h" | 29 | #include "xmalloc.h" |
@@ -36,6 +36,10 @@ RCSID("$OpenBSD: auth2.c,v 1.99 2003/06/24 08:23:46 markus Exp $"); | |||
36 | #include "pathnames.h" | 36 | #include "pathnames.h" |
37 | #include "monitor_wrap.h" | 37 | #include "monitor_wrap.h" |
38 | 38 | ||
39 | #ifdef GSSAPI | ||
40 | #include "ssh-gss.h" | ||
41 | #endif | ||
42 | |||
39 | /* import */ | 43 | /* import */ |
40 | extern ServerOptions options; | 44 | extern ServerOptions options; |
41 | extern u_char *session_id2; | 45 | extern u_char *session_id2; |
@@ -53,10 +57,16 @@ extern Authmethod method_hostbased; | |||
53 | #ifdef KRB5 | 57 | #ifdef KRB5 |
54 | extern Authmethod method_kerberos; | 58 | extern Authmethod method_kerberos; |
55 | #endif | 59 | #endif |
60 | #ifdef GSSAPI | ||
61 | extern Authmethod method_gssapi; | ||
62 | #endif | ||
56 | 63 | ||
57 | Authmethod *authmethods[] = { | 64 | Authmethod *authmethods[] = { |
58 | &method_none, | 65 | &method_none, |
59 | &method_pubkey, | 66 | &method_pubkey, |
67 | #ifdef GSSAPI | ||
68 | &method_gssapi, | ||
69 | #endif | ||
60 | &method_passwd, | 70 | &method_passwd, |
61 | &method_kbdint, | 71 | &method_kbdint, |
62 | &method_hostbased, | 72 | &method_hostbased, |
@@ -184,6 +194,12 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) | |||
184 | } | 194 | } |
185 | /* reset state */ | 195 | /* reset state */ |
186 | auth2_challenge_stop(authctxt); | 196 | auth2_challenge_stop(authctxt); |
197 | |||
198 | #ifdef GSSAPI | ||
199 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); | ||
200 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); | ||
201 | #endif | ||
202 | |||
187 | authctxt->postponed = 0; | 203 | authctxt->postponed = 0; |
188 | 204 | ||
189 | /* try to authenticate user */ | 205 | /* try to authenticate user */ |
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: compat.c,v 1.67 2003/04/08 20:21:28 itojun Exp $"); | 26 | RCSID("$OpenBSD: compat.c,v 1.68 2003/08/22 10:56:09 markus Exp $"); |
27 | 27 | ||
28 | #include "buffer.h" | 28 | #include "buffer.h" |
29 | #include "packet.h" | 29 | #include "packet.h" |
@@ -79,7 +79,11 @@ compat_datafellows(const char *version) | |||
79 | { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, | 79 | { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, |
80 | { "OpenSSH_2.*," | 80 | { "OpenSSH_2.*," |
81 | "OpenSSH_3.0*," | 81 | "OpenSSH_3.0*," |
82 | "OpenSSH_3.1*", SSH_BUG_EXTEOF}, | 82 | "OpenSSH_3.1*", SSH_BUG_EXTEOF|SSH_BUG_GSSAPI_BER}, |
83 | { "OpenSSH_3.2*," | ||
84 | "OpenSSH_3.3*," | ||
85 | "OpenSSH_3.4*," | ||
86 | "OpenSSH_3.5*", SSH_BUG_GSSAPI_BER}, | ||
83 | { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, | 87 | { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, |
84 | { "OpenSSH*", 0 }, | 88 | { "OpenSSH*", 0 }, |
85 | { "*MindTerm*", 0 }, | 89 | { "*MindTerm*", 0 }, |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: compat.h,v 1.34 2003/04/01 10:31:26 markus Exp $ */ | 1 | /* $OpenBSD: compat.h,v 1.35 2003/08/22 10:56:09 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. |
@@ -56,6 +56,7 @@ | |||
56 | #define SSH_BUG_K5USER 0x00400000 | 56 | #define SSH_BUG_K5USER 0x00400000 |
57 | #define SSH_BUG_PROBE 0x00800000 | 57 | #define SSH_BUG_PROBE 0x00800000 |
58 | #define SSH_BUG_FIRSTKEX 0x01000000 | 58 | #define SSH_BUG_FIRSTKEX 0x01000000 |
59 | #define SSH_BUG_GSSAPI_BER 0x02000000 | ||
59 | 60 | ||
60 | void enable_compat13(void); | 61 | void enable_compat13(void); |
61 | void enable_compat20(void); | 62 | void enable_compat20(void); |
diff --git a/gss-genr.c b/gss-genr.c new file mode 100644 index 000000000..bda12d6f1 --- /dev/null +++ b/gss-genr.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* $OpenBSD: gss-genr.c,v 1.1 2003/08/22 10:56:09 markus Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR | ||
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | */ | ||
26 | |||
27 | #include "includes.h" | ||
28 | |||
29 | #ifdef GSSAPI | ||
30 | |||
31 | #include "xmalloc.h" | ||
32 | #include "bufaux.h" | ||
33 | #include "compat.h" | ||
34 | #include "log.h" | ||
35 | #include "monitor_wrap.h" | ||
36 | |||
37 | #include "ssh-gss.h" | ||
38 | |||
39 | |||
40 | /* Check that the OID in a data stream matches that in the context */ | ||
41 | int | ||
42 | ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) | ||
43 | { | ||
44 | return (ctx != NULL && ctx->oid != GSS_C_NO_OID && | ||
45 | ctx->oid->length == len && | ||
46 | memcmp(ctx->oid->elements, data, len) == 0); | ||
47 | } | ||
48 | |||
49 | /* Set the contexts OID from a data stream */ | ||
50 | void | ||
51 | ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len) | ||
52 | { | ||
53 | if (ctx->oid != GSS_C_NO_OID) { | ||
54 | xfree(ctx->oid->elements); | ||
55 | xfree(ctx->oid); | ||
56 | } | ||
57 | ctx->oid = xmalloc(sizeof(gss_OID_desc)); | ||
58 | ctx->oid->length = len; | ||
59 | ctx->oid->elements = xmalloc(len); | ||
60 | memcpy(ctx->oid->elements, data, len); | ||
61 | } | ||
62 | |||
63 | /* Set the contexts OID */ | ||
64 | void | ||
65 | ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid) | ||
66 | { | ||
67 | ssh_gssapi_set_oid_data(ctx, oid->elements, oid->length); | ||
68 | } | ||
69 | |||
70 | /* All this effort to report an error ... */ | ||
71 | void | ||
72 | ssh_gssapi_error(Gssctxt *ctxt) | ||
73 | { | ||
74 | debug("%s", ssh_gssapi_last_error(ctxt, NULL, NULL)); | ||
75 | } | ||
76 | |||
77 | char * | ||
78 | ssh_gssapi_last_error(Gssctxt *ctxt, | ||
79 | OM_uint32 *major_status, OM_uint32 *minor_status) | ||
80 | { | ||
81 | OM_uint32 lmin; | ||
82 | gss_buffer_desc msg = GSS_C_EMPTY_BUFFER; | ||
83 | OM_uint32 ctx; | ||
84 | Buffer b; | ||
85 | char *ret; | ||
86 | |||
87 | buffer_init(&b); | ||
88 | |||
89 | if (major_status != NULL) | ||
90 | *major_status = ctxt->major; | ||
91 | if (minor_status != NULL) | ||
92 | *minor_status = ctxt->minor; | ||
93 | |||
94 | ctx = 0; | ||
95 | /* The GSSAPI error */ | ||
96 | do { | ||
97 | gss_display_status(&lmin, ctxt->major, | ||
98 | GSS_C_GSS_CODE, GSS_C_NULL_OID, &ctx, &msg); | ||
99 | |||
100 | buffer_append(&b, msg.value, msg.length); | ||
101 | buffer_put_char(&b, '\n'); | ||
102 | |||
103 | gss_release_buffer(&lmin, &msg); | ||
104 | } while (ctx != 0); | ||
105 | |||
106 | /* The mechanism specific error */ | ||
107 | do { | ||
108 | gss_display_status(&lmin, ctxt->minor, | ||
109 | GSS_C_MECH_CODE, GSS_C_NULL_OID, &ctx, &msg); | ||
110 | |||
111 | buffer_append(&b, msg.value, msg.length); | ||
112 | buffer_put_char(&b, '\n'); | ||
113 | |||
114 | gss_release_buffer(&lmin, &msg); | ||
115 | } while (ctx != 0); | ||
116 | |||
117 | buffer_put_char(&b, '\0'); | ||
118 | ret = xmalloc(buffer_len(&b)); | ||
119 | buffer_get(&b, ret, buffer_len(&b)); | ||
120 | buffer_free(&b); | ||
121 | return (ret); | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * Initialise our GSSAPI context. We use this opaque structure to contain all | ||
126 | * of the data which both the client and server need to persist across | ||
127 | * {accept,init}_sec_context calls, so that when we do it from the userauth | ||
128 | * stuff life is a little easier | ||
129 | */ | ||
130 | void | ||
131 | ssh_gssapi_build_ctx(Gssctxt **ctx) | ||
132 | { | ||
133 | *ctx = xmalloc(sizeof (Gssctxt)); | ||
134 | (*ctx)->major = 0; | ||
135 | (*ctx)->minor = 0; | ||
136 | (*ctx)->context = GSS_C_NO_CONTEXT; | ||
137 | (*ctx)->name = GSS_C_NO_NAME; | ||
138 | (*ctx)->oid = GSS_C_NO_OID; | ||
139 | (*ctx)->creds = GSS_C_NO_CREDENTIAL; | ||
140 | (*ctx)->client = GSS_C_NO_NAME; | ||
141 | (*ctx)->client_creds = GSS_C_NO_CREDENTIAL; | ||
142 | } | ||
143 | |||
144 | /* Delete our context, providing it has been built correctly */ | ||
145 | void | ||
146 | ssh_gssapi_delete_ctx(Gssctxt **ctx) | ||
147 | { | ||
148 | OM_uint32 ms; | ||
149 | |||
150 | if ((*ctx) == NULL) | ||
151 | return; | ||
152 | if ((*ctx)->context != GSS_C_NO_CONTEXT) | ||
153 | gss_delete_sec_context(&ms, &(*ctx)->context, GSS_C_NO_BUFFER); | ||
154 | if ((*ctx)->name != GSS_C_NO_NAME) | ||
155 | gss_release_name(&ms, &(*ctx)->name); | ||
156 | if ((*ctx)->oid != GSS_C_NO_OID) { | ||
157 | xfree((*ctx)->oid->elements); | ||
158 | xfree((*ctx)->oid); | ||
159 | (*ctx)->oid = GSS_C_NO_OID; | ||
160 | } | ||
161 | if ((*ctx)->creds != GSS_C_NO_CREDENTIAL) | ||
162 | gss_release_cred(&ms, &(*ctx)->creds); | ||
163 | if ((*ctx)->client != GSS_C_NO_NAME) | ||
164 | gss_release_name(&ms, &(*ctx)->client); | ||
165 | if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL) | ||
166 | gss_release_cred(&ms, &(*ctx)->client_creds); | ||
167 | |||
168 | xfree(*ctx); | ||
169 | *ctx = NULL; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * Wrapper to init_sec_context | ||
174 | * Requires that the context contains: | ||
175 | * oid | ||
176 | * server name (from ssh_gssapi_import_name) | ||
177 | */ | ||
178 | OM_uint32 | ||
179 | ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, | ||
180 | gss_buffer_desc* send_tok, OM_uint32 *flags) | ||
181 | { | ||
182 | int deleg_flag = 0; | ||
183 | |||
184 | if (deleg_creds) { | ||
185 | deleg_flag = GSS_C_DELEG_FLAG; | ||
186 | debug("Delegating credentials"); | ||
187 | } | ||
188 | |||
189 | ctx->major = gss_init_sec_context(&ctx->minor, | ||
190 | GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, | ||
191 | GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, | ||
192 | 0, NULL, recv_tok, NULL, send_tok, flags, NULL); | ||
193 | |||
194 | if (GSS_ERROR(ctx->major)) | ||
195 | ssh_gssapi_error(ctx); | ||
196 | |||
197 | return (ctx->major); | ||
198 | } | ||
199 | |||
200 | /* Create a service name for the given host */ | ||
201 | OM_uint32 | ||
202 | ssh_gssapi_import_name(Gssctxt *ctx, const char *host) | ||
203 | { | ||
204 | gss_buffer_desc gssbuf; | ||
205 | |||
206 | gssbuf.length = sizeof("host@") + strlen(host); | ||
207 | gssbuf.value = xmalloc(gssbuf.length); | ||
208 | snprintf(gssbuf.value, gssbuf.length, "host@%s", host); | ||
209 | |||
210 | if ((ctx->major = gss_import_name(&ctx->minor, | ||
211 | &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) | ||
212 | ssh_gssapi_error(ctx); | ||
213 | |||
214 | xfree(gssbuf.value); | ||
215 | return (ctx->major); | ||
216 | } | ||
217 | |||
218 | /* Acquire credentials for a server running on the current host. | ||
219 | * Requires that the context structure contains a valid OID | ||
220 | */ | ||
221 | |||
222 | /* Returns a GSSAPI error code */ | ||
223 | OM_uint32 | ||
224 | ssh_gssapi_acquire_cred(Gssctxt *ctx) | ||
225 | { | ||
226 | OM_uint32 status; | ||
227 | char lname[MAXHOSTNAMELEN]; | ||
228 | gss_OID_set oidset; | ||
229 | |||
230 | gss_create_empty_oid_set(&status, &oidset); | ||
231 | gss_add_oid_set_member(&status, ctx->oid, &oidset); | ||
232 | |||
233 | if (gethostname(lname, MAXHOSTNAMELEN)) | ||
234 | return (-1); | ||
235 | |||
236 | if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) | ||
237 | return (ctx->major); | ||
238 | |||
239 | if ((ctx->major = gss_acquire_cred(&ctx->minor, | ||
240 | ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) | ||
241 | ssh_gssapi_error(ctx); | ||
242 | |||
243 | gss_release_oid_set(&status, &oidset); | ||
244 | return (ctx->major); | ||
245 | } | ||
246 | |||
247 | OM_uint32 | ||
248 | ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) { | ||
249 | if (*ctx) | ||
250 | ssh_gssapi_delete_ctx(ctx); | ||
251 | ssh_gssapi_build_ctx(ctx); | ||
252 | ssh_gssapi_set_oid(*ctx, oid); | ||
253 | return (ssh_gssapi_acquire_cred(*ctx)); | ||
254 | } | ||
255 | |||
256 | #endif /* GSSAPI */ | ||
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c new file mode 100644 index 000000000..d86872258 --- /dev/null +++ b/gss-serv-krb5.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* $OpenBSD: gss-serv-krb5.c,v 1.1 2003/08/22 10:56:09 markus Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR | ||
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | */ | ||
26 | |||
27 | #include "includes.h" | ||
28 | |||
29 | #ifdef GSSAPI | ||
30 | #ifdef KRB5 | ||
31 | |||
32 | #include "auth.h" | ||
33 | #include "xmalloc.h" | ||
34 | #include "log.h" | ||
35 | #include "servconf.h" | ||
36 | |||
37 | #include "ssh-gss.h" | ||
38 | |||
39 | extern ServerOptions options; | ||
40 | |||
41 | #include <krb5.h> | ||
42 | |||
43 | static krb5_context krb_context = NULL; | ||
44 | |||
45 | /* Initialise the krb5 library, for the stuff that GSSAPI won't do */ | ||
46 | |||
47 | static int | ||
48 | ssh_gssapi_krb5_init() | ||
49 | { | ||
50 | krb5_error_code problem; | ||
51 | |||
52 | if (krb_context != NULL) | ||
53 | return 1; | ||
54 | |||
55 | problem = krb5_init_context(&krb_context); | ||
56 | if (problem) { | ||
57 | logit("Cannot initialize krb5 context"); | ||
58 | return 0; | ||
59 | } | ||
60 | krb5_init_ets(krb_context); | ||
61 | |||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | /* Check if this user is OK to login. This only works with krb5 - other | ||
66 | * GSSAPI mechanisms will need their own. | ||
67 | * Returns true if the user is OK to log in, otherwise returns 0 | ||
68 | */ | ||
69 | |||
70 | static int | ||
71 | ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) | ||
72 | { | ||
73 | krb5_principal princ; | ||
74 | int retval; | ||
75 | |||
76 | if (ssh_gssapi_krb5_init() == 0) | ||
77 | return 0; | ||
78 | |||
79 | if ((retval = krb5_parse_name(krb_context, client->exportedname.value, | ||
80 | &princ))) { | ||
81 | logit("krb5_parse_name(): %.100s", | ||
82 | krb5_get_err_text(krb_context, retval)); | ||
83 | return 0; | ||
84 | } | ||
85 | if (krb5_kuserok(krb_context, princ, name)) { | ||
86 | retval = 1; | ||
87 | logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", | ||
88 | name, (char *)client->displayname.value); | ||
89 | } else | ||
90 | retval = 0; | ||
91 | |||
92 | krb5_free_principal(krb_context, princ); | ||
93 | return retval; | ||
94 | } | ||
95 | |||
96 | |||
97 | /* This writes out any forwarded credentials from the structure populated | ||
98 | * during userauth. Called after we have setuid to the user */ | ||
99 | |||
100 | static void | ||
101 | ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) | ||
102 | { | ||
103 | krb5_ccache ccache; | ||
104 | krb5_error_code problem; | ||
105 | krb5_principal princ; | ||
106 | OM_uint32 maj_status, min_status; | ||
107 | |||
108 | if (client->creds == NULL) { | ||
109 | debug("No credentials stored"); | ||
110 | return; | ||
111 | } | ||
112 | |||
113 | if (ssh_gssapi_krb5_init() == 0) | ||
114 | return; | ||
115 | |||
116 | if ((problem = krb5_cc_gen_new(krb_context, &krb5_fcc_ops, &ccache))) { | ||
117 | logit("krb5_cc_gen_new(): %.100s", | ||
118 | krb5_get_err_text(krb_context, problem)); | ||
119 | return; | ||
120 | } | ||
121 | |||
122 | if ((problem = krb5_parse_name(krb_context, | ||
123 | client->exportedname.value, &princ))) { | ||
124 | logit("krb5_parse_name(): %.100s", | ||
125 | krb5_get_err_text(krb_context, problem)); | ||
126 | krb5_cc_destroy(krb_context, ccache); | ||
127 | return; | ||
128 | } | ||
129 | |||
130 | if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) { | ||
131 | logit("krb5_cc_initialize(): %.100s", | ||
132 | krb5_get_err_text(krb_context, problem)); | ||
133 | krb5_free_principal(krb_context, princ); | ||
134 | krb5_cc_destroy(krb_context, ccache); | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | krb5_free_principal(krb_context, princ); | ||
139 | |||
140 | if ((maj_status = gss_krb5_copy_ccache(&min_status, | ||
141 | client->creds, ccache))) { | ||
142 | logit("gss_krb5_copy_ccache() failed"); | ||
143 | krb5_cc_destroy(krb_context, ccache); | ||
144 | return; | ||
145 | } | ||
146 | |||
147 | client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); | ||
148 | client->store.envvar = "KRB5CCNAME"; | ||
149 | client->store.envval = xstrdup(client->store.filename); | ||
150 | |||
151 | krb5_cc_close(krb_context, ccache); | ||
152 | |||
153 | return; | ||
154 | } | ||
155 | |||
156 | ssh_gssapi_mech gssapi_kerberos_mech = { | ||
157 | "toWM5Slw5Ew8Mqkay+al2g==", | ||
158 | "Kerberos", | ||
159 | {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}, | ||
160 | NULL, | ||
161 | &ssh_gssapi_krb5_userok, | ||
162 | NULL, | ||
163 | &ssh_gssapi_krb5_storecreds | ||
164 | }; | ||
165 | |||
166 | #endif /* KRB5 */ | ||
167 | |||
168 | #endif /* GSSAPI */ | ||
diff --git a/gss-serv.c b/gss-serv.c new file mode 100644 index 000000000..42718177d --- /dev/null +++ b/gss-serv.c | |||
@@ -0,0 +1,291 @@ | |||
1 | /* $OpenBSD: gss-serv.c,v 1.1 2003/08/22 10:56:09 markus Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR | ||
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | */ | ||
26 | |||
27 | #include "includes.h" | ||
28 | |||
29 | #ifdef GSSAPI | ||
30 | |||
31 | #include "bufaux.h" | ||
32 | #include "compat.h" | ||
33 | #include "auth.h" | ||
34 | #include "log.h" | ||
35 | #include "channels.h" | ||
36 | #include "session.h" | ||
37 | #include "servconf.h" | ||
38 | #include "monitor_wrap.h" | ||
39 | #include "xmalloc.h" | ||
40 | #include "getput.h" | ||
41 | |||
42 | #include "ssh-gss.h" | ||
43 | |||
44 | extern ServerOptions options; | ||
45 | |||
46 | static ssh_gssapi_client gssapi_client = | ||
47 | { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, | ||
48 | GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}}; | ||
49 | |||
50 | ssh_gssapi_mech gssapi_null_mech = | ||
51 | { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; | ||
52 | |||
53 | #ifdef KRB5 | ||
54 | extern ssh_gssapi_mech gssapi_kerberos_mech; | ||
55 | #endif | ||
56 | |||
57 | ssh_gssapi_mech* supported_mechs[]= { | ||
58 | #ifdef KRB5 | ||
59 | &gssapi_kerberos_mech, | ||
60 | #endif | ||
61 | &gssapi_null_mech, | ||
62 | }; | ||
63 | |||
64 | /* Unpriviledged */ | ||
65 | void | ||
66 | ssh_gssapi_supported_oids(gss_OID_set *oidset) | ||
67 | { | ||
68 | int i = 0; | ||
69 | OM_uint32 min_status; | ||
70 | int present; | ||
71 | gss_OID_set supported; | ||
72 | |||
73 | gss_create_empty_oid_set(&min_status, oidset); | ||
74 | gss_indicate_mechs(&min_status, &supported); | ||
75 | |||
76 | while (supported_mechs[i]->name != NULL) { | ||
77 | if (GSS_ERROR(gss_test_oid_set_member(&min_status, | ||
78 | &supported_mechs[i]->oid, supported, &present))) | ||
79 | present = 0; | ||
80 | if (present) | ||
81 | gss_add_oid_set_member(&min_status, | ||
82 | &supported_mechs[i]->oid, oidset); | ||
83 | i++; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | |||
88 | /* Wrapper around accept_sec_context | ||
89 | * Requires that the context contains: | ||
90 | * oid | ||
91 | * credentials (from ssh_gssapi_acquire_cred) | ||
92 | */ | ||
93 | /* Priviledged */ | ||
94 | OM_uint32 | ||
95 | ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *recv_tok, | ||
96 | gss_buffer_desc *send_tok, OM_uint32 *flags) | ||
97 | { | ||
98 | OM_uint32 status; | ||
99 | gss_OID mech; | ||
100 | |||
101 | ctx->major = gss_accept_sec_context(&ctx->minor, | ||
102 | &ctx->context, ctx->creds, recv_tok, | ||
103 | GSS_C_NO_CHANNEL_BINDINGS, &ctx->client, &mech, | ||
104 | send_tok, flags, NULL, &ctx->client_creds); | ||
105 | |||
106 | if (GSS_ERROR(ctx->major)) | ||
107 | ssh_gssapi_error(ctx); | ||
108 | |||
109 | if (ctx->client_creds) | ||
110 | debug("Received some client credentials"); | ||
111 | else | ||
112 | debug("Got no client credentials"); | ||
113 | |||
114 | status = ctx->major; | ||
115 | |||
116 | /* Now, if we're complete and we have the right flags, then | ||
117 | * we flag the user as also having been authenticated | ||
118 | */ | ||
119 | |||
120 | if (((flags == NULL) || ((*flags & GSS_C_MUTUAL_FLAG) && | ||
121 | (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) { | ||
122 | if (ssh_gssapi_getclient(ctx, &gssapi_client)) | ||
123 | fatal("Couldn't convert client name"); | ||
124 | } | ||
125 | |||
126 | return (status); | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * This parses an exported name, extracting the mechanism specific portion | ||
131 | * to use for ACL checking. It verifies that the name belongs the mechanism | ||
132 | * originally selected. | ||
133 | */ | ||
134 | static OM_uint32 | ||
135 | ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name) | ||
136 | { | ||
137 | char *tok; | ||
138 | OM_uint32 offset; | ||
139 | OM_uint32 oidl; | ||
140 | |||
141 | tok=ename->value; | ||
142 | |||
143 | /* | ||
144 | * Check that ename is long enough for all of the fixed length | ||
145 | * header, and that the initial ID bytes are correct | ||
146 | */ | ||
147 | |||
148 | if (ename->length<6 || memcmp(tok,"\x04\x01", 2)!=0) | ||
149 | return GSS_S_FAILURE; | ||
150 | |||
151 | /* | ||
152 | * Extract the OID, and check it. Here GSSAPI breaks with tradition | ||
153 | * and does use the OID type and length bytes. To confuse things | ||
154 | * there are two lengths - the first including these, and the | ||
155 | * second without. | ||
156 | */ | ||
157 | |||
158 | oidl = GET_16BIT(tok+2); /* length including next two bytes */ | ||
159 | oidl = oidl-2; /* turn it into the _real_ length of the variable OID */ | ||
160 | |||
161 | /* | ||
162 | * Check the BER encoding for correct type and length, that the | ||
163 | * string is long enough and that the OID matches that in our context | ||
164 | */ | ||
165 | if (tok[4] != 0x06 || tok[5] != oidl || | ||
166 | ename->length < oidl+6 || | ||
167 | !ssh_gssapi_check_oid(ctx,tok+6,oidl)) | ||
168 | return GSS_S_FAILURE; | ||
169 | |||
170 | offset = oidl+6; | ||
171 | |||
172 | if (ename->length < offset+4) | ||
173 | return GSS_S_FAILURE; | ||
174 | |||
175 | name->length = GET_32BIT(tok+offset); | ||
176 | offset += 4; | ||
177 | |||
178 | if (ename->length < offset+name->length) | ||
179 | return GSS_S_FAILURE; | ||
180 | |||
181 | name->value = xmalloc(name->length); | ||
182 | memcpy(name->value,tok+offset,name->length); | ||
183 | |||
184 | return GSS_S_COMPLETE; | ||
185 | } | ||
186 | |||
187 | /* Extract the client details from a given context. This can only reliably | ||
188 | * be called once for a context */ | ||
189 | |||
190 | /* Priviledged (called from accept_secure_ctx) */ | ||
191 | OM_uint32 | ||
192 | ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) | ||
193 | { | ||
194 | int i = 0; | ||
195 | |||
196 | gss_buffer_desc ename; | ||
197 | |||
198 | client->mech = NULL; | ||
199 | |||
200 | while (supported_mechs[i]->name != NULL) { | ||
201 | if (supported_mechs[i]->oid.length == ctx->oid->length && | ||
202 | (memcmp(supported_mechs[i]->oid.elements, | ||
203 | ctx->oid->elements, ctx->oid->length) == 0)) | ||
204 | client->mech = supported_mechs[i]; | ||
205 | i++; | ||
206 | } | ||
207 | |||
208 | if (client->mech == NULL) | ||
209 | return GSS_S_FAILURE; | ||
210 | |||
211 | if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, | ||
212 | &client->displayname, NULL))) { | ||
213 | ssh_gssapi_error(ctx); | ||
214 | return (ctx->major); | ||
215 | } | ||
216 | |||
217 | if ((ctx->major = gss_export_name(&ctx->minor, ctx->client, | ||
218 | &ename))) { | ||
219 | ssh_gssapi_error(ctx); | ||
220 | return (ctx->major); | ||
221 | } | ||
222 | |||
223 | if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename, | ||
224 | &client->exportedname))) { | ||
225 | return (ctx->major); | ||
226 | } | ||
227 | |||
228 | /* We can't copy this structure, so we just move the pointer to it */ | ||
229 | client->creds = ctx->client_creds; | ||
230 | ctx->client_creds = GSS_C_NO_CREDENTIAL; | ||
231 | return (ctx->major); | ||
232 | } | ||
233 | |||
234 | /* As user - called through fatal cleanup hook */ | ||
235 | void | ||
236 | ssh_gssapi_cleanup_creds(void *ignored) | ||
237 | { | ||
238 | if (gssapi_client.store.filename != NULL) { | ||
239 | /* Unlink probably isn't sufficient */ | ||
240 | debug("removing gssapi cred file\"%s\"", gssapi_client.store.filename); | ||
241 | unlink(gssapi_client.store.filename); | ||
242 | } | ||
243 | } | ||
244 | |||
245 | /* As user */ | ||
246 | void | ||
247 | ssh_gssapi_storecreds(void) | ||
248 | { | ||
249 | if (gssapi_client.mech && gssapi_client.mech->storecreds) { | ||
250 | (*gssapi_client.mech->storecreds)(&gssapi_client); | ||
251 | if (options.gss_cleanup_creds) | ||
252 | fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL); | ||
253 | } else | ||
254 | debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism"); | ||
255 | } | ||
256 | |||
257 | /* This allows GSSAPI methods to do things to the childs environment based | ||
258 | * on the passed authentication process and credentials. | ||
259 | */ | ||
260 | /* As user */ | ||
261 | void | ||
262 | ssh_gssapi_do_child(char ***envp, u_int *envsizep) | ||
263 | { | ||
264 | |||
265 | if (gssapi_client.store.envvar != NULL && | ||
266 | gssapi_client.store.envval != NULL) { | ||
267 | |||
268 | debug("Setting %s to %s", gssapi_client.store.envvar, | ||
269 | gssapi_client.store.envval); | ||
270 | child_set_env(envp, envsizep, gssapi_client.store.envvar, | ||
271 | gssapi_client.store.envval); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /* Priviledged */ | ||
276 | int | ||
277 | ssh_gssapi_userok(char *user) | ||
278 | { | ||
279 | if (gssapi_client.exportedname.length == 0 || | ||
280 | gssapi_client.exportedname.value == NULL) { | ||
281 | debug("No suitable client data"); | ||
282 | return 0; | ||
283 | } | ||
284 | if (gssapi_client.mech && gssapi_client.mech->userok) | ||
285 | return ((*gssapi_client.mech->userok)(&gssapi_client, user)); | ||
286 | else | ||
287 | debug("ssh_gssapi_userok: Unknown GSSAPI mechanism"); | ||
288 | return (0); | ||
289 | } | ||
290 | |||
291 | #endif | ||
@@ -25,7 +25,7 @@ | |||
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include "includes.h" | 27 | #include "includes.h" |
28 | RCSID("$OpenBSD: monitor.c,v 1.45 2003/07/22 13:35:22 markus Exp $"); | 28 | RCSID("$OpenBSD: monitor.c,v 1.46 2003/08/22 10:56:09 markus Exp $"); |
29 | 29 | ||
30 | #include <openssl/dh.h> | 30 | #include <openssl/dh.h> |
31 | 31 | ||
@@ -59,6 +59,11 @@ RCSID("$OpenBSD: monitor.c,v 1.45 2003/07/22 13:35:22 markus Exp $"); | |||
59 | #include "ssh2.h" | 59 | #include "ssh2.h" |
60 | #include "mpaux.h" | 60 | #include "mpaux.h" |
61 | 61 | ||
62 | #ifdef GSSAPI | ||
63 | #include "ssh-gss.h" | ||
64 | static Gssctxt *gsscontext = NULL; | ||
65 | #endif | ||
66 | |||
62 | /* Imports */ | 67 | /* Imports */ |
63 | extern ServerOptions options; | 68 | extern ServerOptions options; |
64 | extern u_int utmp_len; | 69 | extern u_int utmp_len; |
@@ -128,6 +133,11 @@ int mm_answer_pam_free_ctx(int, Buffer *); | |||
128 | #ifdef KRB5 | 133 | #ifdef KRB5 |
129 | int mm_answer_krb5(int, Buffer *); | 134 | int mm_answer_krb5(int, Buffer *); |
130 | #endif | 135 | #endif |
136 | #ifdef GSSAPI | ||
137 | int mm_answer_gss_setup_ctx(int, Buffer *); | ||
138 | int mm_answer_gss_accept_ctx(int, Buffer *); | ||
139 | int mm_answer_gss_userok(int, Buffer *); | ||
140 | #endif | ||
131 | 141 | ||
132 | static Authctxt *authctxt; | 142 | static Authctxt *authctxt; |
133 | static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ | 143 | static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ |
@@ -185,6 +195,11 @@ struct mon_table mon_dispatch_proto20[] = { | |||
185 | #ifdef KRB5 | 195 | #ifdef KRB5 |
186 | {MONITOR_REQ_KRB5, MON_ONCE|MON_AUTH, mm_answer_krb5}, | 196 | {MONITOR_REQ_KRB5, MON_ONCE|MON_AUTH, mm_answer_krb5}, |
187 | #endif | 197 | #endif |
198 | #ifdef GSSAPI | ||
199 | {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx}, | ||
200 | {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, | ||
201 | {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, | ||
202 | #endif | ||
188 | {0, 0, NULL} | 203 | {0, 0, NULL} |
189 | }; | 204 | }; |
190 | 205 | ||
@@ -357,7 +372,6 @@ monitor_child_postauth(struct monitor *pmonitor) | |||
357 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); | 372 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); |
358 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); | 373 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); |
359 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); | 374 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); |
360 | |||
361 | } else { | 375 | } else { |
362 | mon_dispatch = mon_dispatch_postauth15; | 376 | mon_dispatch = mon_dispatch_postauth15; |
363 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); | 377 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); |
@@ -1769,3 +1783,77 @@ monitor_reinit(struct monitor *mon) | |||
1769 | mon->m_recvfd = pair[0]; | 1783 | mon->m_recvfd = pair[0]; |
1770 | mon->m_sendfd = pair[1]; | 1784 | mon->m_sendfd = pair[1]; |
1771 | } | 1785 | } |
1786 | |||
1787 | #ifdef GSSAPI | ||
1788 | int | ||
1789 | mm_answer_gss_setup_ctx(int socket, Buffer *m) | ||
1790 | { | ||
1791 | gss_OID_desc oid; | ||
1792 | OM_uint32 major; | ||
1793 | u_int len; | ||
1794 | |||
1795 | oid.elements = buffer_get_string(m, &len); | ||
1796 | oid.length = len; | ||
1797 | |||
1798 | major = ssh_gssapi_server_ctx(&gsscontext, &oid); | ||
1799 | |||
1800 | xfree(oid.elements); | ||
1801 | |||
1802 | buffer_clear(m); | ||
1803 | buffer_put_int(m, major); | ||
1804 | |||
1805 | mm_request_send(socket,MONITOR_ANS_GSSSETUP, m); | ||
1806 | |||
1807 | /* Now we have a context, enable the step */ | ||
1808 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1); | ||
1809 | |||
1810 | return (0); | ||
1811 | } | ||
1812 | |||
1813 | int | ||
1814 | mm_answer_gss_accept_ctx(int socket, Buffer *m) | ||
1815 | { | ||
1816 | gss_buffer_desc in; | ||
1817 | gss_buffer_desc out = GSS_C_EMPTY_BUFFER; | ||
1818 | OM_uint32 major,minor; | ||
1819 | OM_uint32 flags = 0; /* GSI needs this */ | ||
1820 | |||
1821 | in.value = buffer_get_string(m, &in.length); | ||
1822 | major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); | ||
1823 | xfree(in.value); | ||
1824 | |||
1825 | buffer_clear(m); | ||
1826 | buffer_put_int(m, major); | ||
1827 | buffer_put_string(m, out.value, out.length); | ||
1828 | buffer_put_int(m, flags); | ||
1829 | mm_request_send(socket, MONITOR_ANS_GSSSTEP, m); | ||
1830 | |||
1831 | gss_release_buffer(&minor, &out); | ||
1832 | |||
1833 | /* Complete - now we can do signing */ | ||
1834 | if (major==GSS_S_COMPLETE) { | ||
1835 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); | ||
1836 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); | ||
1837 | } | ||
1838 | return (0); | ||
1839 | } | ||
1840 | |||
1841 | int | ||
1842 | mm_answer_gss_userok(int socket, Buffer *m) | ||
1843 | { | ||
1844 | int authenticated; | ||
1845 | |||
1846 | authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); | ||
1847 | |||
1848 | buffer_clear(m); | ||
1849 | buffer_put_int(m, authenticated); | ||
1850 | |||
1851 | debug3("%s: sending result %d", __func__, authenticated); | ||
1852 | mm_request_send(socket, MONITOR_ANS_GSSUSEROK, m); | ||
1853 | |||
1854 | auth_method="gssapi"; | ||
1855 | |||
1856 | /* Monitor loop will terminate if authenticated */ | ||
1857 | return (authenticated); | ||
1858 | } | ||
1859 | #endif /* GSSAPI */ | ||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: monitor.h,v 1.9 2003/07/22 13:35:22 markus Exp $ */ | 1 | /* $OpenBSD: monitor.h,v 1.10 2003/08/22 10:56:09 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | 4 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> |
@@ -50,6 +50,9 @@ enum monitor_reqtype { | |||
50 | MONITOR_REQ_RSACHALLENGE, MONITOR_ANS_RSACHALLENGE, | 50 | MONITOR_REQ_RSACHALLENGE, MONITOR_ANS_RSACHALLENGE, |
51 | MONITOR_REQ_RSARESPONSE, MONITOR_ANS_RSARESPONSE, | 51 | MONITOR_REQ_RSARESPONSE, MONITOR_ANS_RSARESPONSE, |
52 | MONITOR_REQ_KRB5, MONITOR_ANS_KRB5, | 52 | MONITOR_REQ_KRB5, MONITOR_ANS_KRB5, |
53 | MONITOR_REQ_GSSSETUP, MONITOR_ANS_GSSSETUP, | ||
54 | MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP, | ||
55 | MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, | ||
53 | MONITOR_REQ_PAM_START, | 56 | MONITOR_REQ_PAM_START, |
54 | MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, | 57 | MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, |
55 | MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, | 58 | MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, |
diff --git a/monitor_wrap.c b/monitor_wrap.c index 9e7e6b3c3..4073905f6 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c | |||
@@ -25,7 +25,7 @@ | |||
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include "includes.h" | 27 | #include "includes.h" |
28 | RCSID("$OpenBSD: monitor_wrap.c,v 1.28 2003/07/22 13:35:22 markus Exp $"); | 28 | RCSID("$OpenBSD: monitor_wrap.c,v 1.29 2003/08/22 10:56:09 markus Exp $"); |
29 | 29 | ||
30 | #include <openssl/bn.h> | 30 | #include <openssl/bn.h> |
31 | #include <openssl/dh.h> | 31 | #include <openssl/dh.h> |
@@ -53,6 +53,10 @@ RCSID("$OpenBSD: monitor_wrap.c,v 1.28 2003/07/22 13:35:22 markus Exp $"); | |||
53 | #include "channels.h" | 53 | #include "channels.h" |
54 | #include "session.h" | 54 | #include "session.h" |
55 | 55 | ||
56 | #ifdef GSSAPI | ||
57 | #include "ssh-gss.h" | ||
58 | #endif | ||
59 | |||
56 | /* Imports */ | 60 | /* Imports */ |
57 | extern int compat20; | 61 | extern int compat20; |
58 | extern Newkeys *newkeys[]; | 62 | extern Newkeys *newkeys[]; |
@@ -1100,4 +1104,69 @@ mm_auth_krb5(void *ctx, void *argp, char **userp, void *resp) | |||
1100 | buffer_free(&m); | 1104 | buffer_free(&m); |
1101 | return (success); | 1105 | return (success); |
1102 | } | 1106 | } |
1103 | #endif | 1107 | #endif /* KRB5 */ |
1108 | |||
1109 | #ifdef GSSAPI | ||
1110 | OM_uint32 | ||
1111 | mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) | ||
1112 | { | ||
1113 | Buffer m; | ||
1114 | OM_uint32 major; | ||
1115 | |||
1116 | /* Client doesn't get to see the context */ | ||
1117 | *ctx = NULL; | ||
1118 | |||
1119 | buffer_init(&m); | ||
1120 | buffer_put_string(&m, oid->elements, oid->length); | ||
1121 | |||
1122 | mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSETUP, &m); | ||
1123 | mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSETUP, &m); | ||
1124 | |||
1125 | major = buffer_get_int(&m); | ||
1126 | |||
1127 | buffer_free(&m); | ||
1128 | return (major); | ||
1129 | } | ||
1130 | |||
1131 | OM_uint32 | ||
1132 | mm_ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *in, | ||
1133 | gss_buffer_desc *out, OM_uint32 *flags) | ||
1134 | { | ||
1135 | Buffer m; | ||
1136 | OM_uint32 major; | ||
1137 | |||
1138 | buffer_init(&m); | ||
1139 | buffer_put_string(&m, in->value, in->length); | ||
1140 | |||
1141 | mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTEP, &m); | ||
1142 | mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTEP, &m); | ||
1143 | |||
1144 | major = buffer_get_int(&m); | ||
1145 | out->value = buffer_get_string(&m, &out->length); | ||
1146 | if (flags) | ||
1147 | *flags = buffer_get_int(&m); | ||
1148 | |||
1149 | buffer_free(&m); | ||
1150 | |||
1151 | return (major); | ||
1152 | } | ||
1153 | |||
1154 | int | ||
1155 | mm_ssh_gssapi_userok(char *user) | ||
1156 | { | ||
1157 | Buffer m; | ||
1158 | int authenticated = 0; | ||
1159 | |||
1160 | buffer_init(&m); | ||
1161 | |||
1162 | mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m); | ||
1163 | mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK, | ||
1164 | &m); | ||
1165 | |||
1166 | authenticated = buffer_get_int(&m); | ||
1167 | |||
1168 | buffer_free(&m); | ||
1169 | debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); | ||
1170 | return (authenticated); | ||
1171 | } | ||
1172 | #endif /* GSSAPI */ | ||
diff --git a/monitor_wrap.h b/monitor_wrap.h index ddd42ee28..c6251924a 100644 --- a/monitor_wrap.h +++ b/monitor_wrap.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: monitor_wrap.h,v 1.9 2003/07/22 13:35:22 markus Exp $ */ | 1 | /* $OpenBSD: monitor_wrap.h,v 1.10 2003/08/22 10:56:09 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | 4 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> |
@@ -55,6 +55,14 @@ int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); | |||
55 | int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); | 55 | int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); |
56 | BIGNUM *mm_auth_rsa_generate_challenge(Key *); | 56 | BIGNUM *mm_auth_rsa_generate_challenge(Key *); |
57 | 57 | ||
58 | #ifdef GSSAPI | ||
59 | #include "ssh-gss.h" | ||
60 | OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **ctxt, gss_OID oid); | ||
61 | OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *ctxt, | ||
62 | gss_buffer_desc *recv, gss_buffer_desc *send, OM_uint32 *flags); | ||
63 | int mm_ssh_gssapi_userok(char *user); | ||
64 | #endif | ||
65 | |||
58 | #ifdef USE_PAM | 66 | #ifdef USE_PAM |
59 | void mm_start_pam(char *); | 67 | void mm_start_pam(char *); |
60 | u_int mm_do_pam_account(void); | 68 | u_int mm_do_pam_account(void); |
diff --git a/readconf.c b/readconf.c index 96ad25a51..9447cb55f 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -12,7 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include "includes.h" | 14 | #include "includes.h" |
15 | RCSID("$OpenBSD: readconf.c,v 1.117 2003/08/13 09:07:09 markus Exp $"); | 15 | RCSID("$OpenBSD: readconf.c,v 1.118 2003/08/22 10:56:09 markus Exp $"); |
16 | 16 | ||
17 | #include "ssh.h" | 17 | #include "ssh.h" |
18 | #include "xmalloc.h" | 18 | #include "xmalloc.h" |
@@ -105,7 +105,7 @@ typedef enum { | |||
105 | oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, | 105 | oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, |
106 | oClearAllForwardings, oNoHostAuthenticationForLocalhost, | 106 | oClearAllForwardings, oNoHostAuthenticationForLocalhost, |
107 | oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, | 107 | oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, |
108 | oAddressFamily, | 108 | oAddressFamily, oGssAuthentication, oGssDelegateCreds, |
109 | oDeprecated, oUnsupported | 109 | oDeprecated, oUnsupported |
110 | } OpCodes; | 110 | } OpCodes; |
111 | 111 | ||
@@ -140,6 +140,14 @@ static struct { | |||
140 | { "kerberostgtpassing", oUnsupported }, | 140 | { "kerberostgtpassing", oUnsupported }, |
141 | #endif | 141 | #endif |
142 | { "afstokenpassing", oUnsupported }, | 142 | { "afstokenpassing", oUnsupported }, |
143 | #if defined(GSSAPI) | ||
144 | { "gssapiauthentication", oGssAuthentication }, | ||
145 | { "gssapidelegatecreds", oGssDelegateCreds }, | ||
146 | { "gssapidelegatecredentials", oGssDelegateCreds }, | ||
147 | #else | ||
148 | { "gssapiauthentication", oUnsupported }, | ||
149 | { "gssapidelegatecredentials", oUnsupported }, | ||
150 | #endif | ||
143 | { "fallbacktorsh", oDeprecated }, | 151 | { "fallbacktorsh", oDeprecated }, |
144 | { "usersh", oDeprecated }, | 152 | { "usersh", oDeprecated }, |
145 | { "identityfile", oIdentityFile }, | 153 | { "identityfile", oIdentityFile }, |
@@ -389,6 +397,14 @@ parse_flag: | |||
389 | intptr = &options->kerberos_tgt_passing; | 397 | intptr = &options->kerberos_tgt_passing; |
390 | goto parse_flag; | 398 | goto parse_flag; |
391 | 399 | ||
400 | case oGssAuthentication: | ||
401 | intptr = &options->gss_authentication; | ||
402 | goto parse_flag; | ||
403 | |||
404 | case oGssDelegateCreds: | ||
405 | intptr = &options->gss_deleg_creds; | ||
406 | goto parse_flag; | ||
407 | |||
392 | case oBatchMode: | 408 | case oBatchMode: |
393 | intptr = &options->batch_mode; | 409 | intptr = &options->batch_mode; |
394 | goto parse_flag; | 410 | goto parse_flag; |
@@ -813,6 +829,8 @@ initialize_options(Options * options) | |||
813 | options->challenge_response_authentication = -1; | 829 | options->challenge_response_authentication = -1; |
814 | options->kerberos_authentication = -1; | 830 | options->kerberos_authentication = -1; |
815 | options->kerberos_tgt_passing = -1; | 831 | options->kerberos_tgt_passing = -1; |
832 | options->gss_authentication = -1; | ||
833 | options->gss_deleg_creds = -1; | ||
816 | options->password_authentication = -1; | 834 | options->password_authentication = -1; |
817 | options->kbd_interactive_authentication = -1; | 835 | options->kbd_interactive_authentication = -1; |
818 | options->kbd_interactive_devices = NULL; | 836 | options->kbd_interactive_devices = NULL; |
@@ -887,6 +905,10 @@ fill_default_options(Options * options) | |||
887 | options->kerberos_authentication = 1; | 905 | options->kerberos_authentication = 1; |
888 | if (options->kerberos_tgt_passing == -1) | 906 | if (options->kerberos_tgt_passing == -1) |
889 | options->kerberos_tgt_passing = 1; | 907 | options->kerberos_tgt_passing = 1; |
908 | if (options->gss_authentication == -1) | ||
909 | options->gss_authentication = 1; | ||
910 | if (options->gss_deleg_creds == -1) | ||
911 | options->gss_deleg_creds = 0; | ||
890 | if (options->password_authentication == -1) | 912 | if (options->password_authentication == -1) |
891 | options->password_authentication = 1; | 913 | options->password_authentication = 1; |
892 | if (options->kbd_interactive_authentication == -1) | 914 | if (options->kbd_interactive_authentication == -1) |
diff --git a/readconf.h b/readconf.h index 6fbf467e5..1100205b8 100644 --- a/readconf.h +++ b/readconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.h,v 1.53 2003/08/13 08:46:30 markus Exp $ */ | 1 | /* $OpenBSD: readconf.h,v 1.54 2003/08/22 10:56:09 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -42,6 +42,8 @@ typedef struct { | |||
42 | /* Try S/Key or TIS, authentication. */ | 42 | /* Try S/Key or TIS, authentication. */ |
43 | int kerberos_authentication; /* Try Kerberos authentication. */ | 43 | int kerberos_authentication; /* Try Kerberos authentication. */ |
44 | int kerberos_tgt_passing; /* Try Kerberos TGT passing. */ | 44 | int kerberos_tgt_passing; /* Try Kerberos TGT passing. */ |
45 | int gss_authentication; /* Try GSS authentication */ | ||
46 | int gss_deleg_creds; /* Delegate GSS credentials */ | ||
45 | int password_authentication; /* Try password | 47 | int password_authentication; /* Try password |
46 | * authentication. */ | 48 | * authentication. */ |
47 | int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ | 49 | int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ |
diff --git a/servconf.c b/servconf.c index 09fdbf424..e13309388 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -10,7 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "includes.h" | 12 | #include "includes.h" |
13 | RCSID("$OpenBSD: servconf.c,v 1.124 2003/08/13 08:46:30 markus Exp $"); | 13 | RCSID("$OpenBSD: servconf.c,v 1.125 2003/08/22 10:56:09 markus Exp $"); |
14 | 14 | ||
15 | #include "ssh.h" | 15 | #include "ssh.h" |
16 | #include "log.h" | 16 | #include "log.h" |
@@ -73,6 +73,8 @@ initialize_server_options(ServerOptions *options) | |||
73 | options->kerberos_or_local_passwd = -1; | 73 | options->kerberos_or_local_passwd = -1; |
74 | options->kerberos_ticket_cleanup = -1; | 74 | options->kerberos_ticket_cleanup = -1; |
75 | options->kerberos_tgt_passing = -1; | 75 | options->kerberos_tgt_passing = -1; |
76 | options->gss_authentication=-1; | ||
77 | options->gss_cleanup_creds = -1; | ||
76 | options->password_authentication = -1; | 78 | options->password_authentication = -1; |
77 | options->kbd_interactive_authentication = -1; | 79 | options->kbd_interactive_authentication = -1; |
78 | options->challenge_response_authentication = -1; | 80 | options->challenge_response_authentication = -1; |
@@ -182,6 +184,10 @@ fill_default_server_options(ServerOptions *options) | |||
182 | options->kerberos_ticket_cleanup = 1; | 184 | options->kerberos_ticket_cleanup = 1; |
183 | if (options->kerberos_tgt_passing == -1) | 185 | if (options->kerberos_tgt_passing == -1) |
184 | options->kerberos_tgt_passing = 0; | 186 | options->kerberos_tgt_passing = 0; |
187 | if (options->gss_authentication == -1) | ||
188 | options->gss_authentication = 0; | ||
189 | if (options->gss_cleanup_creds == -1) | ||
190 | options->gss_cleanup_creds = 1; | ||
185 | if (options->password_authentication == -1) | 191 | if (options->password_authentication == -1) |
186 | options->password_authentication = 1; | 192 | options->password_authentication = 1; |
187 | if (options->kbd_interactive_authentication == -1) | 193 | if (options->kbd_interactive_authentication == -1) |
@@ -259,6 +265,7 @@ typedef enum { | |||
259 | sBanner, sUseDNS, sHostbasedAuthentication, | 265 | sBanner, sUseDNS, sHostbasedAuthentication, |
260 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, | 266 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, |
261 | sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, | 267 | sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, |
268 | sGssAuthentication, sGssCleanupCreds, | ||
262 | sUsePrivilegeSeparation, | 269 | sUsePrivilegeSeparation, |
263 | sDeprecated, sUnsupported | 270 | sDeprecated, sUnsupported |
264 | } ServerOpCodes; | 271 | } ServerOpCodes; |
@@ -305,6 +312,13 @@ static struct { | |||
305 | { "kerberostgtpassing", sUnsupported }, | 312 | { "kerberostgtpassing", sUnsupported }, |
306 | #endif | 313 | #endif |
307 | { "afstokenpassing", sUnsupported }, | 314 | { "afstokenpassing", sUnsupported }, |
315 | #ifdef GSSAPI | ||
316 | { "gssapiauthentication", sGssAuthentication }, | ||
317 | { "gssapicleanupcreds", sGssCleanupCreds }, | ||
318 | #else | ||
319 | { "gssapiauthentication", sUnsupported }, | ||
320 | { "gssapicleanupcreds", sUnsupported }, | ||
321 | #endif | ||
308 | { "passwordauthentication", sPasswordAuthentication }, | 322 | { "passwordauthentication", sPasswordAuthentication }, |
309 | { "kbdinteractiveauthentication", sKbdInteractiveAuthentication }, | 323 | { "kbdinteractiveauthentication", sKbdInteractiveAuthentication }, |
310 | { "challengeresponseauthentication", sChallengeResponseAuthentication }, | 324 | { "challengeresponseauthentication", sChallengeResponseAuthentication }, |
@@ -623,6 +637,14 @@ parse_flag: | |||
623 | intptr = &options->kerberos_tgt_passing; | 637 | intptr = &options->kerberos_tgt_passing; |
624 | goto parse_flag; | 638 | goto parse_flag; |
625 | 639 | ||
640 | case sGssAuthentication: | ||
641 | intptr = &options->gss_authentication; | ||
642 | goto parse_flag; | ||
643 | |||
644 | case sGssCleanupCreds: | ||
645 | intptr = &options->gss_cleanup_creds; | ||
646 | goto parse_flag; | ||
647 | |||
626 | case sPasswordAuthentication: | 648 | case sPasswordAuthentication: |
627 | intptr = &options->password_authentication; | 649 | intptr = &options->password_authentication; |
628 | goto parse_flag; | 650 | goto parse_flag; |
diff --git a/servconf.h b/servconf.h index 42bcda757..f86cb2209 100644 --- a/servconf.h +++ b/servconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: servconf.h,v 1.63 2003/08/13 08:46:30 markus Exp $ */ | 1 | /* $OpenBSD: servconf.h,v 1.64 2003/08/22 10:56:09 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -82,6 +82,8 @@ typedef struct { | |||
82 | * file on logout. */ | 82 | * file on logout. */ |
83 | int kerberos_tgt_passing; /* If true, permit Kerberos TGT | 83 | int kerberos_tgt_passing; /* If true, permit Kerberos TGT |
84 | * passing. */ | 84 | * passing. */ |
85 | int gss_authentication; /* If true, permit GSSAPI authentication */ | ||
86 | int gss_cleanup_creds; /* If true, destroy cred cache on logout */ | ||
85 | int password_authentication; /* If true, permit password | 87 | int password_authentication; /* If true, permit password |
86 | * authentication. */ | 88 | * authentication. */ |
87 | int kbd_interactive_authentication; /* If true, permit */ | 89 | int kbd_interactive_authentication; /* If true, permit */ |
@@ -33,7 +33,7 @@ | |||
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include "includes.h" | 35 | #include "includes.h" |
36 | RCSID("$OpenBSD: session.c,v 1.160 2003/08/13 08:33:02 markus Exp $"); | 36 | RCSID("$OpenBSD: session.c,v 1.161 2003/08/22 10:56:09 markus Exp $"); |
37 | 37 | ||
38 | #include "ssh.h" | 38 | #include "ssh.h" |
39 | #include "ssh1.h" | 39 | #include "ssh1.h" |
@@ -58,6 +58,10 @@ RCSID("$OpenBSD: session.c,v 1.160 2003/08/13 08:33:02 markus Exp $"); | |||
58 | #include "session.h" | 58 | #include "session.h" |
59 | #include "monitor_wrap.h" | 59 | #include "monitor_wrap.h" |
60 | 60 | ||
61 | #ifdef GSSAPI | ||
62 | #include "ssh-gss.h" | ||
63 | #endif | ||
64 | |||
61 | /* func */ | 65 | /* func */ |
62 | 66 | ||
63 | Session *session_new(void); | 67 | Session *session_new(void); |
@@ -424,6 +428,12 @@ do_exec_no_pty(Session *s, const char *command) | |||
424 | } | 428 | } |
425 | #endif /* USE_PAM */ | 429 | #endif /* USE_PAM */ |
426 | 430 | ||
431 | #ifdef GSSAPI | ||
432 | temporarily_use_uid(s->pw); | ||
433 | ssh_gssapi_storecreds(); | ||
434 | restore_uid(); | ||
435 | #endif | ||
436 | |||
427 | /* Fork the child. */ | 437 | /* Fork the child. */ |
428 | if ((pid = fork()) == 0) { | 438 | if ((pid = fork()) == 0) { |
429 | fatal_remove_all_cleanups(); | 439 | fatal_remove_all_cleanups(); |
@@ -550,6 +560,12 @@ do_exec_pty(Session *s, const char *command) | |||
550 | } | 560 | } |
551 | #endif | 561 | #endif |
552 | 562 | ||
563 | #ifdef GSSAPI | ||
564 | temporarily_use_uid(s->pw); | ||
565 | ssh_gssapi_storecreds(); | ||
566 | restore_uid(); | ||
567 | #endif | ||
568 | |||
553 | /* Fork the child. */ | 569 | /* Fork the child. */ |
554 | if ((pid = fork()) == 0) { | 570 | if ((pid = fork()) == 0) { |
555 | fatal_remove_all_cleanups(); | 571 | fatal_remove_all_cleanups(); |
@@ -807,7 +823,7 @@ check_quietlogin(Session *s, const char *command) | |||
807 | * Sets the value of the given variable in the environment. If the variable | 823 | * Sets the value of the given variable in the environment. If the variable |
808 | * already exists, its value is overriden. | 824 | * already exists, its value is overriden. |
809 | */ | 825 | */ |
810 | static void | 826 | void |
811 | child_set_env(char ***envp, u_int *envsizep, const char *name, | 827 | child_set_env(char ***envp, u_int *envsizep, const char *name, |
812 | const char *value) | 828 | const char *value) |
813 | { | 829 | { |
@@ -934,6 +950,13 @@ do_setup_env(Session *s, const char *shell) | |||
934 | copy_environment(environ, &env, &envsize); | 950 | copy_environment(environ, &env, &envsize); |
935 | #endif | 951 | #endif |
936 | 952 | ||
953 | #ifdef GSSAPI | ||
954 | /* Allow any GSSAPI methods that we've used to alter | ||
955 | * the childs environment as they see fit | ||
956 | */ | ||
957 | ssh_gssapi_do_child(&env, &envsize); | ||
958 | #endif | ||
959 | |||
937 | if (!options.use_login) { | 960 | if (!options.use_login) { |
938 | /* Set basic environment. */ | 961 | /* Set basic environment. */ |
939 | child_set_env(&env, &envsize, "USER", pw->pw_name); | 962 | child_set_env(&env, &envsize, "USER", pw->pw_name); |
@@ -2088,4 +2111,8 @@ static void | |||
2088 | do_authenticated2(Authctxt *authctxt) | 2111 | do_authenticated2(Authctxt *authctxt) |
2089 | { | 2112 | { |
2090 | server_loop2(authctxt); | 2113 | server_loop2(authctxt); |
2114 | #if defined(GSSAPI) | ||
2115 | if (options.gss_cleanup_creds) | ||
2116 | ssh_gssapi_cleanup_creds(NULL); | ||
2117 | #endif | ||
2091 | } | 2118 | } |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: session.h,v 1.19 2002/06/30 21:59:45 deraadt Exp $ */ | 1 | /* $OpenBSD: session.h,v 1.20 2003/08/22 10:56:09 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
@@ -68,4 +68,7 @@ Session *session_new(void); | |||
68 | Session *session_by_tty(char *); | 68 | Session *session_by_tty(char *); |
69 | void session_close(Session *); | 69 | void session_close(Session *); |
70 | void do_setusercontext(struct passwd *); | 70 | void do_setusercontext(struct passwd *); |
71 | void child_set_env(char ***envp, u_int *envsizep, const char *name, | ||
72 | const char *value); | ||
73 | |||
71 | #endif | 74 | #endif |
diff --git a/ssh-gss.h b/ssh-gss.h new file mode 100644 index 000000000..263e51b94 --- /dev/null +++ b/ssh-gss.h | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | ||
3 | * | ||
4 | * Redistribution and use in source and binary forms, with or without | ||
5 | * modification, are permitted provided that the following conditions | ||
6 | * are met: | ||
7 | * 1. Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * 2. Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * | ||
13 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR | ||
14 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
15 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
16 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
19 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
20 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
23 | */ | ||
24 | |||
25 | #ifndef _SSH_GSS_H | ||
26 | #define _SSH_GSS_H | ||
27 | |||
28 | #ifdef GSSAPI | ||
29 | |||
30 | #include "buffer.h" | ||
31 | |||
32 | #include <gssapi.h> | ||
33 | |||
34 | /* draft-ietf-secsh-gsskeyex-06 */ | ||
35 | #define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60 | ||
36 | #define SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61 | ||
37 | #define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63 | ||
38 | #define SSH2_MSG_USERAUTH_GSSAPI_ERROR 64 | ||
39 | #define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65 | ||
40 | |||
41 | #define SSH_GSS_OIDTYPE 0x06 | ||
42 | |||
43 | typedef struct { | ||
44 | char *filename; | ||
45 | char *envvar; | ||
46 | char *envval; | ||
47 | void *data; | ||
48 | } ssh_gssapi_ccache; | ||
49 | |||
50 | typedef struct { | ||
51 | gss_buffer_desc displayname; | ||
52 | gss_buffer_desc exportedname; | ||
53 | gss_cred_id_t creds; | ||
54 | struct ssh_gssapi_mech_struct *mech; | ||
55 | ssh_gssapi_ccache store; | ||
56 | } ssh_gssapi_client; | ||
57 | |||
58 | typedef struct ssh_gssapi_mech_struct { | ||
59 | char *enc_name; | ||
60 | char *name; | ||
61 | gss_OID_desc oid; | ||
62 | int (*dochild) (ssh_gssapi_client *); | ||
63 | int (*userok) (ssh_gssapi_client *, char *); | ||
64 | int (*localname) (ssh_gssapi_client *, char **); | ||
65 | void (*storecreds) (ssh_gssapi_client *); | ||
66 | } ssh_gssapi_mech; | ||
67 | |||
68 | typedef struct { | ||
69 | OM_uint32 major; /* both */ | ||
70 | OM_uint32 minor; /* both */ | ||
71 | gss_ctx_id_t context; /* both */ | ||
72 | gss_name_t name; /* both */ | ||
73 | gss_OID oid; /* client */ | ||
74 | gss_cred_id_t creds; /* server */ | ||
75 | gss_name_t client; /* server */ | ||
76 | gss_cred_id_t client_creds; /* server */ | ||
77 | } Gssctxt; | ||
78 | |||
79 | extern ssh_gssapi_mech *supported_mechs[]; | ||
80 | |||
81 | int ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len); | ||
82 | void ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len); | ||
83 | void ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid); | ||
84 | void ssh_gssapi_supported_oids(gss_OID_set *oidset); | ||
85 | ssh_gssapi_mech *ssh_gssapi_get_ctype(Gssctxt *ctxt); | ||
86 | |||
87 | OM_uint32 ssh_gssapi_import_name(Gssctxt *ctx, const char *host); | ||
88 | OM_uint32 ssh_gssapi_acquire_cred(Gssctxt *ctx); | ||
89 | OM_uint32 ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, | ||
90 | gss_buffer_desc *recv_tok, gss_buffer_desc *send_tok, OM_uint32 *flags); | ||
91 | OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx, | ||
92 | gss_buffer_desc *recv_tok, gss_buffer_desc *send_tok, OM_uint32 *flags); | ||
93 | OM_uint32 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *); | ||
94 | void ssh_gssapi_error(Gssctxt *ctx); | ||
95 | char *ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min); | ||
96 | void ssh_gssapi_build_ctx(Gssctxt **ctx); | ||
97 | void ssh_gssapi_delete_ctx(Gssctxt **ctx); | ||
98 | OM_uint32 ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid); | ||
99 | |||
100 | /* In the server */ | ||
101 | int ssh_gssapi_userok(char *name); | ||
102 | |||
103 | void ssh_gssapi_do_child(char ***envp, u_int *envsizep); | ||
104 | void ssh_gssapi_cleanup_creds(void *ignored); | ||
105 | void ssh_gssapi_storecreds(void); | ||
106 | |||
107 | #endif /* GSSAPI */ | ||
108 | |||
109 | #endif /* _SSH_GSS_H */ | ||
diff --git a/ssh_config.5 b/ssh_config.5 index fb341d79b..f99562b96 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -34,7 +34,7 @@ | |||
34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 | .\" | 36 | .\" |
37 | .\" $OpenBSD: ssh_config.5,v 1.17 2003/08/13 08:46:31 markus Exp $ | 37 | .\" $OpenBSD: ssh_config.5,v 1.18 2003/08/22 10:56:09 markus Exp $ |
38 | .Dd September 25, 1999 | 38 | .Dd September 25, 1999 |
39 | .Dt SSH_CONFIG 5 | 39 | .Dt SSH_CONFIG 5 |
40 | .Os | 40 | .Os |
@@ -331,6 +331,18 @@ The default is | |||
331 | Specifies a file to use for the global | 331 | Specifies a file to use for the global |
332 | host key database instead of | 332 | host key database instead of |
333 | .Pa /etc/ssh/ssh_known_hosts . | 333 | .Pa /etc/ssh/ssh_known_hosts . |
334 | .It Cm GSSAPIAuthentication | ||
335 | Specifies whether authentication based on GSSAPI may be used, either using | ||
336 | the result of a successful key exchange, or using GSSAPI user | ||
337 | authentication. | ||
338 | The default is | ||
339 | .Dq yes . | ||
340 | Note that this option applies to protocol version 2 only. | ||
341 | .It Cm GSSAPIDelegateCredentials | ||
342 | Forward (delegate) credentials to the server. | ||
343 | The default is | ||
344 | .Dq no . | ||
345 | Note that this option applies to protocol version 2 only. | ||
334 | .It Cm HostbasedAuthentication | 346 | .It Cm HostbasedAuthentication |
335 | Specifies whether to try rhosts based authentication with public key | 347 | Specifies whether to try rhosts based authentication with public key |
336 | authentication. | 348 | authentication. |
diff --git a/sshconnect2.c b/sshconnect2.c index 6a0bd409a..c71ad506b 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: sshconnect2.c,v 1.120 2003/06/24 08:23:46 markus Exp $"); | 26 | RCSID("$OpenBSD: sshconnect2.c,v 1.121 2003/08/22 10:56:09 markus Exp $"); |
27 | 27 | ||
28 | #ifdef KRB5 | 28 | #ifdef KRB5 |
29 | #include <krb5.h> | 29 | #include <krb5.h> |
@@ -57,6 +57,10 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.120 2003/06/24 08:23:46 markus Exp $"); | |||
57 | #include "msg.h" | 57 | #include "msg.h" |
58 | #include "pathnames.h" | 58 | #include "pathnames.h" |
59 | 59 | ||
60 | #ifdef GSSAPI | ||
61 | #include "ssh-gss.h" | ||
62 | #endif | ||
63 | |||
60 | /* import */ | 64 | /* import */ |
61 | extern char *client_version_string; | 65 | extern char *client_version_string; |
62 | extern char *server_version_string; | 66 | extern char *server_version_string; |
@@ -178,6 +182,8 @@ struct Authctxt { | |||
178 | Sensitive *sensitive; | 182 | Sensitive *sensitive; |
179 | /* kbd-interactive */ | 183 | /* kbd-interactive */ |
180 | int info_req_seen; | 184 | int info_req_seen; |
185 | /* generic */ | ||
186 | void *methoddata; | ||
181 | }; | 187 | }; |
182 | struct Authmethod { | 188 | struct Authmethod { |
183 | char *name; /* string to compare against server's list */ | 189 | char *name; /* string to compare against server's list */ |
@@ -201,6 +207,15 @@ int userauth_kbdint(Authctxt *); | |||
201 | int userauth_hostbased(Authctxt *); | 207 | int userauth_hostbased(Authctxt *); |
202 | int userauth_kerberos(Authctxt *); | 208 | int userauth_kerberos(Authctxt *); |
203 | 209 | ||
210 | #ifdef GSSAPI | ||
211 | int userauth_gssapi(Authctxt *authctxt); | ||
212 | void input_gssapi_response(int type, u_int32_t, void *); | ||
213 | void input_gssapi_token(int type, u_int32_t, void *); | ||
214 | void input_gssapi_hash(int type, u_int32_t, void *); | ||
215 | void input_gssapi_error(int, u_int32_t, void *); | ||
216 | void input_gssapi_errtok(int, u_int32_t, void *); | ||
217 | #endif | ||
218 | |||
204 | void userauth(Authctxt *, char *); | 219 | void userauth(Authctxt *, char *); |
205 | 220 | ||
206 | static int sign_and_send_pubkey(Authctxt *, Identity *); | 221 | static int sign_and_send_pubkey(Authctxt *, Identity *); |
@@ -213,6 +228,12 @@ static Authmethod *authmethod_lookup(const char *name); | |||
213 | static char *authmethods_get(void); | 228 | static char *authmethods_get(void); |
214 | 229 | ||
215 | Authmethod authmethods[] = { | 230 | Authmethod authmethods[] = { |
231 | #ifdef GSSAPI | ||
232 | {"gssapi", | ||
233 | userauth_gssapi, | ||
234 | &options.gss_authentication, | ||
235 | NULL}, | ||
236 | #endif | ||
216 | {"hostbased", | 237 | {"hostbased", |
217 | userauth_hostbased, | 238 | userauth_hostbased, |
218 | &options.hostbased_authentication, | 239 | &options.hostbased_authentication, |
@@ -283,6 +304,7 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, | |||
283 | authctxt.success = 0; | 304 | authctxt.success = 0; |
284 | authctxt.method = authmethod_lookup("none"); | 305 | authctxt.method = authmethod_lookup("none"); |
285 | authctxt.authlist = NULL; | 306 | authctxt.authlist = NULL; |
307 | authctxt.methoddata = NULL; | ||
286 | authctxt.sensitive = sensitive; | 308 | authctxt.sensitive = sensitive; |
287 | authctxt.info_req_seen = 0; | 309 | authctxt.info_req_seen = 0; |
288 | if (authctxt.method == NULL) | 310 | if (authctxt.method == NULL) |
@@ -306,6 +328,10 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, | |||
306 | void | 328 | void |
307 | userauth(Authctxt *authctxt, char *authlist) | 329 | userauth(Authctxt *authctxt, char *authlist) |
308 | { | 330 | { |
331 | if (authctxt->methoddata) { | ||
332 | xfree(authctxt->methoddata); | ||
333 | authctxt->methoddata = NULL; | ||
334 | } | ||
309 | if (authlist == NULL) { | 335 | if (authlist == NULL) { |
310 | authlist = authctxt->authlist; | 336 | authlist = authctxt->authlist; |
311 | } else { | 337 | } else { |
@@ -361,6 +387,8 @@ input_userauth_success(int type, u_int32_t seq, void *ctxt) | |||
361 | fatal("input_userauth_success: no authentication context"); | 387 | fatal("input_userauth_success: no authentication context"); |
362 | if (authctxt->authlist) | 388 | if (authctxt->authlist) |
363 | xfree(authctxt->authlist); | 389 | xfree(authctxt->authlist); |
390 | if (authctxt->methoddata) | ||
391 | xfree(authctxt->methoddata); | ||
364 | authctxt->success = 1; /* break out */ | 392 | authctxt->success = 1; /* break out */ |
365 | } | 393 | } |
366 | 394 | ||
@@ -449,6 +477,228 @@ done: | |||
449 | userauth(authctxt, NULL); | 477 | userauth(authctxt, NULL); |
450 | } | 478 | } |
451 | 479 | ||
480 | #ifdef GSSAPI | ||
481 | int | ||
482 | userauth_gssapi(Authctxt *authctxt) | ||
483 | { | ||
484 | Gssctxt *gssctxt = NULL; | ||
485 | static gss_OID_set supported = NULL; | ||
486 | static int mech = 0; | ||
487 | OM_uint32 min; | ||
488 | int ok = 0; | ||
489 | |||
490 | /* Try one GSSAPI method at a time, rather than sending them all at | ||
491 | * once. */ | ||
492 | |||
493 | if (supported == NULL) | ||
494 | gss_indicate_mechs(&min, &supported); | ||
495 | |||
496 | /* Check to see if the mechanism is usable before we offer it */ | ||
497 | while (mech<supported->count && !ok) { | ||
498 | if (gssctxt) | ||
499 | ssh_gssapi_delete_ctx(&gssctxt); | ||
500 | ssh_gssapi_build_ctx(&gssctxt); | ||
501 | ssh_gssapi_set_oid(gssctxt, &supported->elements[mech]); | ||
502 | |||
503 | /* My DER encoding requires length<128 */ | ||
504 | if (supported->elements[mech].length < 128 && | ||
505 | !GSS_ERROR(ssh_gssapi_import_name(gssctxt, | ||
506 | authctxt->host))) { | ||
507 | ok = 1; /* Mechanism works */ | ||
508 | } else { | ||
509 | mech++; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | if (!ok) return 0; | ||
514 | |||
515 | authctxt->methoddata=(void *)gssctxt; | ||
516 | |||
517 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
518 | packet_put_cstring(authctxt->server_user); | ||
519 | packet_put_cstring(authctxt->service); | ||
520 | packet_put_cstring(authctxt->method->name); | ||
521 | |||
522 | packet_put_int(1); | ||
523 | |||
524 | /* Some servers encode the OID incorrectly (as we used to) */ | ||
525 | if (datafellows & SSH_BUG_GSSAPI_BER) { | ||
526 | packet_put_string(supported->elements[mech].elements, | ||
527 | supported->elements[mech].length); | ||
528 | } else { | ||
529 | packet_put_int((supported->elements[mech].length)+2); | ||
530 | packet_put_char(SSH_GSS_OIDTYPE); | ||
531 | packet_put_char(supported->elements[mech].length); | ||
532 | packet_put_raw(supported->elements[mech].elements, | ||
533 | supported->elements[mech].length); | ||
534 | } | ||
535 | |||
536 | packet_send(); | ||
537 | |||
538 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response); | ||
539 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); | ||
540 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error); | ||
541 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); | ||
542 | |||
543 | mech++; /* Move along to next candidate */ | ||
544 | |||
545 | return 1; | ||
546 | } | ||
547 | |||
548 | void | ||
549 | input_gssapi_response(int type, u_int32_t plen, void *ctxt) | ||
550 | { | ||
551 | Authctxt *authctxt = ctxt; | ||
552 | Gssctxt *gssctxt; | ||
553 | OM_uint32 status, ms; | ||
554 | int oidlen; | ||
555 | char *oidv; | ||
556 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
557 | |||
558 | if (authctxt == NULL) | ||
559 | fatal("input_gssapi_response: no authentication context"); | ||
560 | gssctxt = authctxt->methoddata; | ||
561 | |||
562 | /* Setup our OID */ | ||
563 | oidv = packet_get_string(&oidlen); | ||
564 | |||
565 | if (datafellows & SSH_BUG_GSSAPI_BER) { | ||
566 | if (!ssh_gssapi_check_oid(gssctxt, oidv, oidlen)) | ||
567 | fatal("Server returned different OID than expected"); | ||
568 | } else { | ||
569 | if(oidv[0] != SSH_GSS_OIDTYPE || oidv[1] != oidlen-2) { | ||
570 | debug("Badly encoded mechanism OID received"); | ||
571 | userauth(authctxt, NULL); | ||
572 | xfree(oidv); | ||
573 | return; | ||
574 | } | ||
575 | if (!ssh_gssapi_check_oid(gssctxt, oidv+2, oidlen-2)) | ||
576 | fatal("Server returned different OID than expected"); | ||
577 | } | ||
578 | |||
579 | packet_check_eom(); | ||
580 | |||
581 | xfree(oidv); | ||
582 | |||
583 | status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, | ||
584 | GSS_C_NO_BUFFER, &send_tok, NULL); | ||
585 | if (GSS_ERROR(status)) { | ||
586 | if (send_tok.length > 0) { | ||
587 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); | ||
588 | packet_put_string(send_tok.value, send_tok.length); | ||
589 | packet_send(); | ||
590 | gss_release_buffer(&ms, &send_tok); | ||
591 | } | ||
592 | /* Start again with next method on list */ | ||
593 | debug("Trying to start again"); | ||
594 | userauth(authctxt, NULL); | ||
595 | return; | ||
596 | } | ||
597 | |||
598 | /* We must have data to send */ | ||
599 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); | ||
600 | packet_put_string(send_tok.value, send_tok.length); | ||
601 | packet_send(); | ||
602 | gss_release_buffer(&ms, &send_tok); | ||
603 | } | ||
604 | |||
605 | void | ||
606 | input_gssapi_token(int type, u_int32_t plen, void *ctxt) | ||
607 | { | ||
608 | Authctxt *authctxt = ctxt; | ||
609 | Gssctxt *gssctxt; | ||
610 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
611 | gss_buffer_desc recv_tok; | ||
612 | OM_uint32 status, ms; | ||
613 | u_int slen; | ||
614 | |||
615 | if (authctxt == NULL) | ||
616 | fatal("input_gssapi_response: no authentication context"); | ||
617 | gssctxt = authctxt->methoddata; | ||
618 | |||
619 | recv_tok.value = packet_get_string(&slen); | ||
620 | recv_tok.length = slen; /* safe typecast */ | ||
621 | |||
622 | packet_check_eom(); | ||
623 | |||
624 | status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, | ||
625 | &recv_tok, &send_tok, NULL); | ||
626 | |||
627 | xfree(recv_tok.value); | ||
628 | |||
629 | if (GSS_ERROR(status)) { | ||
630 | if (send_tok.length > 0) { | ||
631 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); | ||
632 | packet_put_string(send_tok.value, send_tok.length); | ||
633 | packet_send(); | ||
634 | gss_release_buffer(&ms, &send_tok); | ||
635 | } | ||
636 | /* Start again with the next method in the list */ | ||
637 | userauth(authctxt, NULL); | ||
638 | return; | ||
639 | } | ||
640 | |||
641 | if (send_tok.length > 0) { | ||
642 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); | ||
643 | packet_put_string(send_tok.value, send_tok.length); | ||
644 | packet_send(); | ||
645 | gss_release_buffer(&ms, &send_tok); | ||
646 | } | ||
647 | |||
648 | if (status == GSS_S_COMPLETE) { | ||
649 | /* If that succeeded, send a exchange complete message */ | ||
650 | packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); | ||
651 | packet_send(); | ||
652 | } | ||
653 | } | ||
654 | |||
655 | void | ||
656 | input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) | ||
657 | { | ||
658 | Authctxt *authctxt = ctxt; | ||
659 | Gssctxt *gssctxt; | ||
660 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
661 | gss_buffer_desc recv_tok; | ||
662 | OM_uint32 status, ms; | ||
663 | |||
664 | if (authctxt == NULL) | ||
665 | fatal("input_gssapi_response: no authentication context"); | ||
666 | gssctxt = authctxt->methoddata; | ||
667 | |||
668 | recv_tok.value = packet_get_string(&recv_tok.length); | ||
669 | |||
670 | packet_check_eom(); | ||
671 | |||
672 | /* Stick it into GSSAPI and see what it says */ | ||
673 | status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, | ||
674 | &recv_tok, &send_tok, NULL); | ||
675 | |||
676 | xfree(recv_tok.value); | ||
677 | gss_release_buffer(&ms, &send_tok); | ||
678 | |||
679 | /* Server will be returning a failed packet after this one */ | ||
680 | } | ||
681 | |||
682 | void | ||
683 | input_gssapi_error(int type, u_int32_t plen, void *ctxt) | ||
684 | { | ||
685 | OM_uint32 maj, min; | ||
686 | char *msg; | ||
687 | char *lang; | ||
688 | |||
689 | maj=packet_get_int(); | ||
690 | min=packet_get_int(); | ||
691 | msg=packet_get_string(NULL); | ||
692 | lang=packet_get_string(NULL); | ||
693 | |||
694 | packet_check_eom(); | ||
695 | |||
696 | debug("Server GSSAPI Error:\n%s\n", msg); | ||
697 | xfree(msg); | ||
698 | xfree(lang); | ||
699 | } | ||
700 | #endif /* GSSAPI */ | ||
701 | |||
452 | int | 702 | int |
453 | userauth_none(Authctxt *authctxt) | 703 | userauth_none(Authctxt *authctxt) |
454 | { | 704 | { |
diff --git a/sshd_config b/sshd_config index a2bd2ff60..294539096 100644 --- a/sshd_config +++ b/sshd_config | |||
@@ -1,4 +1,4 @@ | |||
1 | # $OpenBSD: sshd_config,v 1.63 2003/08/13 08:46:31 markus Exp $ | 1 | # $OpenBSD: sshd_config,v 1.64 2003/08/22 10:56:09 markus Exp $ |
2 | 2 | ||
3 | # This is the sshd server system-wide configuration file. See | 3 | # This is the sshd server system-wide configuration file. See |
4 | # sshd_config(5) for more information. | 4 | # sshd_config(5) for more information. |
@@ -63,6 +63,10 @@ | |||
63 | #KerberosTicketCleanup yes | 63 | #KerberosTicketCleanup yes |
64 | #KerberosTgtPassing no | 64 | #KerberosTgtPassing no |
65 | 65 | ||
66 | # GSSAPI options | ||
67 | #GSSAPIAuthentication no | ||
68 | #GSSAPICleanupCreds yes | ||
69 | |||
66 | # Set this to 'yes' to enable PAM authentication (via challenge-response) | 70 | # Set this to 'yes' to enable PAM authentication (via challenge-response) |
67 | # and session processing. Depending on your PAM configuration, this may | 71 | # and session processing. Depending on your PAM configuration, this may |
68 | # bypass the setting of 'PasswordAuthentication' | 72 | # bypass the setting of 'PasswordAuthentication' |
diff --git a/sshd_config.5 b/sshd_config.5 index 3d920cc80..8857c673d 100644 --- a/sshd_config.5 +++ b/sshd_config.5 | |||
@@ -34,7 +34,7 @@ | |||
34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 | .\" | 36 | .\" |
37 | .\" $OpenBSD: sshd_config.5,v 1.22 2003/08/13 08:46:31 markus Exp $ | 37 | .\" $OpenBSD: sshd_config.5,v 1.23 2003/08/22 10:56:09 markus Exp $ |
38 | .Dd September 25, 1999 | 38 | .Dd September 25, 1999 |
39 | .Dt SSHD_CONFIG 5 | 39 | .Dt SSHD_CONFIG 5 |
40 | .Os | 40 | .Os |
@@ -225,6 +225,19 @@ or | |||
225 | .Dq no . | 225 | .Dq no . |
226 | The default is | 226 | The default is |
227 | .Dq no . | 227 | .Dq no . |
228 | .It Cm GSSAPIAuthentication | ||
229 | Specifies whether authentication based on GSSAPI may be used, either using | ||
230 | the result of a successful key exchange, or using GSSAPI user | ||
231 | authentication. | ||
232 | The default is | ||
233 | .Dq no . | ||
234 | Note that this option applies to protocol version 2 only. | ||
235 | .It Cm GSSAPICleanupCredentials | ||
236 | Specifies whether to automatically destroy the user's credentials cache | ||
237 | on logout. | ||
238 | The default is | ||
239 | .Dq yes . | ||
240 | Note that this option applies to protocol version 2 only. | ||
228 | .It Cm HostbasedAuthentication | 241 | .It Cm HostbasedAuthentication |
229 | Specifies whether rhosts or /etc/hosts.equiv authentication together | 242 | Specifies whether rhosts or /etc/hosts.equiv authentication together |
230 | with successful public key client host authentication is allowed | 243 | with successful public key client host authentication is allowed |