Exemple #1
0
int
iprop_replay(struct replay_options *opt, int argc, char **argv)
{
    kadm5_server_context *server_context;
    krb5_error_code ret;

    server_context = get_kadmin_context(opt->config_file_string,
					opt->realm_string);

    ret = server_context->db->hdb_open(context,
				       server_context->db,
				       O_RDWR | O_CREAT, 0600);
    if (ret)
	krb5_err (context, 1, ret, "db->open");

    ret = kadm5_log_init (server_context);
    if (ret)
	krb5_err (context, 1, ret, "kadm5_log_init");

    ret = kadm5_log_foreach (server_context, apply_entry, opt);
    if(ret)
	krb5_warn(context, ret, "kadm5_log_foreach");
    ret = kadm5_log_end (server_context);
    if (ret)
	krb5_warn(context, ret, "kadm5_log_end");
    ret = server_context->db->hdb_close (context, server_context->db);
    if (ret)
	krb5_err (context, 1, ret, "db->close");

    return 0;
}
Exemple #2
0
int
last_version(struct last_version_options *opt, int argc, char **argv)
{
    kadm5_server_context *server_context;
    krb5_error_code ret;
    uint32_t version;

    server_context = get_kadmin_context(opt->config_file_string,
					opt->realm_string);

    ret = kadm5_log_init (server_context);
    if (ret)
	krb5_err (context, 1, ret, "kadm5_log_init");

    ret = kadm5_log_get_version (server_context, &version);
    if (ret)
	krb5_err (context, 1, ret, "kadm5_log_get_version");

    ret = kadm5_log_end (server_context);
    if (ret)
	krb5_warn(context, ret, "kadm5_log_end");

    printf("version: %lu\n", (unsigned long)version);

    return 0;
}
Exemple #3
0
kadm5_ret_t
kadm5_log_nop (kadm5_server_context *context)
{
    krb5_storage *sp;
    kadm5_ret_t ret;
    kadm5_log_context *log_context = &context->log_context;

    sp = krb5_storage_emem();
    ret = kadm5_log_preamble (context, sp, kadm_nop);
    if (ret) {
	krb5_storage_free (sp);
	return ret;
    }
    krb5_store_int32 (sp, 0);
    krb5_store_int32 (sp, 0);
    ret = kadm5_log_postamble (log_context, sp);
    if (ret) {
	krb5_storage_free (sp);
	return ret;
    }
    ret = kadm5_log_flush (log_context, sp);
    krb5_storage_free (sp);
    if (ret)
	return ret;
    ret = kadm5_log_end (context);
    return ret;
}
Exemple #4
0
kadm5_ret_t
kadm5_log_truncate (kadm5_server_context *server_context)
{
    kadm5_ret_t ret;
    u_int32_t vno;

    ret = kadm5_log_init (server_context);
    if (ret)
	return ret;

    ret = kadm5_log_get_version (server_context, &vno);
    if (ret)
	return ret;

    ret = kadm5_log_reinit (server_context);
    if (ret)
	return ret;

    ret = kadm5_log_set_version (server_context, vno + 1);
    if (ret)
	return ret;

    ret = kadm5_log_nop (server_context);
    if (ret)
	return ret;

    ret = kadm5_log_end (server_context);
    if (ret)
	return ret;
    return 0;

}
Exemple #5
0
kadm5_ret_t
kadm5_s_create_principal_with_key(void *server_handle,
				  kadm5_principal_ent_t princ,
				  uint32_t mask)
{
    kadm5_ret_t ret;
    hdb_entry_ex ent;
    kadm5_server_context *context = server_handle;

    if ((mask & KADM5_KVNO) == 0) {
	/* create_principal() through _kadm5_setup_entry(), will need this */
	princ->kvno = 1;
	mask |= KADM5_KVNO;
    }

    ret = create_principal(context, princ, mask, &ent,
			   KADM5_PRINCIPAL | KADM5_KEY_DATA,
			   KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME
			   | KADM5_MOD_NAME | KADM5_MKVNO
			   | KADM5_AUX_ATTRIBUTES
			   | KADM5_POLICY_CLR | KADM5_LAST_SUCCESS
			   | KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT);
    if (ret)
        return ret;

    if (!context->keep_open) {
        ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
        if (ret) {
            hdb_free_entry(context->context, &ent);
            return ret;
        }
    }

    ret = kadm5_log_init(context);
    if (ret)
        goto out;

    ret = hdb_seal_keys(context->context, context->db, &ent.entry);
    if (ret)
	goto out2;

    /* This logs the change for iprop and writes to the HDB */
    ret = kadm5_log_create(context, &ent.entry);

 out2:
    (void) kadm5_log_end(context);
 out:
    if (!context->keep_open) {
        kadm5_ret_t ret2;
        ret2 = context->db->hdb_close(context->context, context->db);
        if (ret == 0 && ret2 != 0)
            ret = ret2;
    }
    hdb_free_entry(context->context, &ent);
    return _kadm5_error_code(ret);
}
Exemple #6
0
kadm5_ret_t
kadm5_log_modify (kadm5_server_context *context,
		  hdb_entry *ent,
		  u_int32_t mask)
{
    krb5_storage *sp;
    kadm5_ret_t ret;
    krb5_data value;
    u_int32_t len;
    kadm5_log_context *log_context = &context->log_context;

    krb5_data_zero(&value);

    sp = krb5_storage_emem();
    ret = hdb_entry2value (context->context, ent, &value);
    if (ret)
	goto failed;

    ret = kadm5_log_preamble (context, sp, kadm_modify);
    if (ret)
	goto failed;

    len = value.length + 4;
    ret = krb5_store_int32 (sp, len);
    if (ret)
	goto failed;
    ret = krb5_store_int32 (sp, mask);
    if (ret)
	goto failed;
    krb5_storage_write (sp, value.data, value.length);

    ret = krb5_store_int32 (sp, len);
    if (ret)
	goto failed;
    ret = kadm5_log_postamble (log_context, sp);
    if (ret)
	goto failed;
    ret = kadm5_log_flush (log_context, sp);
    if (ret)
	goto failed;
    krb5_data_free(&value);
    krb5_storage_free (sp);
    return kadm5_log_end (context);
failed:
    krb5_data_free(&value);
    krb5_storage_free(sp);
    return ret;
}
Exemple #7
0
kadm5_ret_t
kadm5_log_delete (kadm5_server_context *context,
		  krb5_principal princ)
{
    krb5_storage *sp;
    kadm5_ret_t ret;
    off_t off;
    off_t len;
    kadm5_log_context *log_context = &context->log_context;

    sp = krb5_storage_emem();
    if (sp == NULL)
	return ENOMEM;
    ret = kadm5_log_preamble (context, sp, kadm_delete);
    if (ret)
	goto out;
    ret = krb5_store_int32 (sp, 0);
    if (ret)
	goto out;
    off = krb5_storage_seek (sp, 0, SEEK_CUR);
    ret = krb5_store_principal (sp, princ);
    if (ret)
	goto out;
    len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
    krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
    ret = krb5_store_int32 (sp, len);
    if (ret)
	goto out;
    krb5_storage_seek(sp, len, SEEK_CUR);
    ret = krb5_store_int32 (sp, len);
    if (ret)
	goto out;
    ret = kadm5_log_postamble (log_context, sp);
    if (ret)
	goto out;
    ret = kadm5_log_flush (log_context, sp);
    if (ret)
	goto out;
    ret = kadm5_log_end (context);
out:
    krb5_storage_free (sp);
    return ret;
}
Exemple #8
0
int
iprop_dump(struct dump_options *opt, int argc, char **argv)
{
    kadm5_server_context *server_context;
    krb5_error_code ret;

    server_context = get_kadmin_context(opt->config_file_string,
					opt->realm_string);

    ret = kadm5_log_init (server_context);
    if (ret)
	krb5_err (context, 1, ret, "kadm5_log_init");

    ret = kadm5_log_foreach (server_context, print_entry, NULL);
    if(ret)
	krb5_warn(context, ret, "kadm5_log_foreach");

    ret = kadm5_log_end (server_context);
    if (ret)
	krb5_warn(context, ret, "kadm5_log_end");
    return 0;
}
Exemple #9
0
kadm5_ret_t
kadm5_log_create (kadm5_server_context *context,
		  hdb_entry *ent)
{
    krb5_storage *sp;
    kadm5_ret_t ret;
    krb5_data value;
    kadm5_log_context *log_context = &context->log_context;

    sp = krb5_storage_emem();
    ret = hdb_entry2value (context->context, ent, &value);
    if (ret) {
	krb5_storage_free(sp);
	return ret;
    }
    ret = kadm5_log_preamble (context, sp, kadm_create);
    if (ret) {
	krb5_data_free (&value);
	krb5_storage_free(sp);
	return ret;
    }
    krb5_store_int32 (sp, value.length);
    krb5_storage_write(sp, value.data, value.length);
    krb5_store_int32 (sp, value.length);
    krb5_data_free (&value);
    ret = kadm5_log_postamble (log_context, sp);
    if (ret) {
	krb5_storage_free (sp);
	return ret;
    }
    ret = kadm5_log_flush (log_context, sp);
    krb5_storage_free (sp);
    if (ret)
	return ret;
    ret = kadm5_log_end (context);
    return ret;
}
Exemple #10
0
kadm5_ret_t
kadm5_log_rename (kadm5_server_context *context,
		  krb5_principal source,
		  hdb_entry *ent)
{
    krb5_storage *sp;
    kadm5_ret_t ret;
    off_t off;
    off_t len;
    krb5_data value;
    kadm5_log_context *log_context = &context->log_context;

    krb5_data_zero(&value);

    sp = krb5_storage_emem();
    ret = hdb_entry2value (context->context, ent, &value);
    if (ret)
	goto failed;

    ret = kadm5_log_preamble (context, sp, kadm_rename);
    if (ret)
	goto failed;

    ret = krb5_store_int32 (sp, 0);
    if (ret)
	goto failed;
    off = krb5_storage_seek (sp, 0, SEEK_CUR);
    ret = krb5_store_principal (sp, source);
    if (ret)
	goto failed;

    krb5_storage_write(sp, value.data, value.length);
    len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;

    krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
    ret = krb5_store_int32 (sp, len);
    if (ret)
	goto failed;

    krb5_storage_seek(sp, len, SEEK_CUR);
    ret = krb5_store_int32 (sp, len);
    if (ret)
	goto failed;

    ret = kadm5_log_postamble (log_context, sp);
    if (ret)
	goto failed;

    ret = kadm5_log_flush (log_context, sp);
    if (ret)
	goto failed;
    krb5_storage_free (sp);
    krb5_data_free (&value);

    return kadm5_log_end (context);

failed:
    krb5_data_free(&value);
    krb5_storage_free(sp);
    return ret;
}
int
main(int argc, char **argv)
{
    krb5_error_code ret;
    krb5_context context;
    void *kadm_handle;
    kadm5_server_context *server_context;
    kadm5_config_params conf;
    krb5_socket_t signal_fd, listen_fd;
    int log_fd;
    slave *slaves = NULL;
    uint32_t current_version = 0, old_version = 0;
    uint32_t current_tstamp = 0;
    krb5_keytab keytab;
    char **files;
    int aret;
    int optidx = 0;
    int restarter_fd = -1;
    struct stat st;

    setprogname(argv[0]);

    if (getarg(args, num_args, argc, argv, &optidx))
        krb5_std_usage(1, args, num_args);

    if (help_flag)
	krb5_std_usage(0, args, num_args);

    if (version_flag) {
	print_version(NULL);
	exit(0);
    }

    if (detach_from_console && daemon_child == -1)
        roken_detach_prep(argc, argv, "--daemon-child");
    rk_pidfile(NULL);

    ret = krb5_init_context(&context);
    if (ret)
        errx(1, "krb5_init_context failed: %d", ret);

    setup_signal();

    if (config_file == NULL) {
	aret = asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context));
	if (aret == -1 || config_file == NULL)
	    errx(1, "out of memory");
    }

    ret = krb5_prepend_config_files_default(config_file, &files);
    if (ret)
	krb5_err(context, 1, ret, "getting configuration files");

    ret = krb5_set_config_files(context, files);
    krb5_free_config_files(files);
    if (ret)
	krb5_err(context, 1, ret, "reading configuration files");

    time_before_gone = parse_time (slave_time_gone,  "s");
    if (time_before_gone < 0)
	krb5_errx (context, 1, "couldn't parse time: %s", slave_time_gone);
    time_before_missing = parse_time (slave_time_missing,  "s");
    if (time_before_missing < 0)
	krb5_errx (context, 1, "couldn't parse time: %s", slave_time_missing);

    krb5_openlog(context, "ipropd-master", &log_facility);
    krb5_set_warn_dest(context, log_facility);

    ret = krb5_kt_register(context, &hdb_get_kt_ops);
    if(ret)
	krb5_err(context, 1, ret, "krb5_kt_register");

    ret = krb5_kt_resolve(context, keytab_str, &keytab);
    if(ret)
	krb5_err(context, 1, ret, "krb5_kt_resolve: %s", keytab_str);

    memset(&conf, 0, sizeof(conf));
    if(realm) {
	conf.mask |= KADM5_CONFIG_REALM;
	conf.realm = realm;
    }
    ret = kadm5_init_with_skey_ctx (context,
				    KADM5_ADMIN_SERVICE,
				    NULL,
				    KADM5_ADMIN_SERVICE,
				    &conf, 0, 0,
				    &kadm_handle);
    if (ret)
	krb5_err (context, 1, ret, "kadm5_init_with_password_ctx");

    server_context = (kadm5_server_context *)kadm_handle;

    log_fd = open (server_context->log_context.log_file, O_RDONLY, 0);
    if (log_fd < 0)
	krb5_err (context, 1, errno, "open %s",
		  server_context->log_context.log_file);

    if (fstat(log_fd, &st) == -1)
        krb5_err(context, 1, errno, "stat %s",
                 server_context->log_context.log_file);

    if (flock(log_fd, LOCK_SH) == -1)
        krb5_err(context, 1, errno, "shared flock %s",
                 server_context->log_context.log_file);
    kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST,
                             &current_version, &current_tstamp);
    flock(log_fd, LOCK_UN);

    signal_fd = make_signal_socket (context);
    listen_fd = make_listen_socket (context, port_str);

    krb5_warnx(context, "ipropd-master started at version: %lu",
	       (unsigned long)current_version);

    roken_detach_finish(NULL, daemon_child);
    restarter_fd = restarter(context, NULL);

    while (exit_flag == 0){
	slave *p;
	fd_set readset;
	int max_fd = 0;
	struct timeval to = {30, 0};
	uint32_t vers;
        struct stat st2;;

#ifndef NO_LIMIT_FD_SETSIZE
	if (signal_fd >= FD_SETSIZE || listen_fd >= FD_SETSIZE ||
            restarter_fd >= FD_SETSIZE)
	    krb5_errx (context, IPROPD_RESTART, "fd too large");
#endif

	FD_ZERO(&readset);
	FD_SET(signal_fd, &readset);
	max_fd = max(max_fd, signal_fd);
	FD_SET(listen_fd, &readset);
	max_fd = max(max_fd, listen_fd);
        if (restarter_fd > -1) {
            FD_SET(restarter_fd, &readset);
            max_fd = max(max_fd, restarter_fd);
        }

	for (p = slaves; p != NULL; p = p->next) {
	    if (p->flags & SLAVE_F_DEAD)
		continue;
	    FD_SET(p->fd, &readset);
	    max_fd = max(max_fd, p->fd);
	}

	ret = select (max_fd + 1,
		      &readset, NULL, NULL, &to);
	if (ret < 0) {
	    if (errno == EINTR)
		continue;
	    else
		krb5_err (context, IPROPD_RESTART, errno, "select");
	}

        if (stat(server_context->log_context.log_file, &st2) == -1) {
            krb5_warn(context, errno, "could not stat log file by path");
            st2 = st;
        }

        if (st2.st_dev != st.st_dev || st2.st_ino != st.st_ino) {
            (void) close(log_fd);

            log_fd = open(server_context->log_context.log_file, O_RDONLY, 0);
            if (log_fd < 0)
                krb5_err(context, 1, IPROPD_RESTART_SLOW, "open %s",
                          server_context->log_context.log_file);

            if (fstat(log_fd, &st) == -1)
                krb5_err(context, IPROPD_RESTART_SLOW, errno, "stat %s",
                         server_context->log_context.log_file);

            if (flock(log_fd, LOCK_SH) == -1)
                krb5_err(context, IPROPD_RESTART, errno, "shared flock %s",
                         server_context->log_context.log_file);
            kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST,
                                     &current_version, &current_tstamp);
            flock(log_fd, LOCK_UN);
        }

	if (ret == 0) {
            /* Recover from failed transactions */
            if (kadm5_log_init_nb(server_context) == 0)
                kadm5_log_end(server_context);

	    if (flock(log_fd, LOCK_SH) == -1)
                krb5_err(context, IPROPD_RESTART, errno,
                         "could not lock log file");
	    kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST,
                                     &current_version, &current_tstamp);
	    flock(log_fd, LOCK_UN);

	    if (current_version > old_version) {
		krb5_warnx(context,
			   "Missed a signal, updating slaves %lu to %lu",
			   (unsigned long)old_version,
			   (unsigned long)current_version);
		for (p = slaves; p != NULL; p = p->next) {
		    if (p->flags & SLAVE_F_DEAD)
			continue;
		    send_diffs (server_context, p, log_fd, database,
                                current_version, current_tstamp);
		}
                old_version = current_version;
	    }
	}

        if (ret && FD_ISSET(restarter_fd, &readset)) {
            exit_flag = SIGTERM;
            break;
        }

	if (ret && FD_ISSET(signal_fd, &readset)) {
#ifndef NO_UNIX_SOCKETS
	    struct sockaddr_un peer_addr;
#else
	    struct sockaddr_storage peer_addr;
#endif
	    socklen_t peer_len = sizeof(peer_addr);

	    if(recvfrom(signal_fd, (void *)&vers, sizeof(vers), 0,
			(struct sockaddr *)&peer_addr, &peer_len) < 0) {
		krb5_warn (context, errno, "recvfrom");
		continue;
	    }
	    --ret;
	    assert(ret >= 0);
	    old_version = current_version;
	    if (flock(log_fd, LOCK_SH) == -1)
                krb5_err(context, IPROPD_RESTART, errno, "shared flock %s",
                         server_context->log_context.log_file);
	    kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_LAST,
                                     &current_version, &current_tstamp);
	    flock(log_fd, LOCK_UN);
	    if (current_version != old_version) {
                /*
                 * If current_version < old_version then the log got
                 * truncated and we'll end up doing full propagations.
                 *
                 * Truncating the log when the current version is
                 * numerically small can lead to race conditions.
                 * Ideally we should identify log versions as
                 * {init_or_trunc_time, vno}, then we could not have any
                 * such race conditions, but this would either require
                 * breaking backwards compatibility for the protocol or
                 * adding new messages to it.
                 */
		krb5_warnx(context,
			   "Got a signal, updating slaves %lu to %lu",
			   (unsigned long)old_version,
			   (unsigned long)current_version);
		for (p = slaves; p != NULL; p = p->next) {
		    if (p->flags & SLAVE_F_DEAD)
			continue;
		    send_diffs (server_context, p, log_fd, database,
                                current_version, current_tstamp);
		}
	    } else {
		krb5_warnx(context,
			   "Got a signal, but no update in log version %lu",
			   (unsigned long)current_version);
	    }
        }

	for(p = slaves; p != NULL; p = p->next) {
	    if (p->flags & SLAVE_F_DEAD)
	        continue;
	    if (ret && FD_ISSET(p->fd, &readset)) {
		--ret;
		assert(ret >= 0);
		if(process_msg (server_context, p, log_fd, database,
				current_version, current_tstamp))
		    slave_dead(context, p);
	    } else if (slave_gone_p (p))
		slave_dead(context, p);
	    else if (slave_missing_p (p))
		send_are_you_there (context, p);
	}

	if (ret && FD_ISSET(listen_fd, &readset)) {
	    add_slave (context, keytab, &slaves, listen_fd);
	    --ret;
	    assert(ret >= 0);
	}
	write_stats(context, slaves, current_version);
    }

    if(exit_flag == SIGINT || exit_flag == SIGTERM)
	krb5_warnx(context, "%s terminated", getprogname());
