78
78
static gss_OID_desc mech_gssapi_krb5_oid =
79
79
{ 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
82
mech_gssapi_wrap(struct gssapi_auth_request *request, gss_buffer_desc inbuf);
81
84
static void mech_gssapi_log_error(struct auth_request *request,
82
85
OM_uint32 status_value, int status_type,
83
86
const char *description)
221
duplicate_name(struct auth_request *request, gss_name_t old)
223
OM_uint32 major_status, minor_status;
226
major_status = gss_duplicate_name(&minor_status, old, &new);
227
if (GSS_ERROR(major_status)) {
228
mech_gssapi_log_error(request, major_status, GSS_C_GSS_CODE,
229
"gss_duplicate_name");
230
return GSS_C_NO_NAME;
217
235
static bool data_has_nuls(const void *data, unsigned int len)
219
237
const unsigned char *c = data;
331
auth_request_handler_reply_continue(auth_request,
333
output_token.length);
349
if (output_token.length > 0) {
350
auth_request_handler_reply_continue(auth_request,
352
output_token.length);
354
/* If there is no output token, go straight to wrap,
355
which is expecting an empty input token. */
356
ret = mech_gssapi_wrap(request, output_token);
335
359
(void)gss_release_buffer(&minor_status, &output_token);
381
405
#ifdef USE_KRB5_USEROK
407
k5_principal_is_authorized(struct auth_request *request, const char *name)
409
const char *value, *const *authorized_names, *const *tmp;
411
value = auth_fields_find(request->extra_fields, "k5principals");
415
authorized_names = t_strsplit_spaces(value, ",");
416
for (tmp = authorized_names; *tmp != NULL; tmp++) {
417
if (strcmp(*tmp, name) == 0) {
418
auth_request_log_debug(request, "gssapi",
419
"authorized by k5principals field: %s", name);
383
427
mech_gssapi_krb5_userok(struct gssapi_auth_request *request,
384
428
gss_name_t name, const char *login_user,
385
429
bool check_name_type)
389
433
krb5_error_code krb5_err;
390
434
gss_OID name_type;
391
435
const char *princ_display_name;
436
bool authorized = FALSE;
394
438
/* Parse out the principal's username */
395
if (!get_display_name(&request->auth_request, name, &name_type,
396
&princ_display_name) < 0)
439
if (get_display_name(&request->auth_request, name, &name_type,
440
&princ_display_name) < 0)
399
443
if (!mech_gssapi_oid_cmp(name_type, GSS_KRB5_NT_PRINCIPAL_NAME) &&
419
463
"krb5_parse_name() failed: %d",
466
/* See if the principal is in the list of authorized
467
* principals for the user */
468
authorized = k5_principal_is_authorized(&request->auth_request,
422
471
/* See if the principal is authorized to act as the
424
ret = krb5_kuserok(ctx, princ, login_user);
472
specified (UNIX) user */
474
authorized = krb5_kuserok(ctx, princ, login_user);
425
476
krb5_free_principal(ctx, princ);
427
478
krb5_free_context(ctx);
484
535
auth_request_log_info(auth_request, "gssapi",
485
536
"Cross-realm authentication not supported "
486
"(authz_name=%s)", login_user);
537
"(authn_name=%s, authz_name=%s)", request->auth_request.original_username, login_user);
543
gssapi_credentials_callback(enum passdb_result result,
544
const unsigned char *credentials ATTR_UNUSED,
545
size_t size ATTR_UNUSED,
546
struct auth_request *request)
548
struct gssapi_auth_request *gssapi_request =
549
(struct gssapi_auth_request *)request;
551
/* We don't care much whether the lookup succeeded or not because GSSAPI
552
* does not strictly require a passdb. But if a passdb is configured,
553
* now the k5principals field will have been filled in. */
555
case PASSDB_RESULT_INTERNAL_FAILURE:
556
auth_request_internal_failure(request);
558
case PASSDB_RESULT_USER_DISABLED:
559
case PASSDB_RESULT_PASS_EXPIRED:
560
/* user is explicitly disabled, don't allow it to log in */
561
auth_request_fail(request);
563
case PASSDB_RESULT_SCHEME_NOT_AVAILABLE:
564
case PASSDB_RESULT_USER_UNKNOWN:
565
case PASSDB_RESULT_PASSWORD_MISMATCH:
566
case PASSDB_RESULT_OK:
570
if (mech_gssapi_userok(gssapi_request, request->user) == 0)
571
auth_request_success(request, NULL, 0);
573
auth_request_fail(request);
492
577
mech_gssapi_unwrap(struct gssapi_auth_request *request, gss_buffer_desc inbuf)
511
596
/* outbuf[0] contains bitmask for selected security layer,
512
597
outbuf[1..3] contains maximum output_message size */
513
if (outbuf.length <= 4) {
598
if (outbuf.length < 4) {
514
599
auth_request_log_error(auth_request, "gssapi",
515
600
"Invalid response length");
518
name = (unsigned char *)outbuf.value + 4;
519
name_len = outbuf.length - 4;
521
if (data_has_nuls(name, name_len)) {
522
auth_request_log_info(auth_request, "gssapi",
523
"authz_name has NULs");
604
if (outbuf.length > 4) {
605
name = (unsigned char *)outbuf.value + 4;
606
name_len = outbuf.length - 4;
608
if (data_has_nuls(name, name_len)) {
609
auth_request_log_info(auth_request, "gssapi",
610
"authz_name has NULs");
614
login_user = p_strndup(auth_request->pool, name, name_len);
615
request->authz_name = import_name(auth_request, name, name_len);
617
request->authz_name = duplicate_name(auth_request,
618
request->authn_name);
619
if (get_display_name(auth_request, request->authz_name,
620
NULL, &login_user) < 0)
527
login_user = p_strndup(auth_request->pool, name, name_len);
528
request->authz_name = import_name(auth_request, name, name_len);
529
624
if (request->authz_name == GSS_C_NO_NAME) {
530
625
auth_request_log_info(auth_request, "gssapi", "no authz_name");
534
if (mech_gssapi_userok(request, login_user) < 0)
629
/* Set username early, so that the credential lookup is for the
630
* authorizing user. This means the username in subsequent log
631
* messagess will be the authorization name, not the authentication
632
* name, which may mean that future log messages should be adjusted
633
* to log the right thing. */
537
634
if (!auth_request_set_username(auth_request, login_user, &error)) {
538
635
auth_request_log_info(auth_request, "gssapi",
539
636
"authz_name: %s", error);
543
auth_request_success(auth_request, NULL, 0);
640
/* Continue in callback once auth_request is populated with passdb
642
auth_request->passdb_success = TRUE; /* default to success */
643
auth_request_lookup_credentials(&request->auth_request, "",
644
gssapi_credentials_callback);