On Thu, Jan 27, 2022 at 02:46:04PM -0500, Viktor Dukhovni wrote:

> Perhaps your Kerberos (GSSAPI via SASL?) library is ignoring environment
> variables in processes that change uids (smtpd starts as root and then
> drops privs).  Of course that makes sense for a setuid process, but not
> so much for a proces that starts as root...  The Fedora 31
> secure_getenv(3) manpage says:

See, for example, the MIT implementation:

    https://github.com/krb5/krb5/blob/master/src/lib/krb5/os/ktdefname.c#L44-L47

    static krb5_error_code
    kt_default_name(krb5_context context, char **name_out)
        ...
        } else if (context->profile_secure == FALSE &&
                   (str = secure_getenv("KRB5_KTNAME")) != NULL) {
            *name_out = strdup(str);
            return (*name_out == NULL) ? ENOMEM : 0;
        ...

> You'll need to try a test program that starts as root, then changes
> uid to (e.g.) "postfix", and see whether "secure_getenv()" reports
> the expected environment variables.
> 
> The most likely reasons for changes are in Cyrus SASL, not Postfix,
> which does not directly do anything with Kerberos.

On Fedora 31 (now dated), secure_getenv(3) does not suppress environment
variables in processes that drop privs.  See attached test program.

    # KRB5_KTNAME=FILE:/etc/postfix/smtp.keytab /tmp/suid -u 89 -v KRB5_KTNAME
    uid = 89, euid=89, suid=89
    getenv('KRB5_KTNAME') = FILE:/etc/postfix/smtp.keytab
    secure_getenv('KRB5_KTNAME') = FILE:/etc/postfix/smtp.keytab

Note that the keytab file in question does need to be readable by
the "postfix" user, not just "root".  The smtpd(8) process drops
privs.

-- 
    Viktor.
#define _GNU_SOURCE
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <err.h>

int main(int argc, char *argv[])
{
    const char *var = "HOME";
    uid_t uid = 0;
    uid_t euid = 0;
    uid_t suid = 0;
    int c;

    while ((c = getopt(argc, argv, "u:v:")) != EOF) {
        switch (c) {
        case 'u':
            uid = (uid_t) atoi(optarg);
            break;
        case 'v':
            var = optarg;
            break;
        default:
            errx(1, "Usage: %s [-u uid] [-v var]", argv[0]);
            break;
        }
    }

    if (uid != 0) {
        if (setuid(uid) != 0)
            err(1, "%s: setuid", argv[0]);
    }
    if (getresuid(&uid, &euid, &suid) != 0)
        err(1, "%s: getresuid", argv[0]);
    printf("uid = %d, euid=%d, suid=%d\n",
           (int) uid, (int) euid, (int) suid);

    printf("getenv('%s') = %s\n", var, getenv(var));
    printf("secure_getenv('%s') = %s\n", var, secure_getenv(var));
    return 0;
}

Reply via email to