#ifdef SIGXCPU
    else if(exit_flag == SIGXCPU)
	krb5_warnx(context, "%s CPU time limit exceeded", getprogname());
#endif
    else
	krb5_warnx(context, "%s unexpected exit reason: %ld",
		   getprogname(), (long)exit_flag);

    write_master_down(context);

    return 0;
}
Exemple #12
0
/**
 * Server-side function to set new keys for a principal.
 */
kadm5_ret_t
kadm5_s_setkey_principal_3(void *server_handle,
			   krb5_principal princ,
			   krb5_boolean keepold,
			   int n_ks_tuple,
			   krb5_key_salt_tuple *ks_tuple,
			   krb5_keyblock *keyblocks, int n_keys)
{
    kadm5_server_context *context = server_handle;
    hdb_entry_ex ent;
    kadm5_ret_t ret = 0;

    memset(&ent, 0, sizeof(ent));
    if (!context->keep_open)
	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
    if (ret)
	return ret;

    ret = kadm5_log_init(context);
    if (ret) {
        if (!context->keep_open)
            context->db->hdb_close(context->context, context->db);
        return ret;
    }

    ret = context->db->hdb_fetch_kvno(context->context, context->db, princ,
				      HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
    if (ret) {
        (void) kadm5_log_end(context);
        if (!context->keep_open)
            context->db->hdb_close(context->context, context->db);
        return ret;
    }

    if (keepold) {
        ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
    } else
	ret = hdb_clear_extension(context->context, &ent.entry,
				  choice_HDB_extension_data_hist_keys);

    /*
     * Though in practice all real calls to this function will pass an empty
     * ks_tuple, and cannot in any case employ any salts that require
     * additional data, we go the extra mile to set any requested salt type
     * along with a zero length salt value.  While we're at it we check that
     * each ks_tuple's enctype matches the corresponding key enctype.
     */
    if (ret == 0) {
	int i;

	free_Keys(&ent.entry.keys);
	for (i = 0; i < n_keys; ++i) {
	    Key k;
	    Salt s;

	    k.mkvno = 0;
	    k.key = keyblocks[i];
	    if (n_ks_tuple == 0)
		k.salt = 0;
	    else {
		if (ks_tuple[i].ks_enctype != keyblocks[i].keytype) {
		    ret = KADM5_SETKEY3_ETYPE_MISMATCH;
		    break;
		}
		s.type = ks_tuple[i].ks_salttype;
		s.salt.data = 0;
		s.opaque = 0;
		k.salt = &s;
	    }
	    if ((ret = add_Keys(&ent.entry.keys, &k)) != 0)
		break;
	}
    }

    if (ret == 0) {
	ent.entry.kvno++;
	ent.entry.flags.require_pwchange = 0;
	hdb_entry_set_pw_change_time(context->context, &ent.entry, 0);
	hdb_entry_clear_password(context->context, &ent.entry);

	if ((ret = hdb_seal_keys(context->context, context->db,
				 &ent.entry)) == 0
	    && (ret = _kadm5_set_modifier(context, &ent.entry)) == 0
	    && (ret = _kadm5_bump_pw_expire(context, &ent.entry)) == 0)
	    ret = kadm5_log_modify(context, &ent.entry,
                                   KADM5_ATTRIBUTES | KADM5_PRINCIPAL |
                                   KADM5_MOD_NAME | KADM5_MOD_TIME |
                                   KADM5_KEY_DATA | KADM5_KVNO |
                                   KADM5_PW_EXPIRATION | KADM5_TL_DATA);
    }

    hdb_free_entry(context->context, &ent);
    (void) kadm5_log_end(context);
    if (!context->keep_open)
	context->db->hdb_close(context->context, context->db);
    return _kadm5_error_code(ret);
}
Exemple #13
0
static kadm5_ret_t
change(void *server_handle,
       krb5_principal princ,
       int keepold,
       int n_ks_tuple,
       krb5_key_salt_tuple *ks_tuple,
       const char *password,
       int cond)
{
    kadm5_server_context *context = server_handle;
    hdb_entry_ex ent;
    kadm5_ret_t ret;
    Key *keys;
    size_t num_keys;
    int existsp = 0;

    memset(&ent, 0, sizeof(ent));
    if (!context->keep_open) {
	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
	if(ret)
	    return ret;
    }

    ret = kadm5_log_init(context);
    if (ret)
        goto out;

    ret = context->db->hdb_fetch_kvno(context->context, context->db, princ,
				      HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
    if (ret)
	goto out2;

    if (keepold || cond) {
	/*
	 * We save these for now so we can handle password history checking;
	 * we handle keepold further below.
	 */
	ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
	if (ret)
	    goto out3;
    }

    if (context->db->hdb_capability_flags & HDB_CAP_F_HANDLE_PASSWORDS) {
	ret = context->db->hdb_password(context->context, context->db,
					&ent, password, cond);
	if (ret)
	    goto out3;
    } else {

	num_keys = ent.entry.keys.len;
	keys     = ent.entry.keys.val;

	ent.entry.keys.len = 0;
	ent.entry.keys.val = NULL;

	ret = _kadm5_set_keys(context, &ent.entry, n_ks_tuple, ks_tuple,
			      password);
	if(ret) {
	    _kadm5_free_keys(context->context, num_keys, keys);
	    goto out3;
	}
	_kadm5_free_keys(context->context, num_keys, keys);

	if (cond) {
	    HDB_extension *ext;

	    ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_hist_keys);
	    if (ext != NULL)
		existsp = _kadm5_exists_keys_hist(ent.entry.keys.val,
						  ent.entry.keys.len,
						  &ext->data.u.hist_keys);
	}

	if (existsp) {
	    ret = KADM5_PASS_REUSE;
	    krb5_set_error_message(context->context, ret,
				   "Password reuse forbidden");
	    goto out3;
	}
    }
    ent.entry.kvno++;

    ent.entry.flags.require_pwchange = 0;

    if (!keepold) {
	HDB_extension ext;

	memset(&ext, 0, sizeof (ext));
        ext.mandatory = FALSE;
	ext.data.element = choice_HDB_extension_data_hist_keys;
	ret = hdb_replace_extension(context->context, &ent.entry, &ext);
	if (ret)
	    goto out3;
    }

    ret = hdb_seal_keys(context->context, context->db, &ent.entry);
    if (ret)
        goto out3;

    ret = _kadm5_set_modifier(context, &ent.entry);
    if(ret)
	goto out3;

    ret = _kadm5_bump_pw_expire(context, &ent.entry);
    if (ret)
	goto out3;

    /* This logs the change for iprop and writes to the HDB */
    ret = kadm5_log_modify(context, &ent.entry,
                           KADM5_ATTRIBUTES | KADM5_PRINCIPAL |
                           KADM5_MOD_NAME | KADM5_MOD_TIME |
                           KADM5_KEY_DATA | KADM5_KVNO |
                           KADM5_PW_EXPIRATION | KADM5_TL_DATA);

 out3:
    hdb_free_entry(context->context, &ent);
 out2:
    (void) kadm5_log_end(context);
 out:
    if (!context->keep_open) {
        kadm5_ret_t ret2;
        ret2 = context->db->hdb_close(context->context, context->db);
        if (ret == 0 && ret2 != 0)
            ret = ret2;
    }
    return _kadm5_error_code(ret);
}
Exemple #14
0
kadm5_ret_t
kadm5_s_chpass_principal_with_key(void *server_handle,
				  krb5_principal princ,
				  int keepold,
				  int n_key_data,
				  krb5_key_data *key_data)
{
    kadm5_server_context *context = server_handle;
    hdb_entry_ex ent;
    kadm5_ret_t ret;

    memset(&ent, 0, sizeof(ent));
    if (!context->keep_open) {
	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
	if(ret)
	    return ret;
    }

    ret = kadm5_log_init(context);
    if (ret)
        goto out;

    ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, 0,
				      HDB_F_GET_ANY|HDB_F_ADMIN_DATA, &ent);
    if (ret == HDB_ERR_NOENTRY)
	goto out2;
    if (keepold) {
	ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
	if (ret)
	    goto out3;
    }
    ret = _kadm5_set_keys2(context, &ent.entry, n_key_data, key_data);
    if (ret)
	goto out3;
    ent.entry.kvno++;
    ret = _kadm5_set_modifier(context, &ent.entry);
    if (ret)
	goto out3;
    ret = _kadm5_bump_pw_expire(context, &ent.entry);
    if (ret)
	goto out3;

    if (keepold) {
	ret = hdb_seal_keys(context->context, context->db, &ent.entry);
	if (ret)
	    goto out3;
    } else {
	HDB_extension ext;

	memset(&ext, 0, sizeof (ext));
	ext.mandatory = FALSE;
	ext.data.element = choice_HDB_extension_data_hist_keys;
	ext.data.u.hist_keys.len = 0;
	ext.data.u.hist_keys.val = NULL;
	hdb_replace_extension(context->context, &ent.entry, &ext);
    }

    /* This logs the change for iprop and writes to the HDB */
    ret = kadm5_log_modify(context, &ent.entry,
                           KADM5_PRINCIPAL | KADM5_MOD_NAME |
                           KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO |
                           KADM5_PW_EXPIRATION | KADM5_TL_DATA);

 out3:
    hdb_free_entry(context->context, &ent);
 out2:
    (void) kadm5_log_end(context);
 out:
    if (!context->keep_open) {
        kadm5_ret_t ret2;
        ret2 = context->db->hdb_close(context->context, context->db);
        if (ret == 0 && ret2 != 0)
            ret = ret2;
    }
    return _kadm5_error_code(ret);
}
Exemple #15
0
static int
append_to_log_file(krb5_context context,
                   kadm5_server_context *server_context,
                   krb5_storage *sp, off_t start, ssize_t slen)
{
    size_t len;
    ssize_t sret;
    off_t log_off;
    int ret, ret2;
    void *buf;

    if (verbose)
        krb5_warnx(context, "appending diffs to log");

    if (slen == 0)
        return 0;
    if (slen < 0)
        return EINVAL;
    len = slen;
    if (len != slen)
        return EOVERFLOW;

    buf = malloc(len);
    if (buf == NULL && len != 0) {
        krb5_warn(context, errno, "malloc: no memory");
        return ENOMEM;
    }

    if (krb5_storage_seek(sp, start, SEEK_SET) != start) {
        krb5_errx(context, IPROPD_RESTART,
                  "krb5_storage_seek() failed"); /* can't happen */
    }
    sret = krb5_storage_read(sp, buf, len);
    if (sret < 0)
        return errno;
    if (len != (size_t)sret) {
        /* Can't happen */
        krb5_errx(context, IPROPD_RESTART,
                  "short krb5_storage_read() from memory buffer");
    }
    log_off = lseek(server_context->log_context.log_fd, 0, SEEK_CUR);
    if (log_off == -1)
        return errno;

    /*
     * Use net_write() so we get an errno if less that len bytes were
     * written.
     */
    sret = net_write(server_context->log_context.log_fd, buf, len);
    free(buf);
    if (sret != slen)
        ret = errno;
    else
        ret = fsync(server_context->log_context.log_fd);
    if (ret == 0)
        return 0;

    /*
     * Attempt to recover from this.  First, truncate the log file
     * and reset the fd offset.  Failure to do this -> unlink the
     * log file and re-create it.  Since we're the slave, we ought to be
     * able to recover from the log being unlinked...
     */
    if (ftruncate(server_context->log_context.log_fd, log_off) == -1 ||
        lseek(server_context->log_context.log_fd, log_off, SEEK_SET) == -1) {
        (void) kadm5_log_end(server_context);
        if (unlink(server_context->log_context.log_file) == -1) {
            krb5_err(context, IPROPD_FATAL, errno,
                     "Failed to recover from failure to write log "
                     "entries from master to disk");
        }
        ret2 = kadm5_log_init(server_context);
        if (ret2) {
            krb5_err(context, IPROPD_RESTART_SLOW, ret2,
                     "Failed to initialize log to recover from "
                     "failure to write log entries from master to disk");
        }
    }
    if (ret == ENOSPC || ret == EDQUOT || ret == EFBIG) {
        /* Unlink the file in these cases. */
        krb5_warn(context, IPROPD_RESTART_SLOW,
                  "Failed to write log entries from master to disk");
        (void) kadm5_log_end(server_context);
        if (unlink(server_context->log_context.log_file) == -1) {
            krb5_err(context, IPROPD_FATAL, errno,
                     "Failed to recover from failure to write log "
                     "entries from master to disk");
        }
        ret2 = kadm5_log_init(server_context);
        if (ret2) {
            krb5_err(context, IPROPD_RESTART_SLOW, ret2,
                     "Failed to initialize log to recover from "
                     "failure to write log entries from master to disk");
        }
        return ret;
    }
    /*
     * All other errors we treat as fatal here.  This includes, for
     * example, EIO and EPIPE (sorry, can't log to pipes nor sockets).
     */
    krb5_err(context, IPROPD_FATAL, ret,
             "Failed to write log entries from master to disk");
}
Exemple #16
0
kadm5_ret_t
kadm5_s_rename_principal(void *server_handle,
			 krb5_principal source,
			 krb5_principal target)
{
    kadm5_server_context *context = server_handle;
    kadm5_ret_t ret;
    hdb_entry_ex ent;
    krb5_principal oldname;

    memset(&ent, 0, sizeof(ent));
    if (krb5_principal_compare(context->context, source, target))
	return KADM5_DUP; /* XXX is this right? */
    if (!context->keep_open) {
	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
	if(ret)
	    return ret;
    }

    ret = kadm5_log_init(context);
    if (ret)
        goto out;

    ret = context->db->hdb_fetch_kvno(context->context, context->db,
				      source, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
    if (ret)
	goto out2;
    oldname = ent.entry.principal;
    ret = _kadm5_set_modifier(context, &ent.entry);
    if (ret)
	goto out3;
    {
	/* fix salt */
	size_t i;
	Salt salt;
	krb5_salt salt2;
	memset(&salt, 0, sizeof(salt));
	krb5_get_pw_salt(context->context, source, &salt2);
	salt.type = hdb_pw_salt;
	salt.salt = salt2.saltvalue;
	for(i = 0; i < ent.entry.keys.len; i++){
	    if(ent.entry.keys.val[i].salt == NULL){
		ent.entry.keys.val[i].salt =
		    malloc(sizeof(*ent.entry.keys.val[i].salt));
		if (ent.entry.keys.val[i].salt == NULL)
		    ret = ENOMEM;
                else
                    ret = copy_Salt(&salt, ent.entry.keys.val[i].salt);
		if (ret)
		    break;
	    }
	}
	krb5_free_salt(context->context, salt2);
    }
    if (ret)
	goto out3;

    /* Borrow target */
    ent.entry.principal = target;
    ret = hdb_seal_keys(context->context, context->db, &ent.entry);
    if (ret)
	goto out3;

    /* This logs the change for iprop and writes to the HDB */
    ret = kadm5_log_rename(context, source, &ent.entry);

 out3:
    ent.entry.principal = oldname; /* Unborrow target */
    hdb_free_entry(context->context, &ent);

 out2:
    (void) kadm5_log_end(context);
 out:
    if (!context->keep_open) {
        kadm5_ret_t ret2;
        ret2 = context->db->hdb_close(context->context, context->db);
        if (ret == 0 && ret2 != 0)
            ret = ret2;
    }
    return _kadm5_error_code(ret);
}
Exemple #17
0
static kadm5_ret_t
modify_principal(void *server_handle,
		 kadm5_principal_ent_t princ,
		 uint32_t mask,
		 uint32_t forbidden_mask)
{
    kadm5_server_context *context = server_handle;
    hdb_entry_ex ent;
    kadm5_ret_t ret;

    memset(&ent, 0, sizeof(ent));

    if((mask & forbidden_mask))
	return KADM5_BAD_MASK;
    if((mask & KADM5_POLICY) && strcmp(princ->policy, "default"))
	return KADM5_UNK_POLICY;

    if (!context->keep_open) {
	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
	if(ret)
	    return ret;
    }

    ret = kadm5_log_init(context);
    if (ret)
        goto out;

    ret = context->db->hdb_fetch_kvno(context->context, context->db,
				      princ->principal, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
    if(ret)
	goto out;
    ret = _kadm5_setup_entry(context, &ent, mask, princ, mask, NULL, 0);
    if(ret)
	goto out2;
    ret = _kadm5_set_modifier(context, &ent.entry);
    if(ret)
	goto out2;

    /*
     * If any keys are bogus, disallow the modify.  If the keys were
     * bogus as stored in the HDB we could allow those through, but
     * distinguishing that case from a pre-1.6 client using add_enctype
     * without the get-keys privilege requires more work (mainly: checking that
     * the bogus keys in princ->key_data[] have corresponding bogus keys in ent
     * before calling _kadm5_setup_entry()).
     */
    if ((mask & KADM5_KEY_DATA) &&
	kadm5_some_keys_are_bogus(princ->n_key_data, princ->key_data)) {
	ret = KADM5_AUTH_GET_KEYS; /* Not quite appropriate, but it'll do */
	goto out2;
    }

    ret = hdb_seal_keys(context->context, context->db, &ent.entry);
    if (ret)
	goto out2;

    if ((mask & KADM5_POLICY)) {
	HDB_extension ext;

        memset(&ext, 0, sizeof(ext));
        /* XXX should be TRUE, but we don't yet support policies */
        ext.mandatory = FALSE;
	ext.data.element = choice_HDB_extension_data_policy;
	ext.data.u.policy = strdup(princ->policy);
	if (ext.data.u.policy == NULL) {
	    ret = ENOMEM;
	    goto out2;
	}
	/* This calls free_HDB_extension(), freeing ext.data.u.policy */
	ret = hdb_replace_extension(context->context, &ent.entry, &ext);
        free(ext.data.u.policy);
	if (ret)
	    goto out2;
    }

    /* This logs the change for iprop and writes to the HDB */
    ret = kadm5_log_modify(context, &ent.entry,
                           mask | KADM5_MOD_NAME | KADM5_MOD_TIME);

out2:
    hdb_free_entry(context->context, &ent);
out:
    (void) kadm5_log_end(context);
    if (!context->keep_open) {
        kadm5_ret_t ret2;
        ret2 = context->db->hdb_close(context->context, context->db);
        if (ret == 0 && ret2 != 0)
            ret = ret2;
    }
    return _kadm5_error_code(ret);
}
Exemple #18
0
static int
doit(const char *filename, int mergep)
{
    krb5_error_code ret = 0;
    FILE *f;
    char s[8192]; /* XXX should fix this properly */
    char *p;
    int line;
    int flags = O_RDWR;
    struct entry e;
    hdb_entry_ex ent;
    HDB *db = _kadm5_s_get_db(kadm_handle);

    f = fopen(filename, "r");
    if(f == NULL){
	krb5_warn(context, errno, "fopen(%s)", filename);
	return 1;
    }
    /*
     * We don't have a version number in the dump, so we don't know which iprop
     * log entries to keep, if any.  We throw the log away.
     *
     * We could merge the ipropd-master/slave dump/load here as an option, in
     * which case we would first load the dump.
     *
     * If we're merging, first recover unconfirmed records in the existing log.
     */
    if (mergep)
        ret = kadm5_log_init(kadm_handle);
    if (ret == 0)
        ret = kadm5_log_reinit(kadm_handle, 0);
    if (ret) {
	fclose (f);
	krb5_warn(context, ret, "kadm5_log_reinit");
	return 1;
    }

    if(!mergep)
	flags |= O_CREAT | O_TRUNC;
    ret = db->hdb_open(context, db, flags, 0600);
    if(ret){
	krb5_warn(context, ret, "hdb_open");
	fclose(f);
	return 1;
    }
    line = 0;
    ret = 0;
    while(fgets(s, sizeof(s), f) != NULL) {
	line++;

	p = s;
	while (isspace((unsigned char)*p))
	    p++;

	e.principal = p;
	for(p = s; *p; p++){
	    if(*p == '\\')
		p++;
	    else if(isspace((unsigned char)*p)) {
		*p = 0;
		break;
	    }
	}
	p = skip_next(p);

	e.key = p;
	p = skip_next(p);

	e.created = p;
	p = skip_next(p);

	e.modified = p;
	p = skip_next(p);

	e.valid_start = p;
	p = skip_next(p);

	e.valid_end = p;
	p = skip_next(p);

	e.pw_end = p;
	p = skip_next(p);

	e.max_life = p;
	p = skip_next(p);

	e.max_renew = p;
	p = skip_next(p);

	e.flags = p;
	p = skip_next(p);

	e.generation = p;
	p = skip_next(p);

	e.extensions = p;
	skip_next(p);

	memset(&ent, 0, sizeof(ent));
	ret = krb5_parse_name(context, e.principal, &ent.entry.principal);
	if(ret) {
	    const char *msg = krb5_get_error_message(context, ret);
	    fprintf(stderr, "%s:%d:%s (%s)\n",
		    filename, line, msg, e.principal);
	    krb5_free_error_message(context, msg);
	    continue;
	}

	if (parse_keys(&ent.entry, e.key)) {
	    fprintf (stderr, "%s:%d:error parsing keys (%s)\n",
		     filename, line, e.key);
	    hdb_free_entry (context, &ent);
	    continue;
	}

	if (parse_event(&ent.entry.created_by, e.created) == -1) {
	    fprintf (stderr, "%s:%d:error parsing created event (%s)\n",
		     filename, line, e.created);
	    hdb_free_entry (context, &ent);
	    continue;
	}
	if (parse_event_alloc (&ent.entry.modified_by, e.modified) == -1) {
	    fprintf (stderr, "%s:%d:error parsing event (%s)\n",
		     filename, line, e.modified);
	    hdb_free_entry (context, &ent);
	    continue;
	}
	if (parse_time_string_alloc (&ent.entry.valid_start, e.valid_start) == -1) {
	    fprintf (stderr, "%s:%d:error parsing time (%s)\n",
		     filename, line, e.valid_start);
	    hdb_free_entry (context, &ent);
	    continue;
	}
	if (parse_time_string_alloc (&ent.entry.valid_end,   e.valid_end) == -1) {
	    fprintf (stderr, "%s:%d:error parsing time (%s)\n",
		     filename, line, e.valid_end);
	    hdb_free_entry (context, &ent);
	    continue;
	}
	if (parse_time_string_alloc (&ent.entry.pw_end,      e.pw_end) == -1) {
	    fprintf (stderr, "%s:%d:error parsing time (%s)\n",
		     filename, line, e.pw_end);
	    hdb_free_entry (context, &ent);
	    continue;
	}

	if (parse_integer_alloc (&ent.entry.max_life,  e.max_life) == -1) {
	    fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n",
		     filename, line, e.max_life);
	    hdb_free_entry (context, &ent);
	    continue;

	}
	if (parse_integer_alloc (&ent.entry.max_renew, e.max_renew) == -1) {
	    fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n",
		     filename, line, e.max_renew);
	    hdb_free_entry (context, &ent);
	    continue;
	}

	if (parse_hdbflags2int (&ent.entry.flags, e.flags) != 1) {
	    fprintf (stderr, "%s:%d:error parsing flags (%s)\n",
		     filename, line, e.flags);
	    hdb_free_entry (context, &ent);
	    continue;
	}

	if(parse_generation(e.generation, &ent.entry.generation) == -1) {
	    fprintf (stderr, "%s:%d:error parsing generation (%s)\n",
		     filename, line, e.generation);
	    hdb_free_entry (context, &ent);
	    continue;
	}

	if(parse_extensions(e.extensions, &ent.entry.extensions) == -1) {
	    fprintf (stderr, "%s:%d:error parsing extension (%s)\n",
		     filename, line, e.extensions);
	    hdb_free_entry (context, &ent);
	    continue;
	}

	ret = db->hdb_store(context, db, HDB_F_REPLACE, &ent);
	hdb_free_entry (context, &ent);
	if (ret) {
	    krb5_warn(context, ret, "db_store");
	    break;
	}
    }
    (void) kadm5_log_end(kadm_handle);
    db->hdb_close(context, db);
    fclose(f);
    return ret != 0;
}