~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to src/auth/mech-gssapi.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
78
78
static gss_OID_desc mech_gssapi_krb5_oid =
79
79
        { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
80
80
 
 
81
static int
 
82
mech_gssapi_wrap(struct gssapi_auth_request *request, gss_buffer_desc inbuf);
 
83
 
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)
214
217
        return name;
215
218
}
216
219
 
 
220
static gss_name_t
 
221
duplicate_name(struct auth_request *request, gss_name_t old)
 
222
{
 
223
        OM_uint32 major_status, minor_status;
 
224
        gss_name_t new;
 
225
 
 
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;
 
231
        }
 
232
        return new;
 
233
}
 
234
 
217
235
static bool data_has_nuls(const void *data, unsigned int len)
218
236
{
219
237
        const unsigned char *c = data;
328
346
        }
329
347
 
330
348
        if (ret == 0) {
331
 
                auth_request_handler_reply_continue(auth_request,
332
 
                                                    output_token.value,
333
 
                                                    output_token.length);
 
349
                if (output_token.length > 0) {
 
350
                        auth_request_handler_reply_continue(auth_request,
 
351
                                                            output_token.value,
 
352
                                                            output_token.length);
 
353
                } else {
 
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);
 
357
                }
334
358
        }
335
359
        (void)gss_release_buffer(&minor_status, &output_token);
336
360
        return ret;
380
404
 
381
405
#ifdef USE_KRB5_USEROK
382
406
static bool
 
407
k5_principal_is_authorized(struct auth_request *request, const char *name)
 
408
{
 
409
        const char *value, *const *authorized_names, *const *tmp;
 
410
 
 
411
        value = auth_fields_find(request->extra_fields, "k5principals");
 
412
        if (value == NULL)
 
413
                return FALSE;
 
414
 
 
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);
 
420
                        return TRUE;
 
421
                }
 
422
        }
 
423
        return FALSE;
 
424
}
 
425
 
 
426
static bool
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;
392
 
        bool ret = FALSE;
 
436
        bool authorized = FALSE;
393
437
 
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)
397
441
                return FALSE;
398
442
 
399
443
        if (!mech_gssapi_oid_cmp(name_type, GSS_KRB5_NT_PRINCIPAL_NAME) &&
419
463
                                      "krb5_parse_name() failed: %d",
420
464
                                      (int)krb5_err);
421
465
        } else {
 
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,
 
469
                                                        princ_display_name);
 
470
 
422
471
                /* See if the principal is authorized to act as the
423
 
                   specified user */
424
 
                ret = krb5_kuserok(ctx, princ, login_user);
 
472
                   specified (UNIX) user */
 
473
                if (!authorized)
 
474
                        authorized = krb5_kuserok(ctx, princ, login_user);
 
475
 
425
476
                krb5_free_principal(ctx, princ);
426
477
        }
427
478
        krb5_free_context(ctx);
428
 
        return ret;
 
479
        return authorized;
429
480
}
430
481
#endif
431
482
 
483
534
#else
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);
487
538
        return -1;
488
539
#endif
489
540
}
490
541
 
 
542
static void
 
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)
 
547
{
 
548
        struct gssapi_auth_request *gssapi_request =
 
549
                (struct gssapi_auth_request *)request;
 
550
 
 
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. */
 
554
        switch (result) {
 
555
        case PASSDB_RESULT_INTERNAL_FAILURE:
 
556
                auth_request_internal_failure(request);
 
557
                return;
 
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);
 
562
                return;
 
563
        case PASSDB_RESULT_SCHEME_NOT_AVAILABLE:
 
564
        case PASSDB_RESULT_USER_UNKNOWN:
 
565
        case PASSDB_RESULT_PASSWORD_MISMATCH:
 
566
        case PASSDB_RESULT_OK:
 
567
                break;
 
568
        }
 
569
 
 
570
        if (mech_gssapi_userok(gssapi_request, request->user) == 0)
 
571
                auth_request_success(request, NULL, 0);
 
572
        else
 
573
                auth_request_fail(request);
 
574
}
 
575
 
491
576
static int
492
577
mech_gssapi_unwrap(struct gssapi_auth_request *request, gss_buffer_desc inbuf)
493
578
{
510
595
 
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");
516
601
                return -1;
517
602
        }
518
 
        name = (unsigned char *)outbuf.value + 4;
519
 
        name_len = outbuf.length - 4;
520
 
 
521
 
        if (data_has_nuls(name, name_len)) {
522
 
                auth_request_log_info(auth_request, "gssapi",
523
 
                                      "authz_name has NULs");
524
 
                return -1;
 
603
 
 
604
        if (outbuf.length > 4) {
 
605
                name = (unsigned char *)outbuf.value + 4;
 
606
                name_len = outbuf.length - 4;
 
607
 
 
608
                if (data_has_nuls(name, name_len)) {
 
609
                        auth_request_log_info(auth_request, "gssapi",
 
610
                                              "authz_name has NULs");
 
611
                        return -1;
 
612
                }
 
613
 
 
614
                login_user = p_strndup(auth_request->pool, name, name_len);
 
615
                request->authz_name = import_name(auth_request, name, name_len);
 
616
        } else {
 
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)
 
621
                        return -1;
525
622
        }
526
623
 
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");
531
626
                return -1;
532
627
        }
533
628
 
534
 
        if (mech_gssapi_userok(request, login_user) < 0)
535
 
                return -1;
536
 
 
 
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);
540
637
                return -1;
541
638
        }
542
639
 
543
 
        auth_request_success(auth_request, NULL, 0);
 
640
        /* Continue in callback once auth_request is populated with passdb
 
641
           information. */
 
642
        auth_request->passdb_success = TRUE; /* default to success */
 
643
        auth_request_lookup_credentials(&request->auth_request, "",
 
644
                                        gssapi_credentials_callback);
544
645
        return 0;
545
646
}
546
647