Lines 51-56
Link Here
|
51 |
#include <unistd.h> |
51 |
#include <unistd.h> |
52 |
#include <string.h> |
52 |
#include <string.h> |
53 |
#include <krb5.h> |
53 |
#include <krb5.h> |
|
|
54 |
#include <profile.h> |
54 |
|
55 |
|
55 |
extern ServerOptions options; |
56 |
extern ServerOptions options; |
56 |
|
57 |
|
Lines 77-83
auth_krb5_password(Authctxt *authctxt, const char *password)
Link Here
|
77 |
#endif |
78 |
#endif |
78 |
krb5_error_code problem; |
79 |
krb5_error_code problem; |
79 |
krb5_ccache ccache = NULL; |
80 |
krb5_ccache ccache = NULL; |
80 |
int len; |
81 |
char *ticket_name = NULL; |
81 |
char *client, *platform_client; |
82 |
char *client, *platform_client; |
82 |
const char *errmsg; |
83 |
const char *errmsg; |
83 |
|
84 |
|
Lines 163-170
auth_krb5_password(Authctxt *authctxt, const char *password)
Link Here
|
163 |
goto out; |
164 |
goto out; |
164 |
} |
165 |
} |
165 |
|
166 |
|
166 |
problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, |
167 |
problem = ssh_krb5_cc_new_unique(authctxt->krb5_ctx, |
167 |
&authctxt->krb5_fwd_ccache); |
168 |
&authctxt->krb5_fwd_ccache, &authctxt->krb5_set_env); |
168 |
if (problem) |
169 |
if (problem) |
169 |
goto out; |
170 |
goto out; |
170 |
|
171 |
|
Lines 179-193
auth_krb5_password(Authctxt *authctxt, const char *password)
Link Here
|
179 |
goto out; |
180 |
goto out; |
180 |
#endif |
181 |
#endif |
181 |
|
182 |
|
182 |
authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); |
183 |
problem = krb5_cc_get_full_name(authctxt->krb5_ctx, |
|
|
184 |
authctxt->krb5_fwd_ccache, &ticket_name); |
183 |
|
185 |
|
184 |
len = strlen(authctxt->krb5_ticket_file) + 6; |
186 |
authctxt->krb5_ccname = xstrdup(ticket_name); |
185 |
authctxt->krb5_ccname = xmalloc(len); |
187 |
krb5_free_string(authctxt->krb5_ctx, ticket_name); |
186 |
snprintf(authctxt->krb5_ccname, len, "FILE:%s", |
|
|
187 |
authctxt->krb5_ticket_file); |
188 |
|
188 |
|
189 |
#ifdef USE_PAM |
189 |
#ifdef USE_PAM |
190 |
if (options.use_pam) |
190 |
if (options.use_pam && authctxt->krb5_set_env) |
191 |
do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname); |
191 |
do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname); |
192 |
#endif |
192 |
#endif |
193 |
|
193 |
|
Lines 223-233
auth_krb5_password(Authctxt *authctxt, const char *password)
Link Here
|
223 |
void |
223 |
void |
224 |
krb5_cleanup_proc(Authctxt *authctxt) |
224 |
krb5_cleanup_proc(Authctxt *authctxt) |
225 |
{ |
225 |
{ |
|
|
226 |
struct stat krb5_ccname_stat; |
227 |
char krb5_ccname[128], *krb5_ccname_dir_start, *krb5_ccname_dir_end; |
228 |
|
226 |
debug("krb5_cleanup_proc called"); |
229 |
debug("krb5_cleanup_proc called"); |
227 |
if (authctxt->krb5_fwd_ccache) { |
230 |
if (authctxt->krb5_fwd_ccache) { |
228 |
krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); |
231 |
krb5_context ctx = authctxt->krb5_ctx; |
|
|
232 |
krb5_cccol_cursor cursor; |
233 |
krb5_ccache ccache; |
234 |
int ret; |
235 |
|
236 |
krb5_cc_destroy(ctx, authctxt->krb5_fwd_ccache); |
229 |
authctxt->krb5_fwd_ccache = NULL; |
237 |
authctxt->krb5_fwd_ccache = NULL; |
|
|
238 |
|
239 |
ret = krb5_cccol_cursor_new(ctx, &cursor); |
240 |
if (ret) |
241 |
goto out; |
242 |
|
243 |
ret = krb5_cccol_cursor_next(ctx, cursor, &ccache); |
244 |
if (ret == 0 && ccache != NULL) { |
245 |
/* There is at least one other ccache in collection |
246 |
* we can switch to */ |
247 |
krb5_cc_switch(ctx, ccache); |
248 |
} else if (authctxt->krb5_ccname != NULL) { |
249 |
/* Clean up the collection too */ |
250 |
strncpy(krb5_ccname, authctxt->krb5_ccname, sizeof(krb5_ccname) - 10); |
251 |
krb5_ccname_dir_start = strchr(krb5_ccname, ':') + 1; |
252 |
*krb5_ccname_dir_start++ = '\0'; |
253 |
if (strcmp(krb5_ccname, "DIR") == 0) { |
254 |
|
255 |
strcat(krb5_ccname_dir_start, "/primary"); |
256 |
|
257 |
if (stat(krb5_ccname_dir_start, &krb5_ccname_stat) == 0) { |
258 |
if (unlink(krb5_ccname_dir_start) == 0) { |
259 |
krb5_ccname_dir_end = strrchr(krb5_ccname_dir_start, '/'); |
260 |
*krb5_ccname_dir_end = '\0'; |
261 |
if (rmdir(krb5_ccname_dir_start) == -1) |
262 |
debug("cache dir '%s' remove failed: %s", |
263 |
krb5_ccname_dir_start, strerror(errno)); |
264 |
} |
265 |
else |
266 |
debug("cache primary file '%s', remove failed: %s", |
267 |
krb5_ccname_dir_start, strerror(errno)); |
268 |
} |
269 |
} |
270 |
} |
271 |
krb5_cccol_cursor_free(ctx, &cursor); |
230 |
} |
272 |
} |
|
|
273 |
out: |
231 |
if (authctxt->krb5_user) { |
274 |
if (authctxt->krb5_user) { |
232 |
krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); |
275 |
krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); |
233 |
authctxt->krb5_user = NULL; |
276 |
authctxt->krb5_user = NULL; |
Lines 238-273
krb5_cleanup_proc(Authctxt *authctxt)
Link Here
|
238 |
} |
281 |
} |
239 |
} |
282 |
} |
240 |
|
283 |
|
241 |
#ifndef HEIMDAL |
|
|
242 |
krb5_error_code |
243 |
ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { |
244 |
int tmpfd, ret, oerrno; |
245 |
char ccname[40]; |
246 |
mode_t old_umask; |
247 |
|
284 |
|
248 |
ret = snprintf(ccname, sizeof(ccname), |
285 |
#if !defined(HEIMDAL) |
249 |
"FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); |
286 |
int |
250 |
if (ret < 0 || (size_t)ret >= sizeof(ccname)) |
287 |
ssh_asprintf_append(char **dsc, const char *fmt, ...) { |
251 |
return ENOMEM; |
288 |
char *src, *old; |
252 |
|
289 |
va_list ap; |
253 |
old_umask = umask(0177); |
290 |
int i; |
254 |
tmpfd = mkstemp(ccname + strlen("FILE:")); |
291 |
|
255 |
oerrno = errno; |
292 |
va_start(ap, fmt); |
256 |
umask(old_umask); |
293 |
i = vasprintf(&src, fmt, ap); |
257 |
if (tmpfd == -1) { |
294 |
va_end(ap); |
258 |
logit("mkstemp(): %.100s", strerror(oerrno)); |
295 |
|
259 |
return oerrno; |
296 |
if (i == -1 || src == NULL) |
|
|
297 |
return -1; |
298 |
|
299 |
old = *dsc; |
300 |
|
301 |
i = asprintf(dsc, "%s%s", *dsc, src); |
302 |
if (i == -1 || src == NULL) { |
303 |
free(src); |
304 |
return -1; |
305 |
} |
306 |
|
307 |
free(old); |
308 |
free(src); |
309 |
|
310 |
return i; |
311 |
} |
312 |
|
313 |
int |
314 |
ssh_krb5_expand_template(char **result, const char *template) { |
315 |
char *p_n, *p_o, *r, *tmp_template; |
316 |
|
317 |
debug3_f("called, template = %s", template); |
318 |
if (template == NULL) |
319 |
return -1; |
320 |
|
321 |
tmp_template = p_n = p_o = xstrdup(template); |
322 |
r = xstrdup(""); |
323 |
|
324 |
while ((p_n = strstr(p_o, "%{")) != NULL) { |
325 |
|
326 |
*p_n++ = '\0'; |
327 |
if (ssh_asprintf_append(&r, "%s", p_o) == -1) |
328 |
goto cleanup; |
329 |
|
330 |
if (strncmp(p_n, "{uid}", 5) == 0 || strncmp(p_n, "{euid}", 6) == 0 || |
331 |
strncmp(p_n, "{USERID}", 8) == 0) { |
332 |
p_o = strchr(p_n, '}') + 1; |
333 |
if (ssh_asprintf_append(&r, "%d", geteuid()) == -1) |
334 |
goto cleanup; |
335 |
continue; |
336 |
} |
337 |
else if (strncmp(p_n, "{TEMP}", 6) == 0) { |
338 |
p_o = strchr(p_n, '}') + 1; |
339 |
if (ssh_asprintf_append(&r, "/tmp") == -1) |
340 |
goto cleanup; |
341 |
continue; |
342 |
} else { |
343 |
p_o = strchr(p_n, '}') + 1; |
344 |
*p_o = '\0'; |
345 |
debug_f("unsupported token %s in %s", p_n, template); |
346 |
/* unknown token, fallback to the default */ |
347 |
goto cleanup; |
348 |
} |
260 |
} |
349 |
} |
261 |
|
350 |
|
262 |
if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { |
351 |
if (ssh_asprintf_append(&r, "%s", p_o) == -1) |
|
|
352 |
goto cleanup; |
353 |
|
354 |
*result = r; |
355 |
free(tmp_template); |
356 |
return 0; |
357 |
|
358 |
cleanup: |
359 |
free(r); |
360 |
free(tmp_template); |
361 |
return -1; |
362 |
} |
363 |
|
364 |
krb5_error_code |
365 |
ssh_krb5_get_cctemplate(krb5_context ctx, char **ccname) { |
366 |
profile_t p; |
367 |
int ret = 0; |
368 |
char *value = NULL; |
369 |
|
370 |
debug3_f("called"); |
371 |
ret = krb5_get_profile(ctx, &p); |
372 |
if (ret) |
373 |
return ret; |
374 |
|
375 |
ret = profile_get_string(p, "libdefaults", "default_ccache_name", NULL, NULL, &value); |
376 |
if (ret || !value) |
377 |
return ret; |
378 |
|
379 |
ret = ssh_krb5_expand_template(ccname, value); |
380 |
|
381 |
debug3_f("returning with ccname = %s", *ccname); |
382 |
return ret; |
383 |
} |
384 |
|
385 |
krb5_error_code |
386 |
ssh_krb5_cc_new_unique(krb5_context ctx, krb5_ccache *ccache, int *need_environment) { |
387 |
int tmpfd, ret, oerrno, type_len; |
388 |
char *ccname = NULL; |
389 |
mode_t old_umask; |
390 |
char *type = NULL, *colon = NULL; |
391 |
|
392 |
debug3_f("called"); |
393 |
if (need_environment) |
394 |
*need_environment = 0; |
395 |
ret = ssh_krb5_get_cctemplate(ctx, &ccname); |
396 |
if (ret || !ccname || options.kerberos_unique_ccache) { |
397 |
/* Otherwise, go with the old method */ |
398 |
if (ccname) |
399 |
free(ccname); |
400 |
ccname = NULL; |
401 |
|
402 |
ret = asprintf(&ccname, |
403 |
"FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); |
404 |
if (ret < 0) |
405 |
return ENOMEM; |
406 |
|
407 |
old_umask = umask(0177); |
408 |
tmpfd = mkstemp(ccname + strlen("FILE:")); |
263 |
oerrno = errno; |
409 |
oerrno = errno; |
264 |
logit("fchmod(): %.100s", strerror(oerrno)); |
410 |
umask(old_umask); |
|
|
411 |
if (tmpfd == -1) { |
412 |
logit("mkstemp(): %.100s", strerror(oerrno)); |
413 |
return oerrno; |
414 |
} |
415 |
|
416 |
if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { |
417 |
oerrno = errno; |
418 |
logit("fchmod(): %.100s", strerror(oerrno)); |
419 |
close(tmpfd); |
420 |
return oerrno; |
421 |
} |
422 |
/* make sure the KRB5CCNAME is set for non-standard location */ |
423 |
if (need_environment) |
424 |
*need_environment = 1; |
265 |
close(tmpfd); |
425 |
close(tmpfd); |
266 |
return oerrno; |
|
|
267 |
} |
426 |
} |
268 |
close(tmpfd); |
|
|
269 |
|
427 |
|
270 |
return (krb5_cc_resolve(ctx, ccname, ccache)); |
428 |
debug3_f("setting default ccname to %s", ccname); |
|
|
429 |
/* set the default with already expanded user IDs */ |
430 |
ret = krb5_cc_set_default_name(ctx, ccname); |
431 |
if (ret) |
432 |
return ret; |
433 |
|
434 |
if ((colon = strstr(ccname, ":")) != NULL) { |
435 |
type_len = colon - ccname; |
436 |
type = malloc((type_len + 1) * sizeof(char)); |
437 |
if (type == NULL) |
438 |
return ENOMEM; |
439 |
strncpy(type, ccname, type_len); |
440 |
type[type_len] = 0; |
441 |
} else { |
442 |
type = strdup(ccname); |
443 |
} |
444 |
|
445 |
/* If we have a credential cache from krb5.conf, we need to switch |
446 |
* a primary cache for this collection, if it supports that (non-FILE) |
447 |
*/ |
448 |
if (krb5_cc_support_switch(ctx, type)) { |
449 |
debug3_f("calling cc_new_unique(%s)", ccname); |
450 |
ret = krb5_cc_new_unique(ctx, type, NULL, ccache); |
451 |
free(type); |
452 |
if (ret) |
453 |
return ret; |
454 |
|
455 |
debug3_f("calling cc_switch()"); |
456 |
return krb5_cc_switch(ctx, *ccache); |
457 |
} else { |
458 |
/* Otherwise, we can not create a unique ccname here (either |
459 |
* it is already unique from above or the type does not support |
460 |
* collections |
461 |
*/ |
462 |
free(type); |
463 |
debug3_f("calling cc_resolve(%s)", ccname); |
464 |
return (krb5_cc_resolve(ctx, ccname, ccache)); |
465 |
} |
271 |
} |
466 |
} |
272 |
#endif /* !HEIMDAL */ |
467 |
#endif /* !HEIMDAL */ |
273 |
#endif /* KRB5 */ |
468 |
#endif /* KRB5 */ |