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