diff options
-rw-r--r-- | auth.c | 62 | ||||
-rw-r--r-- | auth.h | 48 | ||||
-rw-r--r-- | auth2-gss.c | 12 | ||||
-rw-r--r-- | auth2-hostbased.c | 8 | ||||
-rw-r--r-- | auth2-pubkey.c | 80 | ||||
-rw-r--r-- | auth2.c | 133 | ||||
-rw-r--r-- | gss-serv.c | 11 | ||||
-rw-r--r-- | monitor.c | 41 | ||||
-rw-r--r-- | servconf.c | 13 | ||||
-rw-r--r-- | servconf.h | 3 | ||||
-rw-r--r-- | session.c | 54 | ||||
-rw-r--r-- | ssh-gss.h | 3 | ||||
-rw-r--r-- | sshd_config.5 | 10 |
13 files changed, 338 insertions, 140 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth.c,v 1.121 2017/05/30 08:52:19 markus Exp $ */ | 1 | /* $OpenBSD: auth.c,v 1.122 2017/06/24 06:34:38 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -267,21 +267,41 @@ allowed_user(struct passwd * pw) | |||
267 | return 1; | 267 | return 1; |
268 | } | 268 | } |
269 | 269 | ||
270 | void | 270 | /* |
271 | auth_info(Authctxt *authctxt, const char *fmt, ...) | 271 | * Formats any key left in authctxt->auth_method_key for inclusion in |
272 | * auth_log()'s message. Also includes authxtct->auth_method_info if present. | ||
273 | */ | ||
274 | static char * | ||
275 | format_method_key(Authctxt *authctxt) | ||
272 | { | 276 | { |
273 | va_list ap; | 277 | const struct sshkey *key = authctxt->auth_method_key; |
274 | int i; | 278 | const char *methinfo = authctxt->auth_method_info; |
275 | 279 | char *fp, *ret = NULL; | |
276 | free(authctxt->info); | ||
277 | authctxt->info = NULL; | ||
278 | 280 | ||
279 | va_start(ap, fmt); | 281 | if (key == NULL) |
280 | i = vasprintf(&authctxt->info, fmt, ap); | 282 | return NULL; |
281 | va_end(ap); | ||
282 | 283 | ||
283 | if (i < 0 || authctxt->info == NULL) | 284 | if (key_is_cert(key)) { |
284 | fatal("vasprintf failed"); | 285 | fp = sshkey_fingerprint(key->cert->signature_key, |
286 | options.fingerprint_hash, SSH_FP_DEFAULT); | ||
287 | xasprintf(&ret, "%s ID %s (serial %llu) CA %s %s%s%s", | ||
288 | sshkey_type(key), key->cert->key_id, | ||
289 | (unsigned long long)key->cert->serial, | ||
290 | sshkey_type(key->cert->signature_key), | ||
291 | fp == NULL ? "(null)" : fp, | ||
292 | methinfo == NULL ? "" : ", ", | ||
293 | methinfo == NULL ? "" : methinfo); | ||
294 | free(fp); | ||
295 | } else { | ||
296 | fp = sshkey_fingerprint(key, options.fingerprint_hash, | ||
297 | SSH_FP_DEFAULT); | ||
298 | xasprintf(&ret, "%s %s%s%s", sshkey_type(key), | ||
299 | fp == NULL ? "(null)" : fp, | ||
300 | methinfo == NULL ? "" : ", ", | ||
301 | methinfo == NULL ? "" : methinfo); | ||
302 | free(fp); | ||
303 | } | ||
304 | return ret; | ||
285 | } | 305 | } |
286 | 306 | ||
287 | void | 307 | void |
@@ -290,7 +310,8 @@ auth_log(Authctxt *authctxt, int authenticated, int partial, | |||
290 | { | 310 | { |
291 | struct ssh *ssh = active_state; /* XXX */ | 311 | struct ssh *ssh = active_state; /* XXX */ |
292 | void (*authlog) (const char *fmt,...) = verbose; | 312 | void (*authlog) (const char *fmt,...) = verbose; |
293 | char *authmsg; | 313 | const char *authmsg; |
314 | char *extra = NULL; | ||
294 | 315 | ||
295 | if (use_privsep && !mm_is_monitor() && !authctxt->postponed) | 316 | if (use_privsep && !mm_is_monitor() && !authctxt->postponed) |
296 | return; | 317 | return; |
@@ -309,6 +330,11 @@ auth_log(Authctxt *authctxt, int authenticated, int partial, | |||
309 | else | 330 | else |
310 | authmsg = authenticated ? "Accepted" : "Failed"; | 331 | authmsg = authenticated ? "Accepted" : "Failed"; |
311 | 332 | ||
333 | if ((extra = format_method_key(authctxt)) == NULL) { | ||
334 | if (authctxt->auth_method_info != NULL) | ||
335 | extra = xstrdup(authctxt->auth_method_info); | ||
336 | } | ||
337 | |||
312 | authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s", | 338 | authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s", |
313 | authmsg, | 339 | authmsg, |
314 | method, | 340 | method, |
@@ -317,10 +343,10 @@ auth_log(Authctxt *authctxt, int authenticated, int partial, | |||
317 | authctxt->user, | 343 | authctxt->user, |
318 | ssh_remote_ipaddr(ssh), | 344 | ssh_remote_ipaddr(ssh), |
319 | ssh_remote_port(ssh), | 345 | ssh_remote_port(ssh), |
320 | authctxt->info != NULL ? ": " : "", | 346 | extra != NULL ? ": " : "", |
321 | authctxt->info != NULL ? authctxt->info : ""); | 347 | extra != NULL ? extra : ""); |
322 | free(authctxt->info); | 348 | |
323 | authctxt->info = NULL; | 349 | free(extra); |
324 | 350 | ||
325 | #ifdef CUSTOM_FAILED_LOGIN | 351 | #ifdef CUSTOM_FAILED_LOGIN |
326 | if (authenticated == 0 && !authctxt->postponed && | 352 | if (authenticated == 0 && !authctxt->postponed && |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth.h,v 1.91 2017/05/30 14:29:59 markus Exp $ */ | 1 | /* $OpenBSD: auth.h,v 1.92 2017/06/24 06:34:38 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
@@ -44,6 +44,7 @@ | |||
44 | 44 | ||
45 | struct ssh; | 45 | struct ssh; |
46 | struct sshkey; | 46 | struct sshkey; |
47 | struct sshbuf; | ||
47 | 48 | ||
48 | typedef struct Authctxt Authctxt; | 49 | typedef struct Authctxt Authctxt; |
49 | typedef struct Authmethod Authmethod; | 50 | typedef struct Authmethod Authmethod; |
@@ -62,13 +63,17 @@ struct Authctxt { | |||
62 | char *service; | 63 | char *service; |
63 | struct passwd *pw; /* set if 'valid' */ | 64 | struct passwd *pw; /* set if 'valid' */ |
64 | char *style; | 65 | char *style; |
66 | |||
67 | /* Method lists for multiple authentication */ | ||
68 | char **auth_methods; /* modified from server config */ | ||
69 | u_int num_auth_methods; | ||
70 | |||
71 | /* Authentication method-specific data */ | ||
72 | void *methoddata; | ||
65 | void *kbdintctxt; | 73 | void *kbdintctxt; |
66 | char *info; /* Extra info for next auth_log */ | ||
67 | #ifdef BSD_AUTH | 74 | #ifdef BSD_AUTH |
68 | auth_session_t *as; | 75 | auth_session_t *as; |
69 | #endif | 76 | #endif |
70 | char **auth_methods; /* modified from server config */ | ||
71 | u_int num_auth_methods; | ||
72 | #ifdef KRB5 | 77 | #ifdef KRB5 |
73 | krb5_context krb5_ctx; | 78 | krb5_context krb5_ctx; |
74 | krb5_ccache krb5_fwd_ccache; | 79 | krb5_ccache krb5_fwd_ccache; |
@@ -76,12 +81,20 @@ struct Authctxt { | |||
76 | char *krb5_ticket_file; | 81 | char *krb5_ticket_file; |
77 | char *krb5_ccname; | 82 | char *krb5_ccname; |
78 | #endif | 83 | #endif |
79 | Buffer *loginmsg; | 84 | struct sshbuf *loginmsg; |
80 | void *methoddata; | 85 | |
86 | /* Authentication keys already used; these will be refused henceforth */ | ||
87 | struct sshkey **prev_keys; | ||
88 | u_int nprev_keys; | ||
81 | 89 | ||
82 | struct sshkey **prev_userkeys; | 90 | /* Last used key and ancilliary information from active auth method */ |
83 | u_int nprev_userkeys; | 91 | struct sshkey *auth_method_key; |
92 | char *auth_method_info; | ||
93 | |||
94 | /* Information exposed to session */ | ||
95 | struct sshbuf *session_info; /* Auth info for environment */ | ||
84 | }; | 96 | }; |
97 | |||
85 | /* | 98 | /* |
86 | * Every authentication method has to handle authentication requests for | 99 | * Every authentication method has to handle authentication requests for |
87 | * non-existing users, or for users that are not allowed to login. In this | 100 | * non-existing users, or for users that are not allowed to login. In this |
@@ -120,10 +133,18 @@ int auth_password(Authctxt *, const char *); | |||
120 | int hostbased_key_allowed(struct passwd *, const char *, char *, | 133 | int hostbased_key_allowed(struct passwd *, const char *, char *, |
121 | struct sshkey *); | 134 | struct sshkey *); |
122 | int user_key_allowed(struct passwd *, struct sshkey *, int); | 135 | int user_key_allowed(struct passwd *, struct sshkey *, int); |
123 | void pubkey_auth_info(Authctxt *, const struct sshkey *, const char *, ...) | 136 | int auth2_key_already_used(Authctxt *, const struct sshkey *); |
124 | __attribute__((__format__ (printf, 3, 4))); | 137 | |
125 | void auth2_record_userkey(Authctxt *, struct sshkey *); | 138 | /* |
126 | int auth2_userkey_already_used(Authctxt *, struct sshkey *); | 139 | * Handling auth method-specific information for logging and prevention |
140 | * of key reuse during multiple authentication. | ||
141 | */ | ||
142 | void auth2_authctxt_reset_info(Authctxt *); | ||
143 | void auth2_record_key(Authctxt *, int, const struct sshkey *); | ||
144 | void auth2_record_info(Authctxt *authctxt, const char *, ...) | ||
145 | __attribute__((__format__ (printf, 2, 3))) | ||
146 | __attribute__((__nonnull__ (2))); | ||
147 | void auth2_update_session_info(Authctxt *, const char *, const char *); | ||
127 | 148 | ||
128 | struct stat; | 149 | struct stat; |
129 | int auth_secure_path(const char *, struct stat *, const char *, uid_t, | 150 | int auth_secure_path(const char *, struct stat *, const char *, uid_t, |
@@ -150,9 +171,6 @@ void disable_forwarding(void); | |||
150 | 171 | ||
151 | void do_authentication2(Authctxt *); | 172 | void do_authentication2(Authctxt *); |
152 | 173 | ||
153 | void auth_info(Authctxt *authctxt, const char *, ...) | ||
154 | __attribute__((__format__ (printf, 2, 3))) | ||
155 | __attribute__((__nonnull__ (2))); | ||
156 | void auth_log(Authctxt *, int, int, const char *, const char *); | 174 | void auth_log(Authctxt *, int, int, const char *, const char *); |
157 | void auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn)); | 175 | void auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn)); |
158 | void userauth_finish(struct ssh *, int, const char *, const char *); | 176 | void userauth_finish(struct ssh *, int, const char *, const char *); |
diff --git a/auth2-gss.c b/auth2-gss.c index 680d5e712..589283b72 100644 --- a/auth2-gss.c +++ b/auth2-gss.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-gss.c,v 1.25 2017/05/30 14:29:59 markus Exp $ */ | 1 | /* $OpenBSD: auth2-gss.c,v 1.26 2017/06/24 06:34:38 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | 4 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. |
@@ -228,6 +228,7 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) | |||
228 | { | 228 | { |
229 | Authctxt *authctxt = ssh->authctxt; | 229 | Authctxt *authctxt = ssh->authctxt; |
230 | int authenticated; | 230 | int authenticated; |
231 | const char *displayname; | ||
231 | 232 | ||
232 | if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) | 233 | if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) |
233 | fatal("No authentication or GSSAPI context"); | 234 | fatal("No authentication or GSSAPI context"); |
@@ -241,6 +242,10 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) | |||
241 | 242 | ||
242 | authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); | 243 | authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); |
243 | 244 | ||
245 | if ((!use_privsep || mm_is_monitor()) && | ||
246 | (displayname = ssh_gssapi_displayname()) != NULL) | ||
247 | auth2_record_info(authctxt, "%s", displayname); | ||
248 | |||
244 | authctxt->postponed = 0; | 249 | authctxt->postponed = 0; |
245 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); | 250 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); |
246 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); | 251 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); |
@@ -259,6 +264,7 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) | |||
259 | Buffer b; | 264 | Buffer b; |
260 | gss_buffer_desc mic, gssbuf; | 265 | gss_buffer_desc mic, gssbuf; |
261 | u_int len; | 266 | u_int len; |
267 | const char *displayname; | ||
262 | 268 | ||
263 | if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) | 269 | if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) |
264 | fatal("No authentication or GSSAPI context"); | 270 | fatal("No authentication or GSSAPI context"); |
@@ -282,6 +288,10 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) | |||
282 | buffer_free(&b); | 288 | buffer_free(&b); |
283 | free(mic.value); | 289 | free(mic.value); |
284 | 290 | ||
291 | if ((!use_privsep || mm_is_monitor()) && | ||
292 | (displayname = ssh_gssapi_displayname()) != NULL) | ||
293 | auth2_record_info(authctxt, "%s", displayname); | ||
294 | |||
285 | authctxt->postponed = 0; | 295 | authctxt->postponed = 0; |
286 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); | 296 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); |
287 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); | 297 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); |
diff --git a/auth2-hostbased.c b/auth2-hostbased.c index 63fe9ae65..92758b38c 100644 --- a/auth2-hostbased.c +++ b/auth2-hostbased.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-hostbased.c,v 1.30 2017/05/30 14:29:59 markus Exp $ */ | 1 | /* $OpenBSD: auth2-hostbased.c,v 1.31 2017/06/24 06:34:38 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -137,7 +137,7 @@ userauth_hostbased(struct ssh *ssh) | |||
137 | sshbuf_dump(b, stderr); | 137 | sshbuf_dump(b, stderr); |
138 | #endif | 138 | #endif |
139 | 139 | ||
140 | pubkey_auth_info(authctxt, key, | 140 | auth2_record_info(authctxt, |
141 | "client user \"%.100s\", client host \"%.100s\"", cuser, chost); | 141 | "client user \"%.100s\", client host \"%.100s\"", cuser, chost); |
142 | 142 | ||
143 | /* test for allowed key and correct signature */ | 143 | /* test for allowed key and correct signature */ |
@@ -147,11 +147,11 @@ userauth_hostbased(struct ssh *ssh) | |||
147 | sshbuf_ptr(b), sshbuf_len(b), ssh->compat)) == 0) | 147 | sshbuf_ptr(b), sshbuf_len(b), ssh->compat)) == 0) |
148 | authenticated = 1; | 148 | authenticated = 1; |
149 | 149 | ||
150 | auth2_record_key(authctxt, authenticated, key); | ||
150 | sshbuf_free(b); | 151 | sshbuf_free(b); |
151 | done: | 152 | done: |
152 | debug2("%s: authenticated %d", __func__, authenticated); | 153 | debug2("%s: authenticated %d", __func__, authenticated); |
153 | if (key != NULL) | 154 | sshkey_free(key); |
154 | sshkey_free(key); | ||
155 | free(pkalg); | 155 | free(pkalg); |
156 | free(pkblob); | 156 | free(pkblob); |
157 | free(cuser); | 157 | free(cuser); |
diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 5794f1f4d..1c59b5bb0 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-pubkey.c,v 1.67 2017/05/31 10:54:00 markus Exp $ */ | 1 | /* $OpenBSD: auth2-pubkey.c,v 1.68 2017/06/24 06:34:38 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -137,7 +137,7 @@ userauth_pubkey(struct ssh *ssh) | |||
137 | goto done; | 137 | goto done; |
138 | } | 138 | } |
139 | fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); | 139 | fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); |
140 | if (auth2_userkey_already_used(authctxt, key)) { | 140 | if (auth2_key_already_used(authctxt, key)) { |
141 | logit("refusing previously-used %s key", sshkey_type(key)); | 141 | logit("refusing previously-used %s key", sshkey_type(key)); |
142 | goto done; | 142 | goto done; |
143 | } | 143 | } |
@@ -194,7 +194,6 @@ userauth_pubkey(struct ssh *ssh) | |||
194 | #ifdef DEBUG_PK | 194 | #ifdef DEBUG_PK |
195 | sshbuf_dump(b, stderr); | 195 | sshbuf_dump(b, stderr); |
196 | #endif | 196 | #endif |
197 | pubkey_auth_info(authctxt, key, NULL); | ||
198 | 197 | ||
199 | /* test for correct signature */ | 198 | /* test for correct signature */ |
200 | authenticated = 0; | 199 | authenticated = 0; |
@@ -202,12 +201,10 @@ userauth_pubkey(struct ssh *ssh) | |||
202 | PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), | 201 | PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), |
203 | sshbuf_len(b), ssh->compat)) == 0) { | 202 | sshbuf_len(b), ssh->compat)) == 0) { |
204 | authenticated = 1; | 203 | authenticated = 1; |
205 | /* Record the successful key to prevent reuse */ | ||
206 | auth2_record_userkey(authctxt, key); | ||
207 | key = NULL; /* Don't free below */ | ||
208 | } | 204 | } |
209 | sshbuf_free(b); | 205 | sshbuf_free(b); |
210 | free(sig); | 206 | free(sig); |
207 | auth2_record_key(authctxt, authenticated, key); | ||
211 | } else { | 208 | } else { |
212 | debug("%s: test whether pkalg/pkblob are acceptable for %s %s", | 209 | debug("%s: test whether pkalg/pkblob are acceptable for %s %s", |
213 | __func__, sshkey_type(key), fp); | 210 | __func__, sshkey_type(key), fp); |
@@ -237,8 +234,7 @@ userauth_pubkey(struct ssh *ssh) | |||
237 | auth_clear_options(); | 234 | auth_clear_options(); |
238 | done: | 235 | done: |
239 | debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg); | 236 | debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg); |
240 | if (key != NULL) | 237 | sshkey_free(key); |
241 | sshkey_free(key); | ||
242 | free(userstyle); | 238 | free(userstyle); |
243 | free(pkalg); | 239 | free(pkalg); |
244 | free(pkblob); | 240 | free(pkblob); |
@@ -246,44 +242,6 @@ done: | |||
246 | return authenticated; | 242 | return authenticated; |
247 | } | 243 | } |
248 | 244 | ||
249 | void | ||
250 | pubkey_auth_info(Authctxt *authctxt, const struct sshkey *key, | ||
251 | const char *fmt, ...) | ||
252 | { | ||
253 | char *fp, *extra; | ||
254 | va_list ap; | ||
255 | int i; | ||
256 | |||
257 | extra = NULL; | ||
258 | if (fmt != NULL) { | ||
259 | va_start(ap, fmt); | ||
260 | i = vasprintf(&extra, fmt, ap); | ||
261 | va_end(ap); | ||
262 | if (i < 0 || extra == NULL) | ||
263 | fatal("%s: vasprintf failed", __func__); | ||
264 | } | ||
265 | |||
266 | if (sshkey_is_cert(key)) { | ||
267 | fp = sshkey_fingerprint(key->cert->signature_key, | ||
268 | options.fingerprint_hash, SSH_FP_DEFAULT); | ||
269 | auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", | ||
270 | sshkey_type(key), key->cert->key_id, | ||
271 | (unsigned long long)key->cert->serial, | ||
272 | sshkey_type(key->cert->signature_key), | ||
273 | fp == NULL ? "(null)" : fp, | ||
274 | extra == NULL ? "" : ", ", extra == NULL ? "" : extra); | ||
275 | free(fp); | ||
276 | } else { | ||
277 | fp = sshkey_fingerprint(key, options.fingerprint_hash, | ||
278 | SSH_FP_DEFAULT); | ||
279 | auth_info(authctxt, "%s %s%s%s", sshkey_type(key), | ||
280 | fp == NULL ? "(null)" : fp, | ||
281 | extra == NULL ? "" : ", ", extra == NULL ? "" : extra); | ||
282 | free(fp); | ||
283 | } | ||
284 | free(extra); | ||
285 | } | ||
286 | |||
287 | /* | 245 | /* |
288 | * Splits 's' into an argument vector. Handles quoted string and basic | 246 | * Splits 's' into an argument vector. Handles quoted string and basic |
289 | * escape characters (\\, \", \'). Caller must free the argument vector | 247 | * escape characters (\\, \", \'). Caller must free the argument vector |
@@ -1148,36 +1106,6 @@ user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt) | |||
1148 | return success; | 1106 | return success; |
1149 | } | 1107 | } |
1150 | 1108 | ||
1151 | /* Records a public key in the list of previously-successful keys */ | ||
1152 | void | ||
1153 | auth2_record_userkey(Authctxt *authctxt, struct sshkey *key) | ||
1154 | { | ||
1155 | struct sshkey **tmp; | ||
1156 | |||
1157 | if (authctxt->nprev_userkeys >= INT_MAX || | ||
1158 | (tmp = recallocarray(authctxt->prev_userkeys, | ||
1159 | authctxt->nprev_userkeys, authctxt->nprev_userkeys + 1, | ||
1160 | sizeof(*tmp))) == NULL) | ||
1161 | fatal("%s: recallocarray failed", __func__); | ||
1162 | authctxt->prev_userkeys = tmp; | ||
1163 | authctxt->prev_userkeys[authctxt->nprev_userkeys] = key; | ||
1164 | authctxt->nprev_userkeys++; | ||
1165 | } | ||
1166 | |||
1167 | /* Checks whether a key has already been used successfully for authentication */ | ||
1168 | int | ||
1169 | auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key) | ||
1170 | { | ||
1171 | u_int i; | ||
1172 | |||
1173 | for (i = 0; i < authctxt->nprev_userkeys; i++) { | ||
1174 | if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) { | ||
1175 | return 1; | ||
1176 | } | ||
1177 | } | ||
1178 | return 0; | ||
1179 | } | ||
1180 | |||
1181 | Authmethod method_pubkey = { | 1109 | Authmethod method_pubkey = { |
1182 | "publickey", | 1110 | "publickey", |
1183 | userauth_pubkey, | 1111 | userauth_pubkey, |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2.c,v 1.142 2017/05/31 07:00:13 markus Exp $ */ | 1 | /* $OpenBSD: auth2.c,v 1.143 2017/06/24 06:34:38 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -30,6 +30,7 @@ | |||
30 | #include <sys/uio.h> | 30 | #include <sys/uio.h> |
31 | 31 | ||
32 | #include <fcntl.h> | 32 | #include <fcntl.h> |
33 | #include <limits.h> | ||
33 | #include <pwd.h> | 34 | #include <pwd.h> |
34 | #include <stdarg.h> | 35 | #include <stdarg.h> |
35 | #include <string.h> | 36 | #include <string.h> |
@@ -55,6 +56,7 @@ | |||
55 | #include "ssh-gss.h" | 56 | #include "ssh-gss.h" |
56 | #endif | 57 | #endif |
57 | #include "monitor_wrap.h" | 58 | #include "monitor_wrap.h" |
59 | #include "ssherr.h" | ||
58 | 60 | ||
59 | /* import */ | 61 | /* import */ |
60 | extern ServerOptions options; | 62 | extern ServerOptions options; |
@@ -277,6 +279,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) | |||
277 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); | 279 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); |
278 | #endif | 280 | #endif |
279 | 281 | ||
282 | auth2_authctxt_reset_info(authctxt); | ||
280 | authctxt->postponed = 0; | 283 | authctxt->postponed = 0; |
281 | authctxt->server_caused_failure = 0; | 284 | authctxt->server_caused_failure = 0; |
282 | 285 | ||
@@ -327,6 +330,10 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method, | |||
327 | /* Log before sending the reply */ | 330 | /* Log before sending the reply */ |
328 | auth_log(authctxt, authenticated, partial, method, submethod); | 331 | auth_log(authctxt, authenticated, partial, method, submethod); |
329 | 332 | ||
333 | /* Update information exposed to session */ | ||
334 | if (authenticated || partial) | ||
335 | auth2_update_session_info(authctxt, method, submethod); | ||
336 | |||
330 | if (authctxt->postponed) | 337 | if (authctxt->postponed) |
331 | return; | 338 | return; |
332 | 339 | ||
@@ -624,4 +631,128 @@ auth2_update_methods_lists(Authctxt *authctxt, const char *method, | |||
624 | return 0; | 631 | return 0; |
625 | } | 632 | } |
626 | 633 | ||
634 | /* Reset method-specific information */ | ||
635 | void auth2_authctxt_reset_info(Authctxt *authctxt) | ||
636 | { | ||
637 | sshkey_free(authctxt->auth_method_key); | ||
638 | free(authctxt->auth_method_info); | ||
639 | authctxt->auth_method_key = NULL; | ||
640 | authctxt->auth_method_info = NULL; | ||
641 | } | ||
642 | |||
643 | /* Record auth method-specific information for logs */ | ||
644 | void | ||
645 | auth2_record_info(Authctxt *authctxt, const char *fmt, ...) | ||
646 | { | ||
647 | va_list ap; | ||
648 | int i; | ||
649 | |||
650 | free(authctxt->auth_method_info); | ||
651 | authctxt->auth_method_info = NULL; | ||
652 | |||
653 | va_start(ap, fmt); | ||
654 | i = vasprintf(&authctxt->auth_method_info, fmt, ap); | ||
655 | va_end(ap); | ||
656 | |||
657 | if (i < 0 || authctxt->auth_method_info == NULL) | ||
658 | fatal("%s: vasprintf failed", __func__); | ||
659 | } | ||
660 | |||
661 | /* | ||
662 | * Records a public key used in authentication. This is used for logging | ||
663 | * and to ensure that the same key is not subsequently accepted again for | ||
664 | * multiple authentication. | ||
665 | */ | ||
666 | void | ||
667 | auth2_record_key(Authctxt *authctxt, int authenticated, | ||
668 | const struct sshkey *key) | ||
669 | { | ||
670 | struct sshkey **tmp, *dup; | ||
671 | int r; | ||
672 | |||
673 | if ((r = sshkey_demote(key, &dup)) != 0) | ||
674 | fatal("%s: copy key: %s", __func__, ssh_err(r)); | ||
675 | sshkey_free(authctxt->auth_method_key); | ||
676 | authctxt->auth_method_key = dup; | ||
677 | |||
678 | if (!authenticated) | ||
679 | return; | ||
680 | |||
681 | /* If authenticated, make sure we don't accept this key again */ | ||
682 | if ((r = sshkey_demote(key, &dup)) != 0) | ||
683 | fatal("%s: copy key: %s", __func__, ssh_err(r)); | ||
684 | if (authctxt->nprev_keys >= INT_MAX || | ||
685 | (tmp = recallocarray(authctxt->prev_keys, authctxt->nprev_keys, | ||
686 | authctxt->nprev_keys + 1, sizeof(*authctxt->prev_keys))) == NULL) | ||
687 | fatal("%s: reallocarray failed", __func__); | ||
688 | authctxt->prev_keys = tmp; | ||
689 | authctxt->prev_keys[authctxt->nprev_keys] = dup; | ||
690 | authctxt->nprev_keys++; | ||
691 | |||
692 | } | ||
693 | |||
694 | /* Checks whether a key has already been previously used for authentication */ | ||
695 | int | ||
696 | auth2_key_already_used(Authctxt *authctxt, const struct sshkey *key) | ||
697 | { | ||
698 | u_int i; | ||
699 | char *fp; | ||
700 | |||
701 | for (i = 0; i < authctxt->nprev_keys; i++) { | ||
702 | if (sshkey_equal_public(key, authctxt->prev_keys[i])) { | ||
703 | fp = sshkey_fingerprint(authctxt->prev_keys[i], | ||
704 | options.fingerprint_hash, SSH_FP_DEFAULT); | ||
705 | debug3("%s: key already used: %s %s", __func__, | ||
706 | sshkey_type(authctxt->prev_keys[i]), | ||
707 | fp == NULL ? "UNKNOWN" : fp); | ||
708 | free(fp); | ||
709 | return 1; | ||
710 | } | ||
711 | } | ||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | /* | ||
716 | * Updates authctxt->session_info with details of authentication. Should be | ||
717 | * whenever an authentication method succeeds. | ||
718 | */ | ||
719 | void | ||
720 | auth2_update_session_info(Authctxt *authctxt, const char *method, | ||
721 | const char *submethod) | ||
722 | { | ||
723 | int r; | ||
724 | |||
725 | if (authctxt->session_info == NULL) { | ||
726 | if ((authctxt->session_info = sshbuf_new()) == NULL) | ||
727 | fatal("%s: sshbuf_new", __func__); | ||
728 | } | ||
729 | |||
730 | /* Append method[/submethod] */ | ||
731 | if ((r = sshbuf_putf(authctxt->session_info, "%s%s%s", | ||
732 | method, submethod == NULL ? "" : "/", | ||
733 | submethod == NULL ? "" : submethod)) != 0) | ||
734 | fatal("%s: append method: %s", __func__, ssh_err(r)); | ||
735 | |||
736 | /* Append key if present */ | ||
737 | if (authctxt->auth_method_key != NULL) { | ||
738 | if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 || | ||
739 | (r = sshkey_format_text(authctxt->auth_method_key, | ||
740 | authctxt->session_info)) != 0) | ||
741 | fatal("%s: append key: %s", __func__, ssh_err(r)); | ||
742 | } | ||
743 | |||
744 | if (authctxt->auth_method_info != NULL) { | ||
745 | /* Ensure no ambiguity here */ | ||
746 | if (strchr(authctxt->auth_method_info, '\n') != NULL) | ||
747 | fatal("%s: auth_method_info contains \\n", __func__); | ||
748 | if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 || | ||
749 | (r = sshbuf_putf(authctxt->session_info, "%s", | ||
750 | authctxt->auth_method_info)) != 0) { | ||
751 | fatal("%s: append method info: %s", | ||
752 | __func__, ssh_err(r)); | ||
753 | } | ||
754 | } | ||
755 | if ((r = sshbuf_put_u8(authctxt->session_info, '\n')) != 0) | ||
756 | fatal("%s: append: %s", __func__, ssh_err(r)); | ||
757 | } | ||
627 | 758 | ||
diff --git a/gss-serv.c b/gss-serv.c index 53993d674..6cae720e5 100644 --- a/gss-serv.c +++ b/gss-serv.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: gss-serv.c,v 1.29 2015/05/22 03:50:02 djm Exp $ */ | 1 | /* $OpenBSD: gss-serv.c,v 1.30 2017/06/24 06:34:38 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | 4 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. |
@@ -393,4 +393,13 @@ ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) | |||
393 | return (ctx->major); | 393 | return (ctx->major); |
394 | } | 394 | } |
395 | 395 | ||
396 | /* Privileged */ | ||
397 | const char *ssh_gssapi_displayname(void) | ||
398 | { | ||
399 | if (gssapi_client.displayname.length == 0 || | ||
400 | gssapi_client.displayname.value == NULL) | ||
401 | return NULL; | ||
402 | return (char *)gssapi_client.displayname.value; | ||
403 | } | ||
404 | |||
396 | #endif | 405 | #endif |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: monitor.c,v 1.171 2017/05/31 10:04:29 markus Exp $ */ | 1 | /* $OpenBSD: monitor.c,v 1.172 2017/06/24 06:34:38 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | 3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> |
4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> | 4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> |
@@ -308,6 +308,8 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) | |||
308 | partial = 0; | 308 | partial = 0; |
309 | auth_method = "unknown"; | 309 | auth_method = "unknown"; |
310 | auth_submethod = NULL; | 310 | auth_submethod = NULL; |
311 | auth2_authctxt_reset_info(authctxt); | ||
312 | |||
311 | authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1); | 313 | authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1); |
312 | 314 | ||
313 | /* Special handling for multiple required authentications */ | 315 | /* Special handling for multiple required authentications */ |
@@ -347,6 +349,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) | |||
347 | auth_method, auth_submethod); | 349 | auth_method, auth_submethod); |
348 | if (!partial && !authenticated) | 350 | if (!partial && !authenticated) |
349 | authctxt->failures++; | 351 | authctxt->failures++; |
352 | if (authenticated || partial) { | ||
353 | auth2_update_session_info(authctxt, | ||
354 | auth_method, auth_submethod); | ||
355 | } | ||
350 | } | 356 | } |
351 | } | 357 | } |
352 | 358 | ||
@@ -1147,12 +1153,11 @@ mm_answer_keyallowed(int sock, Buffer *m) | |||
1147 | switch (type) { | 1153 | switch (type) { |
1148 | case MM_USERKEY: | 1154 | case MM_USERKEY: |
1149 | allowed = options.pubkey_authentication && | 1155 | allowed = options.pubkey_authentication && |
1150 | !auth2_userkey_already_used(authctxt, key) && | 1156 | !auth2_key_already_used(authctxt, key) && |
1151 | match_pattern_list(sshkey_ssh_name(key), | 1157 | match_pattern_list(sshkey_ssh_name(key), |
1152 | options.pubkey_key_types, 0) == 1 && | 1158 | options.pubkey_key_types, 0) == 1 && |
1153 | user_key_allowed(authctxt->pw, key, | 1159 | user_key_allowed(authctxt->pw, key, |
1154 | pubkey_auth_attempt); | 1160 | pubkey_auth_attempt); |
1155 | pubkey_auth_info(authctxt, key, NULL); | ||
1156 | auth_method = "publickey"; | 1161 | auth_method = "publickey"; |
1157 | if (options.pubkey_authentication && | 1162 | if (options.pubkey_authentication && |
1158 | (!pubkey_auth_attempt || allowed != 1)) | 1163 | (!pubkey_auth_attempt || allowed != 1)) |
@@ -1160,11 +1165,12 @@ mm_answer_keyallowed(int sock, Buffer *m) | |||
1160 | break; | 1165 | break; |
1161 | case MM_HOSTKEY: | 1166 | case MM_HOSTKEY: |
1162 | allowed = options.hostbased_authentication && | 1167 | allowed = options.hostbased_authentication && |
1168 | !auth2_key_already_used(authctxt, key) && | ||
1163 | match_pattern_list(sshkey_ssh_name(key), | 1169 | match_pattern_list(sshkey_ssh_name(key), |
1164 | options.hostbased_key_types, 0) == 1 && | 1170 | options.hostbased_key_types, 0) == 1 && |
1165 | hostbased_key_allowed(authctxt->pw, | 1171 | hostbased_key_allowed(authctxt->pw, |
1166 | cuser, chost, key); | 1172 | cuser, chost, key); |
1167 | pubkey_auth_info(authctxt, key, | 1173 | auth2_record_info(authctxt, |
1168 | "client user \"%.100s\", client host \"%.100s\"", | 1174 | "client user \"%.100s\", client host \"%.100s\"", |
1169 | cuser, chost); | 1175 | cuser, chost); |
1170 | auth_method = "hostbased"; | 1176 | auth_method = "hostbased"; |
@@ -1175,11 +1181,10 @@ mm_answer_keyallowed(int sock, Buffer *m) | |||
1175 | } | 1181 | } |
1176 | } | 1182 | } |
1177 | 1183 | ||
1178 | debug3("%s: key %p is %s", | 1184 | debug3("%s: key is %s", __func__, allowed ? "allowed" : "not allowed"); |
1179 | __func__, key, allowed ? "allowed" : "not allowed"); | ||
1180 | 1185 | ||
1181 | if (key != NULL) | 1186 | auth2_record_key(authctxt, 0, key); |
1182 | key_free(key); | 1187 | sshkey_free(key); |
1183 | 1188 | ||
1184 | /* clear temporarily storage (used by verify) */ | 1189 | /* clear temporarily storage (used by verify) */ |
1185 | monitor_reset_key_state(); | 1190 | monitor_reset_key_state(); |
@@ -1353,10 +1358,12 @@ mm_answer_keyverify(int sock, struct sshbuf *m) | |||
1353 | switch (key_blobtype) { | 1358 | switch (key_blobtype) { |
1354 | case MM_USERKEY: | 1359 | case MM_USERKEY: |
1355 | valid_data = monitor_valid_userblob(data, datalen); | 1360 | valid_data = monitor_valid_userblob(data, datalen); |
1361 | auth_method = "publickey"; | ||
1356 | break; | 1362 | break; |
1357 | case MM_HOSTKEY: | 1363 | case MM_HOSTKEY: |
1358 | valid_data = monitor_valid_hostbasedblob(data, datalen, | 1364 | valid_data = monitor_valid_hostbasedblob(data, datalen, |
1359 | hostbased_cuser, hostbased_chost); | 1365 | hostbased_cuser, hostbased_chost); |
1366 | auth_method = "hostbased"; | ||
1360 | break; | 1367 | break; |
1361 | default: | 1368 | default: |
1362 | valid_data = 0; | 1369 | valid_data = 0; |
@@ -1367,23 +1374,17 @@ mm_answer_keyverify(int sock, struct sshbuf *m) | |||
1367 | 1374 | ||
1368 | ret = sshkey_verify(key, signature, signaturelen, data, datalen, | 1375 | ret = sshkey_verify(key, signature, signaturelen, data, datalen, |
1369 | active_state->compat); | 1376 | active_state->compat); |
1370 | debug3("%s: key %p signature %s", | 1377 | debug3("%s: %s %p signature %s", __func__, auth_method, key, |
1371 | __func__, key, (ret == 0) ? "verified" : "unverified"); | 1378 | (ret == 0) ? "verified" : "unverified"); |
1372 | 1379 | auth2_record_key(authctxt, ret == 0, key); | |
1373 | /* If auth was successful then record key to ensure it isn't reused */ | ||
1374 | if (ret == 0 && key_blobtype == MM_USERKEY) | ||
1375 | auth2_record_userkey(authctxt, key); | ||
1376 | else | ||
1377 | sshkey_free(key); | ||
1378 | 1380 | ||
1379 | free(blob); | 1381 | free(blob); |
1380 | free(signature); | 1382 | free(signature); |
1381 | free(data); | 1383 | free(data); |
1382 | 1384 | ||
1383 | auth_method = key_blobtype == MM_USERKEY ? "publickey" : "hostbased"; | ||
1384 | |||
1385 | monitor_reset_key_state(); | 1385 | monitor_reset_key_state(); |
1386 | 1386 | ||
1387 | sshkey_free(key); | ||
1387 | sshbuf_reset(m); | 1388 | sshbuf_reset(m); |
1388 | 1389 | ||
1389 | /* encode ret != 0 as positive integer, since we're sending u32 */ | 1390 | /* encode ret != 0 as positive integer, since we're sending u32 */ |
@@ -1799,6 +1800,7 @@ int | |||
1799 | mm_answer_gss_userok(int sock, Buffer *m) | 1800 | mm_answer_gss_userok(int sock, Buffer *m) |
1800 | { | 1801 | { |
1801 | int authenticated; | 1802 | int authenticated; |
1803 | const char *displayname; | ||
1802 | 1804 | ||
1803 | if (!options.gss_authentication) | 1805 | if (!options.gss_authentication) |
1804 | fatal("%s: GSSAPI authentication not enabled", __func__); | 1806 | fatal("%s: GSSAPI authentication not enabled", __func__); |
@@ -1813,6 +1815,9 @@ mm_answer_gss_userok(int sock, Buffer *m) | |||
1813 | 1815 | ||
1814 | auth_method = "gssapi-with-mic"; | 1816 | auth_method = "gssapi-with-mic"; |
1815 | 1817 | ||
1818 | if ((displayname = ssh_gssapi_displayname()) != NULL) | ||
1819 | auth2_record_info(authctxt, "%s", displayname); | ||
1820 | |||
1816 | /* Monitor loop will terminate if authenticated */ | 1821 | /* Monitor loop will terminate if authenticated */ |
1817 | return (authenticated); | 1822 | return (authenticated); |
1818 | } | 1823 | } |
diff --git a/servconf.c b/servconf.c index a112798e4..ed1fc71cf 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -1,5 +1,5 @@ | |||
1 | 1 | ||
2 | /* $OpenBSD: servconf.c,v 1.308 2017/05/17 01:24:17 djm Exp $ */ | 2 | /* $OpenBSD: servconf.c,v 1.309 2017/06/24 06:34:38 djm Exp $ */ |
3 | /* | 3 | /* |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
5 | * All rights reserved | 5 | * All rights reserved |
@@ -164,6 +164,7 @@ initialize_server_options(ServerOptions *options) | |||
164 | options->version_addendum = NULL; | 164 | options->version_addendum = NULL; |
165 | options->fingerprint_hash = -1; | 165 | options->fingerprint_hash = -1; |
166 | options->disable_forwarding = -1; | 166 | options->disable_forwarding = -1; |
167 | options->expose_userauth_info = -1; | ||
167 | } | 168 | } |
168 | 169 | ||
169 | /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ | 170 | /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ |
@@ -333,6 +334,8 @@ fill_default_server_options(ServerOptions *options) | |||
333 | options->fingerprint_hash = SSH_FP_HASH_DEFAULT; | 334 | options->fingerprint_hash = SSH_FP_HASH_DEFAULT; |
334 | if (options->disable_forwarding == -1) | 335 | if (options->disable_forwarding == -1) |
335 | options->disable_forwarding = 0; | 336 | options->disable_forwarding = 0; |
337 | if (options->expose_userauth_info == -1) | ||
338 | options->expose_userauth_info = 0; | ||
336 | 339 | ||
337 | assemble_algorithms(options); | 340 | assemble_algorithms(options); |
338 | 341 | ||
@@ -418,6 +421,7 @@ typedef enum { | |||
418 | sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, | 421 | sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, |
419 | sStreamLocalBindMask, sStreamLocalBindUnlink, | 422 | sStreamLocalBindMask, sStreamLocalBindUnlink, |
420 | sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, | 423 | sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, |
424 | sExposeAuthInfo, | ||
421 | sDeprecated, sIgnore, sUnsupported | 425 | sDeprecated, sIgnore, sUnsupported |
422 | } ServerOpCodes; | 426 | } ServerOpCodes; |
423 | 427 | ||
@@ -561,6 +565,7 @@ static struct { | |||
561 | { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL }, | 565 | { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL }, |
562 | { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, | 566 | { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, |
563 | { "disableforwarding", sDisableForwarding, SSHCFG_ALL }, | 567 | { "disableforwarding", sDisableForwarding, SSHCFG_ALL }, |
568 | { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL }, | ||
564 | { NULL, sBadOption, 0 } | 569 | { NULL, sBadOption, 0 } |
565 | }; | 570 | }; |
566 | 571 | ||
@@ -1835,6 +1840,10 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1835 | options->fingerprint_hash = value; | 1840 | options->fingerprint_hash = value; |
1836 | break; | 1841 | break; |
1837 | 1842 | ||
1843 | case sExposeAuthInfo: | ||
1844 | intptr = &options->expose_userauth_info; | ||
1845 | goto parse_flag; | ||
1846 | |||
1838 | case sDeprecated: | 1847 | case sDeprecated: |
1839 | case sIgnore: | 1848 | case sIgnore: |
1840 | case sUnsupported: | 1849 | case sUnsupported: |
@@ -1973,6 +1982,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) | |||
1973 | M_CP_INTOPT(allow_streamlocal_forwarding); | 1982 | M_CP_INTOPT(allow_streamlocal_forwarding); |
1974 | M_CP_INTOPT(allow_agent_forwarding); | 1983 | M_CP_INTOPT(allow_agent_forwarding); |
1975 | M_CP_INTOPT(disable_forwarding); | 1984 | M_CP_INTOPT(disable_forwarding); |
1985 | M_CP_INTOPT(expose_userauth_info); | ||
1976 | M_CP_INTOPT(permit_tun); | 1986 | M_CP_INTOPT(permit_tun); |
1977 | M_CP_INTOPT(fwd_opts.gateway_ports); | 1987 | M_CP_INTOPT(fwd_opts.gateway_ports); |
1978 | M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink); | 1988 | M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink); |
@@ -2272,6 +2282,7 @@ dump_config(ServerOptions *o) | |||
2272 | dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding); | 2282 | dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding); |
2273 | dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); | 2283 | dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); |
2274 | dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); | 2284 | dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); |
2285 | dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info); | ||
2275 | 2286 | ||
2276 | /* string arguments */ | 2287 | /* string arguments */ |
2277 | dump_cfg_string(sPidFile, o->pid_file); | 2288 | dump_cfg_string(sPidFile, o->pid_file); |
diff --git a/servconf.h b/servconf.h index 5853a9747..c2848a765 100644 --- a/servconf.h +++ b/servconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: servconf.h,v 1.123 2016/11/30 03:00:05 djm Exp $ */ | 1 | /* $OpenBSD: servconf.h,v 1.124 2017/06/24 06:34:38 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -189,6 +189,7 @@ typedef struct { | |||
189 | char *auth_methods[MAX_AUTH_METHODS]; | 189 | char *auth_methods[MAX_AUTH_METHODS]; |
190 | 190 | ||
191 | int fingerprint_hash; | 191 | int fingerprint_hash; |
192 | int expose_userauth_info; | ||
192 | } ServerOptions; | 193 | } ServerOptions; |
193 | 194 | ||
194 | /* Information about the incoming connection as used by Match */ | 195 | /* Information about the incoming connection as used by Match */ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: session.c,v 1.289 2017/06/24 05:24:11 djm Exp $ */ | 1 | /* $OpenBSD: session.c,v 1.290 2017/06/24 06:34:38 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
4 | * All rights reserved | 4 | * All rights reserved |
@@ -94,6 +94,7 @@ | |||
94 | #include "kex.h" | 94 | #include "kex.h" |
95 | #include "monitor_wrap.h" | 95 | #include "monitor_wrap.h" |
96 | #include "sftp.h" | 96 | #include "sftp.h" |
97 | #include "atomicio.h" | ||
97 | 98 | ||
98 | #if defined(KRB5) && defined(USE_AFS) | 99 | #if defined(KRB5) && defined(USE_AFS) |
99 | #include <kafs.h> | 100 | #include <kafs.h> |
@@ -160,6 +161,9 @@ login_cap_t *lc; | |||
160 | static int is_child = 0; | 161 | static int is_child = 0; |
161 | static int in_chroot = 0; | 162 | static int in_chroot = 0; |
162 | 163 | ||
164 | /* File containing userauth info, if ExposeAuthInfo set */ | ||
165 | static char *auth_info_file = NULL; | ||
166 | |||
163 | /* Name and directory of socket for authentication agent forwarding. */ | 167 | /* Name and directory of socket for authentication agent forwarding. */ |
164 | static char *auth_sock_name = NULL; | 168 | static char *auth_sock_name = NULL; |
165 | static char *auth_sock_dir = NULL; | 169 | static char *auth_sock_dir = NULL; |
@@ -249,6 +253,40 @@ display_loginmsg(void) | |||
249 | } | 253 | } |
250 | } | 254 | } |
251 | 255 | ||
256 | static void | ||
257 | prepare_auth_info_file(struct passwd *pw, struct sshbuf *info) | ||
258 | { | ||
259 | int fd = -1, success = 0; | ||
260 | |||
261 | if (!options.expose_userauth_info || info == NULL) | ||
262 | return; | ||
263 | |||
264 | temporarily_use_uid(pw); | ||
265 | auth_info_file = xstrdup("/tmp/sshauth.XXXXXXXXXXXXXXX"); | ||
266 | if ((fd = mkstemp(auth_info_file)) == -1) { | ||
267 | error("%s: mkstemp: %s", __func__, strerror(errno)); | ||
268 | goto out; | ||
269 | } | ||
270 | if (atomicio(vwrite, fd, sshbuf_mutable_ptr(info), | ||
271 | sshbuf_len(info)) != sshbuf_len(info)) { | ||
272 | error("%s: write: %s", __func__, strerror(errno)); | ||
273 | goto out; | ||
274 | } | ||
275 | if (close(fd) != 0) { | ||
276 | error("%s: close: %s", __func__, strerror(errno)); | ||
277 | goto out; | ||
278 | } | ||
279 | success = 1; | ||
280 | out: | ||
281 | if (!success) { | ||
282 | if (fd != -1) | ||
283 | close(fd); | ||
284 | free(auth_info_file); | ||
285 | auth_info_file = NULL; | ||
286 | } | ||
287 | restore_uid(); | ||
288 | } | ||
289 | |||
252 | void | 290 | void |
253 | do_authenticated(Authctxt *authctxt) | 291 | do_authenticated(Authctxt *authctxt) |
254 | { | 292 | { |
@@ -264,7 +302,10 @@ do_authenticated(Authctxt *authctxt) | |||
264 | 302 | ||
265 | auth_debug_send(); | 303 | auth_debug_send(); |
266 | 304 | ||
305 | prepare_auth_info_file(authctxt->pw, authctxt->session_info); | ||
306 | |||
267 | do_authenticated2(authctxt); | 307 | do_authenticated2(authctxt); |
308 | |||
268 | do_cleanup(authctxt); | 309 | do_cleanup(authctxt); |
269 | } | 310 | } |
270 | 311 | ||
@@ -1077,6 +1118,8 @@ do_setup_env(Session *s, const char *shell) | |||
1077 | free(laddr); | 1118 | free(laddr); |
1078 | child_set_env(&env, &envsize, "SSH_CONNECTION", buf); | 1119 | child_set_env(&env, &envsize, "SSH_CONNECTION", buf); |
1079 | 1120 | ||
1121 | if (auth_info_file != NULL) | ||
1122 | child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file); | ||
1080 | if (s->ttyfd != -1) | 1123 | if (s->ttyfd != -1) |
1081 | child_set_env(&env, &envsize, "SSH_TTY", s->tty); | 1124 | child_set_env(&env, &envsize, "SSH_TTY", s->tty); |
1082 | if (s->term) | 1125 | if (s->term) |
@@ -2549,6 +2592,15 @@ do_cleanup(Authctxt *authctxt) | |||
2549 | /* remove agent socket */ | 2592 | /* remove agent socket */ |
2550 | auth_sock_cleanup_proc(authctxt->pw); | 2593 | auth_sock_cleanup_proc(authctxt->pw); |
2551 | 2594 | ||
2595 | /* remove userauth info */ | ||
2596 | if (auth_info_file != NULL) { | ||
2597 | temporarily_use_uid(authctxt->pw); | ||
2598 | unlink(auth_info_file); | ||
2599 | restore_uid(); | ||
2600 | free(auth_info_file); | ||
2601 | auth_info_file = NULL; | ||
2602 | } | ||
2603 | |||
2552 | /* | 2604 | /* |
2553 | * Cleanup ptys/utmp only if privsep is disabled, | 2605 | * Cleanup ptys/utmp only if privsep is disabled, |
2554 | * or if running in monitor. | 2606 | * or if running in monitor. |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 djm Exp $ */ | 1 | /* $OpenBSD: ssh-gss.h,v 1.12 2017/06/24 06:34:38 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | 3 | * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. |
4 | * | 4 | * |
@@ -128,6 +128,7 @@ OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); | |||
128 | void ssh_gssapi_do_child(char ***, u_int *); | 128 | void ssh_gssapi_do_child(char ***, u_int *); |
129 | void ssh_gssapi_cleanup_creds(void); | 129 | void ssh_gssapi_cleanup_creds(void); |
130 | void ssh_gssapi_storecreds(void); | 130 | void ssh_gssapi_storecreds(void); |
131 | const char *ssh_gssapi_displayname(void); | ||
131 | 132 | ||
132 | #endif /* GSSAPI */ | 133 | #endif /* GSSAPI */ |
133 | 134 | ||
diff --git a/sshd_config.5 b/sshd_config.5 index 7b4cb1d9a..cfe1db82a 100644 --- a/sshd_config.5 +++ b/sshd_config.5 | |||
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: sshd_config.5,v 1.245 2017/05/17 01:24:17 djm Exp $ | 36 | .\" $OpenBSD: sshd_config.5,v 1.246 2017/06/24 06:34:38 djm Exp $ |
37 | .Dd $Mdocdate: May 17 2017 $ | 37 | .Dd $Mdocdate: June 24 2017 $ |
38 | .Dt SSHD_CONFIG 5 | 38 | .Dt SSHD_CONFIG 5 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -564,6 +564,12 @@ Disables all forwarding features, including X11, | |||
564 | TCP and StreamLocal. | 564 | TCP and StreamLocal. |
565 | This option overrides all other forwarding-related options and may | 565 | This option overrides all other forwarding-related options and may |
566 | simplify restricted configurations. | 566 | simplify restricted configurations. |
567 | .It Cm ExposeAuthInfo | ||
568 | Enables writing a file containing a list of authentication methods and | ||
569 | public credentials (e.g. keys) used to authenticate the user. | ||
570 | The location of the file is exposed to the user session though the | ||
571 | .Ev SSH_AUTH_INFO | ||
572 | enviornment variable. | ||
567 | .It Cm FingerprintHash | 573 | .It Cm FingerprintHash |
568 | Specifies the hash algorithm used when logging key fingerprints. | 574 | Specifies the hash algorithm used when logging key fingerprints. |
569 | Valid options are: | 575 | Valid options are: |