Blame src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c

Packit fd8b60
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit fd8b60
/* plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c */
Packit fd8b60
/* Copyright (c) 2004-2005, Novell, Inc.
Packit fd8b60
 * All rights reserved.
Packit fd8b60
 *
Packit fd8b60
 * Redistribution and use in source and binary forms, with or without
Packit fd8b60
 * modification, are permitted provided that the following conditions are met:
Packit fd8b60
 *
Packit fd8b60
 *   * Redistributions of source code must retain the above copyright notice,
Packit fd8b60
 *       this list of conditions and the following disclaimer.
Packit fd8b60
 *   * Redistributions in binary form must reproduce the above copyright
Packit fd8b60
 *       notice, this list of conditions and the following disclaimer in the
Packit fd8b60
 *       documentation and/or other materials provided with the distribution.
Packit fd8b60
 *   * The copyright holder's name is not used to endorse or promote products
Packit fd8b60
 *       derived from this software without specific prior written permission.
Packit fd8b60
 *
Packit fd8b60
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit fd8b60
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit fd8b60
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit fd8b60
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
Packit fd8b60
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
Packit fd8b60
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
Packit fd8b60
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
Packit fd8b60
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
Packit fd8b60
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit fd8b60
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Packit fd8b60
 * POSSIBILITY OF SUCH DAMAGE.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Create / Delete / Modify / View / List service objects.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Service objects have rights over realm objects and principals. The following
Packit fd8b60
 * functions manage the service objects.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
#include <k5-int.h>
Packit fd8b60
#include <k5-hex.h>
Packit fd8b60
#include "kdb5_ldap_util.h"
Packit fd8b60
#include "kdb5_ldap_list.h"
Packit fd8b60
Packit fd8b60
/* Get the configured LDAP service password file.  The caller should free the
Packit fd8b60
 * result with profile_release_string(). */
Packit fd8b60
static krb5_error_code
Packit fd8b60
get_conf_service_file(profile_t profile, const char *realm, char **path_out)
Packit fd8b60
{
Packit fd8b60
    char *subsection, *path;
Packit fd8b60
    long ret;
Packit fd8b60
Packit fd8b60
    *path_out = NULL;
Packit fd8b60
Packit fd8b60
    /* Get the [dbmodules] subsection for realm. */
Packit fd8b60
    ret = profile_get_string(profile, KDB_REALM_SECTION, realm,
Packit fd8b60
                             KDB_MODULE_POINTER, realm, &subsection);
Packit fd8b60
    if (ret)
Packit fd8b60
        return ret;
Packit fd8b60
Packit fd8b60
    /* Look up the password file in the [dbmodules] subsection. */
Packit fd8b60
    ret = profile_get_string(profile, KDB_MODULE_SECTION, subsection,
Packit fd8b60
                             KRB5_CONF_LDAP_SERVICE_PASSWORD_FILE, NULL,
Packit fd8b60
                             &path);
Packit fd8b60
    profile_release_string(subsection);
Packit fd8b60
    if (ret)
Packit fd8b60
        return ret;
Packit fd8b60
Packit fd8b60
    if (path == NULL) {
Packit fd8b60
        /* Look up the password file in [dbdefaults] as a fallback. */
Packit fd8b60
        ret = profile_get_string(profile, KDB_MODULE_DEF_SECTION,
Packit fd8b60
                                 KRB5_CONF_LDAP_SERVICE_PASSWORD_FILE, NULL,
Packit fd8b60
                                 NULL, &path);
Packit fd8b60
        if (ret)
Packit fd8b60
            return ret;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    if (path == NULL) {
Packit fd8b60
        k5_setmsg(util_context, ENOENT,
Packit fd8b60
                  _("ldap_service_password_file not configured"));
Packit fd8b60
        return ENOENT;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    *path_out = path;
Packit fd8b60
    return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Convert the user supplied password into hexadecimal and stash it. Only a
Packit fd8b60
 * little more secure than storing plain password in the file ...
Packit fd8b60
 */
Packit fd8b60
void
Packit fd8b60
kdb5_ldap_stash_service_password(int argc, char **argv)
Packit fd8b60
{
Packit fd8b60
    int ret = 0;
Packit fd8b60
    unsigned int passwd_len = 0;
Packit fd8b60
    char *me = progname;
Packit fd8b60
    char *service_object = NULL;
Packit fd8b60
    char *file_name = NULL, *tmp_file = NULL;
Packit fd8b60
    char passwd[MAX_SERVICE_PASSWD_LEN];
Packit fd8b60
    char *str = NULL, *hexpasswd = NULL;
Packit fd8b60
    char line[MAX_LEN];
Packit fd8b60
    FILE *pfile = NULL;
Packit fd8b60
    krb5_boolean print_usage = FALSE;
Packit fd8b60
    mode_t old_mode = 0;
Packit fd8b60
Packit fd8b60
    /*
Packit fd8b60
     * Format:
Packit fd8b60
     *   stashsrvpw [-f filename] service_dn
Packit fd8b60
     * where
Packit fd8b60
     *   'service_dn' is the DN of the service object
Packit fd8b60
     *   'filename' is the path of the stash file
Packit fd8b60
     */
Packit fd8b60
    if (argc != 2 && argc != 4) {
Packit fd8b60
        print_usage = TRUE;
Packit fd8b60
        goto cleanup;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    if (argc == 4) {
Packit fd8b60
        /* Find the stash file name */
Packit fd8b60
        if (strcmp (argv[1], "-f") == 0) {
Packit fd8b60
            if (((file_name = strdup (argv[2])) == NULL) ||
Packit fd8b60
                ((service_object = strdup (argv[3])) == NULL)) {
Packit fd8b60
                com_err(me, ENOMEM,
Packit fd8b60
                        _("while setting service object password"));
Packit fd8b60
                goto cleanup;
Packit fd8b60
            }
Packit fd8b60
        } else if (strcmp (argv[2], "-f") == 0) {
Packit fd8b60
            if (((file_name = strdup (argv[3])) == NULL) ||
Packit fd8b60
                ((service_object = strdup (argv[1])) == NULL)) {
Packit fd8b60
                com_err(me, ENOMEM,
Packit fd8b60
                        _("while setting service object password"));
Packit fd8b60
                goto cleanup;
Packit fd8b60
            }
Packit fd8b60
        } else {
Packit fd8b60
            print_usage = TRUE;
Packit fd8b60
            goto cleanup;
Packit fd8b60
        }
Packit fd8b60
    } else { /* argc == 2 */
Packit fd8b60
        service_object = strdup (argv[1]);
Packit fd8b60
        if (service_object == NULL) {
Packit fd8b60
            com_err(me, ENOMEM, _("while setting service object password"));
Packit fd8b60
            goto cleanup;
Packit fd8b60
        }
Packit fd8b60
Packit fd8b60
        ret = get_conf_service_file(util_context->profile,
Packit fd8b60
                                    util_context->default_realm, &file_name);
Packit fd8b60
        if (ret) {
Packit fd8b60
            com_err(me, ret, _("while getting service password filename"));
Packit fd8b60
            goto cleanup;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    /* Get password from user */
Packit fd8b60
    {
Packit fd8b60
        char prompt1[256], prompt2[256];
Packit fd8b60
Packit fd8b60
        /* Get the service object password from the terminal */
Packit fd8b60
        memset(passwd, 0, sizeof (passwd));
Packit fd8b60
        passwd_len = sizeof (passwd);
Packit fd8b60
Packit fd8b60
        snprintf(prompt1, sizeof(prompt1), _("Password for \"%s\""),
Packit fd8b60
                 service_object);
Packit fd8b60
Packit fd8b60
        snprintf(prompt2, sizeof(prompt2), _("Re-enter password for \"%s\""),
Packit fd8b60
                 service_object);
Packit fd8b60
Packit fd8b60
        ret = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len);
Packit fd8b60
        if (ret != 0) {
Packit fd8b60
            com_err(me, ret, _("while setting service object password"));
Packit fd8b60
            memset(passwd, 0, sizeof (passwd));
Packit fd8b60
            goto cleanup;
Packit fd8b60
        }
Packit fd8b60
Packit fd8b60
        if (passwd_len == 0) {
Packit fd8b60
            printf(_("%s: Invalid password\n"), me);
Packit fd8b60
            memset(passwd, 0, MAX_SERVICE_PASSWD_LEN);
Packit fd8b60
            goto cleanup;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    /* Convert the password to hexadecimal */
Packit fd8b60
    ret = k5_hex_encode(passwd, passwd_len, FALSE, &hexpasswd);
Packit fd8b60
    zap(passwd, passwd_len);
Packit fd8b60
    if (ret != 0) {
Packit fd8b60
        com_err(me, ret, _("Failed to convert the password to hexadecimal"));
Packit fd8b60
        goto cleanup;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    /* TODO: file lock for the service password file */
Packit fd8b60
Packit fd8b60
    /* set password in the file */
Packit fd8b60
    old_mode = umask(0177);
Packit Service a81408
    pfile = fopen(file_name, "a+");
Packit fd8b60
    if (pfile == NULL) {
Packit fd8b60
        com_err(me, errno, _("Failed to open file %s: %s"), file_name,
Packit fd8b60
                strerror (errno));
Packit fd8b60
        goto cleanup;
Packit fd8b60
    }
Packit fd8b60
    set_cloexec_file(pfile);
Packit fd8b60
    rewind (pfile);
Packit fd8b60
    umask(old_mode);
Packit fd8b60
Packit fd8b60
    while (fgets (line, MAX_LEN, pfile) != NULL) {
Packit fd8b60
        if ((str = strstr (line, service_object)) != NULL) {
Packit fd8b60
            /* White spaces not allowed */
Packit fd8b60
            if (line [strlen (service_object)] == '#')
Packit fd8b60
                break;
Packit fd8b60
            str = NULL;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    if (str == NULL) {
Packit fd8b60
        if (feof(pfile)) {
Packit fd8b60
            /* If the service object dn is not present in the service password file */
Packit fd8b60
            if (fprintf(pfile, "%s#{HEX}%s\n", service_object, hexpasswd) < 0) {
Packit fd8b60
                com_err(me, errno,
Packit fd8b60
                        _("Failed to write service object password to file"));
Packit fd8b60
                fclose(pfile);
Packit fd8b60
                goto cleanup;
Packit fd8b60
            }
Packit fd8b60
        } else {
Packit fd8b60
            com_err(me, errno,
Packit fd8b60
                    _("Error reading service object password file"));
Packit fd8b60
            fclose(pfile);
Packit fd8b60
            goto cleanup;
Packit fd8b60
        }
Packit fd8b60
        fclose(pfile);
Packit fd8b60
    } else {
Packit fd8b60
        /*
Packit fd8b60
         * Password entry for the service object is already present in the file
Packit fd8b60
         * Delete the existing entry and add the new entry
Packit fd8b60
         */
Packit fd8b60
        FILE *newfile;
Packit fd8b60
Packit fd8b60
        mode_t omask;
Packit fd8b60
Packit fd8b60
        /* Create a new file with the extension .tmp */
Packit fd8b60
        if (asprintf(&tmp_file,"%s.tmp",file_name) < 0) {
Packit fd8b60
            com_err(me, ENOMEM, _("while setting service object password"));
Packit fd8b60
            fclose(pfile);
Packit fd8b60
            goto cleanup;
Packit fd8b60
        }
Packit fd8b60
Packit fd8b60
        omask = umask(077);
Packit fd8b60
        newfile = fopen(tmp_file, "w");
Packit fd8b60
        umask (omask);
Packit fd8b60
        if (newfile == NULL) {
Packit fd8b60
            com_err(me, errno, _("Error creating file %s"), tmp_file);
Packit fd8b60
            fclose(pfile);
Packit fd8b60
            goto cleanup;
Packit fd8b60
        }
Packit fd8b60
        set_cloexec_file(newfile);
Packit fd8b60
Packit fd8b60
        fseek(pfile, 0, SEEK_SET);
Packit fd8b60
        while (fgets(line, MAX_LEN, pfile) != NULL) {
Packit fd8b60
            if (((str = strstr(line, service_object)) != NULL) &&
Packit fd8b60
                (line[strlen(service_object)] == '#')) {
Packit fd8b60
                if (fprintf(newfile, "%s#{HEX}%s\n", service_object, hexpasswd) < 0) {
Packit fd8b60
                    com_err(me, errno, _("Failed to write service object "
Packit fd8b60
                                         "password to file"));
Packit fd8b60
                    fclose(newfile);
Packit fd8b60
                    unlink(tmp_file);
Packit fd8b60
                    fclose(pfile);
Packit fd8b60
                    goto cleanup;
Packit fd8b60
                }
Packit fd8b60
            } else {
Packit fd8b60
                if (fprintf (newfile, "%s", line) < 0) {
Packit fd8b60
                    com_err(me, errno, _("Failed to write service object "
Packit fd8b60
                                         "password to file"));
Packit fd8b60
                    fclose(newfile);
Packit fd8b60
                    unlink(tmp_file);
Packit fd8b60
                    fclose(pfile);
Packit fd8b60
                    goto cleanup;
Packit fd8b60
                }
Packit fd8b60
            }
Packit fd8b60
        }
Packit fd8b60
Packit fd8b60
        if (!feof(pfile)) {
Packit fd8b60
            com_err(me, errno,
Packit fd8b60
                    _("Error reading service object password file"));
Packit fd8b60
            fclose(newfile);
Packit fd8b60
            unlink(tmp_file);
Packit fd8b60
            fclose(pfile);
Packit fd8b60
            goto cleanup;
Packit fd8b60
        }
Packit fd8b60
Packit fd8b60
        /* TODO: file lock for the service passowrd file */
Packit fd8b60
Packit fd8b60
        fclose(pfile);
Packit fd8b60
        fclose(newfile);
Packit fd8b60
Packit fd8b60
        ret = rename(tmp_file, file_name);
Packit fd8b60
        if (ret != 0) {
Packit fd8b60
            com_err(me, errno,
Packit fd8b60
                    _("Failed to write service object password to file"));
Packit fd8b60
            goto cleanup;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
    ret = 0;
Packit fd8b60
Packit fd8b60
cleanup:
Packit fd8b60
Packit fd8b60
    zapfreestr(hexpasswd);
Packit fd8b60
Packit fd8b60
    if (service_object)
Packit fd8b60
        free(service_object);
Packit fd8b60
Packit fd8b60
    profile_release_string(file_name);
Packit fd8b60
Packit fd8b60
    if (tmp_file)
Packit fd8b60
        free(tmp_file);
Packit fd8b60
Packit fd8b60
    if (print_usage)
Packit fd8b60
        usage();
Packit fd8b60
/*      db_usage(STASH_SRV_PW); */
Packit fd8b60
Packit fd8b60
    if (ret)
Packit fd8b60
        exit_status++;
Packit fd8b60
}