예제 #1
0
/*
 * Function: kadm5_create
 *
 * Purpose: create admin principals in KDC database
 *
 * Arguments:	params	(r) configuration parameters to use
 *      
 * Effects:  Creates KADM5_ADMIN_SERVICE and KADM5_CHANGEPW_SERVICE
 * principals in the KDC database and sets their attributes
 * appropriately.
 */
int kadm5_create(kadm5_config_params *params)
{
     int retval;
     krb5_context context;

     kadm5_config_params lparams;

     if ((retval = kadm5_init_krb5_context(&context)))
	  exit(ERR);

     /*
      * The lock file has to exist before calling kadm5_init, but
      * params->admin_lockfile may not be set yet...
      */
     if ((retval = kadm5_get_config_params(context, 1,
					   params, &lparams))) {
	  com_err(progname, retval, "while looking up the Kerberos configuration");
	  return 1;
     }

     retval = kadm5_create_magic_princs(&lparams, context);

     kadm5_free_config_params(context, &lparams);
     krb5_free_context(context);

     return retval;
}
예제 #2
0
int
main(int argc, char **argv)
{
	int			c;
	bool_t			verbose = FALSE;
	bool_t			headeronly = FALSE;
	uint32_t		entry = 0;
	krb5_context		context;
	kadm5_config_params	params;
	kdb_log_context		*log_ctx;
	kdb_hlog_t		*ulog = NULL;

	(void) setlocale(LC_ALL, "");

#if !defined(TEXT_DOMAIN)
#define	TEXT_DOMAIN "SYS_TEST"
#endif /* TEXT_DOMAIN */

	(void) textdomain(TEXT_DOMAIN);

	if (geteuid() != (uid_t)0) {
		(void) fprintf(stderr,
		    gettext("kproplog must be run as root\n\n"));
		exit(1);
	}

	progname = argv[0];

	while ((c = getopt(argc, argv, "vhe:")) != -1) {
		switch (c) {
			case 'h':
				headeronly = TRUE;
				break;
			case 'e':
				entry = atoi(optarg);
				break;
			case 'v':
				verbose = TRUE;
				break;
			default:
				usage();
		}
	}

	if (krb5_init_context(&context)) {
		(void) fprintf(stderr,
		    gettext("Unable to initialize Kerberos\n\n"));
		exit(1);
	}

	(void) memset((char *)&params, 0, sizeof (params));

	if (kadm5_get_config_params(context, NULL, NULL, &params, &params)) {
		(void) fprintf(stderr,
		    gettext("Couldn't read database_name\n\n"));
		exit(1);
	}

	(void) printf(gettext("\nKerberos update log (%s.ulog)\n"),
	    params.dbname);

	if (ulog_map(context, &params, FKPROPLOG)) {
		(void) fprintf(stderr, gettext("Unable to map log file "
		    "%s.ulog\n\n"), params.dbname);
		exit(1);
	}

	log_ctx = context->kdblog_context;
	if (log_ctx)
		ulog = log_ctx->ulog;
	else {
		(void) fprintf(stderr, gettext("Unable to map log file "
		    "%s.ulog\n\n"), params.dbname);
		exit(1);
	}

	if (ulog->kdb_hmagic != KDB_HMAGIC) {
		(void) fprintf(stderr,
		    gettext("Corrupt header log, exiting\n\n"));
		exit(1);
	}

	(void) printf(gettext("Update log dump :\n"));
	(void) printf(gettext("\tLog version # : %u\n"), ulog->db_version_num);
	(void) printf(gettext("\tLog state : "));
	switch (ulog->kdb_state) {
		case KDB_STABLE:
			(void) printf(gettext("Stable\n"));
			break;
		case KDB_UNSTABLE:
			(void) printf(gettext("Unstable\n"));
			break;
		case KDB_CORRUPT:
			(void) printf(gettext("Corrupt\n"));
			break;
		default:
			(void) printf(gettext("Unknown state: %d\n"),
			    ulog->kdb_state);
			break;
	}
	(void) printf(gettext("\tEntry block size : %u\n"), ulog->kdb_block);
	(void) printf(gettext("\tNumber of entries : %u\n"), ulog->kdb_num);

	if (ulog->kdb_last_sno == 0)
		(void) printf(gettext("\tLast serial # : None\n"));
	else {
		if (ulog->kdb_first_sno == 0)
			(void) printf(gettext("\tFirst serial # : None\n"));
		else {
			(void) printf(gettext("\tFirst serial # : "));
			(void) printf("%u\n", ulog->kdb_first_sno);
		}

		(void) printf(gettext("\tLast serial # : "));
		(void) printf("%u\n", ulog->kdb_last_sno);
	}

	if (ulog->kdb_last_time.seconds == 0L) {
		(void) printf(gettext("\tLast time stamp : None\n"));
	} else {
		if (ulog->kdb_first_time.seconds == 0L)
			(void) printf(gettext("\tFirst time stamp : None\n"));
		else {
			(void) printf(gettext("\tFirst time stamp : %s"),
			    ctime((time_t *)
			    &(ulog->kdb_first_time.seconds)));
		}

		(void) printf(gettext("\tLast time stamp : %s\n"),
		    ctime((time_t *)&(ulog->kdb_last_time.seconds)));
	}

	if ((!headeronly) && ulog->kdb_num) {
		print_update(ulog, entry, verbose);
	}

	(void) printf("\n");

	return (0);
}
예제 #3
0
파일: client_init.c 프로젝트: aacero/krb5
static kadm5_ret_t
init_any(krb5_context context, char *client_name, enum init_type init_type,
         char *pass, krb5_ccache ccache_in, char *service_name,
         kadm5_config_params *params_in, krb5_ui_4 struct_version,
         krb5_ui_4 api_version, char **db_args, void **server_handle)
{
    int fd = -1;

    krb5_boolean iprop_enable;
    int port;
    rpcprog_t rpc_prog;
    rpcvers_t rpc_vers;
    krb5_ccache ccache;
    krb5_principal client = NULL, server = NULL;

    kadm5_server_handle_t handle;
    kadm5_config_params params_local;

    int code = 0;
    generic_ret *r;

    initialize_ovk_error_table();
/*      initialize_adb_error_table(); */
    initialize_ovku_error_table();

    if (! server_handle) {
        return EINVAL;
    }

    if (! (handle = malloc(sizeof(*handle)))) {
        return ENOMEM;
    }
    memset(handle, 0, sizeof(*handle));
    if (! (handle->lhandle = malloc(sizeof(*handle)))) {
        free(handle);
        return ENOMEM;
    }

    handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
    handle->struct_version = struct_version;
    handle->api_version = api_version;
    handle->clnt = 0;
    handle->client_socket = -1;
    handle->cache_name = 0;
    handle->destroy_cache = 0;
    handle->context = 0;
    *handle->lhandle = *handle;
    handle->lhandle->api_version = KADM5_API_VERSION_4;
    handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
    handle->lhandle->lhandle = handle->lhandle;

    handle->context = context;

    if(client_name == NULL) {
        free(handle);
        return EINVAL;
    }

    /*
     * Verify the version numbers before proceeding; we can't use
     * CHECK_HANDLE because not all fields are set yet.
     */
    GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION,
                         KADM5_NEW_LIB_API_VERSION);

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

    if ((code = kadm5_get_config_params(handle->context, 0,
                                        params_in, &handle->params))) {
        free(handle);
        return(code);
    }

#define REQUIRED_PARAMS (KADM5_CONFIG_REALM |           \
                         KADM5_CONFIG_ADMIN_SERVER |    \
                         KADM5_CONFIG_KADMIND_PORT)

    if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
        free(handle);
        return KADM5_MISSING_KRB5_CONF_PARAMS;
    }

    code = krb5_parse_name(handle->context, client_name, &client);
    if (code)
        goto error;

    /*
     * Get credentials.  Also does some fallbacks in case kadmin/fqdn
     * principal doesn't exist.
     */
    code = get_init_creds(handle, client, init_type, pass, ccache_in,
                          service_name, handle->params.realm, &server);
    if (code)
        goto error;

    /* If the service_name and client_name are iprop-centric, use the iprop
     * port and RPC identifiers. */
    iprop_enable = (service_name != NULL &&
                    strstr(service_name, KIPROP_SVC_NAME) != NULL &&
                    strstr(client_name, KIPROP_SVC_NAME) != NULL);
    if (iprop_enable) {
        port = handle->params.iprop_port;
        rpc_prog = KRB5_IPROP_PROG;
        rpc_vers = KRB5_IPROP_VERS;
    } else {
        port = handle->params.kadmind_port;
        rpc_prog = KADM;
        rpc_vers = KADMVERS;
    }

    code = connect_to_server(handle->params.admin_server, port, &fd);
    if (code)
        goto error;

    handle->clnt = clnttcp_create(NULL, rpc_prog, rpc_vers, &fd, 0, 0);
    if (handle->clnt == NULL) {
        code = KADM5_RPC_ERROR;
#ifdef DEBUG
        clnt_pcreateerror("clnttcp_create");
#endif
        goto error;
    }
    handle->client_socket = fd;
    handle->lhandle->clnt = handle->clnt;
    handle->lhandle->client_socket = fd;

    /* now that handle->clnt is set, we can check the handle */
    if ((code = _kadm5_check_handle((void *) handle)))
        goto error;

    /*
     * The RPC connection is open; establish the GSS-API
     * authentication context.
     */
    code = setup_gss(handle, params_in,
                     (init_type == INIT_CREDS) ? client : NULL, server);
    if (code)
        goto error;

    /*
     * Bypass the remainder of the code and return straightaway
     * if the gss service requested is kiprop
     */
    if (iprop_enable) {
        code = 0;
        *server_handle = (void *) handle;
        goto cleanup;
    }

    r = init_2(&handle->api_version, handle->clnt);
    if (r == NULL) {
        code = KADM5_RPC_ERROR;
#ifdef DEBUG
        clnt_perror(handle->clnt, "init_2 null resp");
#endif
        goto error;
    }
    /* Drop down to v3 wire protocol if server does not support v4 */
    if (r->code == KADM5_NEW_SERVER_API_VERSION &&
        handle->api_version == KADM5_API_VERSION_4) {
        handle->api_version = KADM5_API_VERSION_3;
        r = init_2(&handle->api_version, handle->clnt);
        if (r == NULL) {
            code = KADM5_RPC_ERROR;
            goto error;
        }
    }
    /* Drop down to v2 wire protocol if server does not support v3 */
    if (r->code == KADM5_NEW_SERVER_API_VERSION &&
        handle->api_version == KADM5_API_VERSION_3) {
        handle->api_version = KADM5_API_VERSION_2;
        r = init_2(&handle->api_version, handle->clnt);
        if (r == NULL) {
            code = KADM5_RPC_ERROR;
            goto error;
        }
    }
    if (r->code) {
        code = r->code;
        goto error;
    }

    *server_handle = (void *) handle;

    goto cleanup;

error:
    /*
     * Note that it is illegal for this code to execute if "handle"
     * has not been allocated and initialized.  I.e., don't use "goto
     * error" before the block of code at the top of the function
     * that allocates and initializes "handle".
     */
    if (handle->destroy_cache && handle->cache_name) {
        if (krb5_cc_resolve(handle->context,
                            handle->cache_name, &ccache) == 0)
            (void) krb5_cc_destroy (handle->context, ccache);
    }
    if (handle->cache_name)
        free(handle->cache_name);
    if(handle->clnt && handle->clnt->cl_auth)
        AUTH_DESTROY(handle->clnt->cl_auth);
    if(handle->clnt)
        clnt_destroy(handle->clnt);
    if (fd != -1)
        close(fd);

    kadm5_free_config_params(handle->context, &handle->params);

cleanup:
    krb5_free_principal(handle->context, client);
    krb5_free_principal(handle->context, server);
    if (code)
        free(handle);

    return code;
}
예제 #4
0
파일: ovsec_kadmd.c 프로젝트: wfiveash/krb5
int
main(int argc, char *argv[])
{
    OM_uint32 minor_status;
    gss_buffer_desc in_buf;
    gss_OID nt_krb5_name_oid = (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME;
    auth_gssapi_name names[4];
    kadm5_config_params params;
    verto_ctx *vctx;
    const char *pid_file = NULL;
    char **db_args = NULL, **tmpargs;
    int ret, i, db_args_size = 0, strong_random = 1, proponly = 0;

    setlocale(LC_ALL, "");
    setvbuf(stderr, NULL, _IONBF, 0);

    names[0].name = names[1].name = names[2].name = names[3].name = NULL;
    names[0].type = names[1].type = names[2].type = names[3].type =
        nt_krb5_name_oid;

    progname = (strrchr(argv[0], '/') != NULL) ? strrchr(argv[0], '/') + 1 :
        argv[0];

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

    argc--, argv++;
    while (argc) {
        if (strcmp(*argv, "-x") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            db_args_size++;
            tmpargs = realloc(db_args, sizeof(char *) * (db_args_size + 1));
            if (tmpargs == NULL) {
                fprintf(stderr, _("%s: cannot initialize. Not enough "
                                  "memory\n"), progname);
                exit(1);
            }
            db_args = tmpargs;
            db_args[db_args_size - 1] = *argv;
            db_args[db_args_size] = NULL;
        } else if (strcmp(*argv, "-r") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            params.realm = *argv;
            params.mask |= KADM5_CONFIG_REALM;
            argc--, argv++;
            continue;
        } else if (strcmp(*argv, "-m") == 0) {
            params.mkey_from_kbd = 1;
            params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
        } else if (strcmp(*argv, "-nofork") == 0) {
            nofork = 1;
#ifdef USE_PASSWORD_SERVER
        } else if (strcmp(*argv, "-passwordserver") == 0) {
            kadm5_set_use_password_server();
#endif
#ifndef DISABLE_IPROP
        } else if (strcmp(*argv, "-proponly") == 0) {
            proponly = 1;
#endif
        } else if (strcmp(*argv, "-port") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            params.kadmind_port = atoi(*argv);
            params.mask |= KADM5_CONFIG_KADMIND_PORT;
        } else if (strcmp(*argv, "-P") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            pid_file = *argv;
        } else if (strcmp(*argv, "-W") == 0) {
            strong_random = 0;
        } else if (strcmp(*argv, "-p") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            kdb5_util = *argv;
        } else if (strcmp(*argv, "-F") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            dump_file = *argv;
        } else if (strcmp(*argv, "-K") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            kprop = *argv;
        } else if (strcmp(*argv, "-k") == 0) {
            argc--, argv++;
            if (!argc)
                usage();
            kprop_port = *argv;
        } else {
            break;
        }
        argc--, argv++;
    }

    if (argc != 0)
        usage();

    ret = kadm5_init_krb5_context(&context);
    if (ret) {
        fprintf(stderr, _("%s: %s while initializing context, aborting\n"),
                progname, error_message(ret));
        exit(1);
    }

    krb5_klog_init(context, "admin_server", progname, 1);

    ret = kadm5_init(context, "kadmind", NULL, NULL, &params,
                     KADM5_STRUCT_VERSION, KADM5_API_VERSION_4, db_args,
                     &global_server_handle);
    if (ret)
        fail_to_start(ret, _("initializing"));

    ret = kadm5_get_config_params(context, 1, &params, &params);
    if (ret)
        fail_to_start(ret, _("getting config parameters"));
    if (!(params.mask & KADM5_CONFIG_REALM))
        fail_to_start(0, _("Missing required realm configuration"));
    if (!(params.mask & KADM5_CONFIG_ACL_FILE))
        fail_to_start(0, _("Missing required ACL file configuration"));

    ret = setup_loop(proponly, &vctx);
    if (ret)
        fail_to_start(ret, _("initializing network"));

    names[0].name = build_princ_name(KADM5_ADMIN_SERVICE, params.realm);
    names[1].name = build_princ_name(KADM5_CHANGEPW_SERVICE, params.realm);
    if (names[0].name == NULL || names[1].name == NULL)
        fail_to_start(0, _("Cannot build GSSAPI auth names"));

    ret = setup_kdb_keytab();
    if (ret)
        fail_to_start(0, _("Cannot set up KDB keytab"));

    if (svcauth_gssapi_set_names(names, 2) == FALSE)
        fail_to_start(0, _("Cannot set GSSAPI authentication names"));

    /* if set_names succeeded, this will too */
    in_buf.value = names[1].name;
    in_buf.length = strlen(names[1].name) + 1;
    (void)gss_import_name(&minor_status, &in_buf, nt_krb5_name_oid,
                          &gss_changepw_name);

    svcauth_gssapi_set_log_badauth2_func(log_badauth, NULL);
    svcauth_gssapi_set_log_badverf_func(log_badverf, NULL);
    svcauth_gssapi_set_log_miscerr_func(log_miscerr, NULL);

    svcauth_gss_set_log_badauth2_func(log_badauth, NULL);
    svcauth_gss_set_log_badverf_func(log_badverf, NULL);
    svcauth_gss_set_log_miscerr_func(log_miscerr, NULL);

    if (svcauth_gss_set_svc_name(GSS_C_NO_NAME) != TRUE)
        fail_to_start(0, _("Cannot initialize GSSAPI service name"));

    ret = acl_init(context, params.acl_file);
    if (ret)
        fail_to_start(ret, _("initializing ACL file"));

    if (!nofork && daemon(0, 0) != 0)
        fail_to_start(errno, _("spawning daemon process"));
    if (pid_file != NULL) {
        ret = write_pid_file(pid_file);
        if (ret)
            fail_to_start(ret, _("creating PID file"));
    }

    krb5_klog_syslog(LOG_INFO, _("Seeding random number generator"));
    ret = krb5_c_random_os_entropy(context, strong_random, NULL);
    if (ret)
        fail_to_start(ret, _("getting random seed"));

    if (params.iprop_enabled == TRUE) {
        ulog_set_role(context, IPROP_MASTER);

        ret = ulog_map(context, params.iprop_logfile, params.iprop_ulogsize);
        if (ret)
            fail_to_start(ret, _("mapping update log"));

        if (nofork) {
            fprintf(stderr,
                    _("%s: create IPROP svc (PROG=%d, VERS=%d)\n"),
                    progname, KRB5_IPROP_PROG, KRB5_IPROP_VERS);
        }
    }

    if (kprop_port == NULL)
        kprop_port = getenv("KPROP_PORT");

    krb5_klog_syslog(LOG_INFO, _("starting"));
    if (nofork)
        fprintf(stderr, _("%s: starting...\n"), progname);

    verto_run(vctx);
    krb5_klog_syslog(LOG_INFO, _("finished, exiting"));

    /* Clean up memory, etc */
    svcauth_gssapi_unset_names();
    kadm5_destroy(global_server_handle);
    loop_free(vctx);
    acl_finish(context);
    (void)gss_release_name(&minor_status, &gss_changepw_name);
    (void)gss_release_name(&minor_status, &gss_oldchangepw_name);
    for (i = 0; i < 4; i++)
        free(names[i].name);

    krb5_klog_close(context);
    krb5_free_context(context);
    exit(2);
}
예제 #5
0
파일: config.c 프로젝트: domcleal/rkerberos
/*
 * Returns a Kerberos::Kadm5::Config object. This object contains Kerberos
 * admin configuration.
 *
 * Note that the returned object is frozen. Changes made to the Kerberos
 * admin configuration options after the call will not be reflected in this
 * object.
 */
static VALUE rkadm5_config_initialize(VALUE self){
  RUBY_KADM5_CONFIG* ptr;
  krb5_error_code kerror;

  Data_Get_Struct(self, RUBY_KADM5_CONFIG, ptr); 

  kerror = krb5_init_context(&ptr->ctx);

  if(kerror)
    rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));

  kerror = kadm5_get_config_params(
    ptr->ctx,
    1,
    &ptr->config,
    &ptr->config
  );

  if(kerror)
    rb_raise(cKrb5Exception, "kadm5_get_config_params: %s", error_message(kerror));

  if(ptr->config.realm)
    rb_iv_set(self, "@realm", rb_str_new2(ptr->config.realm));
  else
    rb_iv_set(self, "@realm", Qnil);

  if(ptr->config.admin_server)
    rb_iv_set(self, "@admin_server", rb_str_new2(ptr->config.admin_server));
  else
    rb_iv_set(self, "@admin_server", Qnil);

  if(ptr->config.kadmind_port)
    rb_iv_set(self, "@kadmind_port", INT2FIX(ptr->config.kadmind_port));
  else
    rb_iv_set(self, "@kadmind_port", Qnil);

  if(ptr->config.kpasswd_port)
    rb_iv_set(self, "@kpasswd_port", INT2FIX(ptr->config.kpasswd_port));
  else
    rb_iv_set(self, "@kpasswd_port", Qnil);

  if(ptr->config.acl_file)
    rb_iv_set(self, "@acl_file", rb_str_new2(ptr->config.acl_file));
  else
    rb_iv_set(self, "@acl_file", Qnil);

  if(ptr->config.dict_file)
    rb_iv_set(self, "@dict_file", rb_str_new2(ptr->config.dict_file));
  else
    rb_iv_set(self, "@dict_file", Qnil);

  if(ptr->config.stash_file)
    rb_iv_set(self, "@stash_file", rb_str_new2(ptr->config.stash_file));
  else
    rb_iv_set(self, "@stash_file", Qnil);

  if(ptr->config.mkey_name)
    rb_iv_set(self, "@mkey_name", rb_str_new2(ptr->config.mkey_name));
  else
    rb_iv_set(self, "@mkey_name", Qnil);

  if(ptr->config.mkey_from_kbd)
    rb_iv_set(self, "@mkey_from_kbd", INT2FIX(ptr->config.mkey_from_kbd));
  else
    rb_iv_set(self, "@mkey_from_kbd", Qnil);

  if(ptr->config.enctype)
    rb_iv_set(self, "@enctype", INT2FIX(ptr->config.enctype));
  else
    rb_iv_set(self, "@enctype", Qnil);

  if(ptr->config.max_life)
    rb_iv_set(self, "@max_life", INT2FIX(ptr->config.max_life));
  else
    rb_iv_set(self, "@max_life", Qnil);

  if(ptr->config.max_rlife)
    rb_iv_set(self, "@max_rlife", INT2FIX(ptr->config.max_rlife));
  else
    rb_iv_set(self, "@max_rlife", Qnil);

  if(ptr->config.expiration)
    rb_iv_set(self, "@expiration", rb_time_new(ptr->config.expiration, 0));
  else
    rb_iv_set(self, "@expiration", Qnil);

  if(ptr->config.flags)
    rb_iv_set(self, "@flags", INT2FIX(ptr->config.flags));
  else
    rb_iv_set(self, "@flags", Qnil);

  if(ptr->config.kvno)
    rb_iv_set(self, "@kvno", INT2FIX(ptr->config.kvno));
  else
    rb_iv_set(self, "@kvno", Qnil);

  if(ptr->config.iprop_enabled)
    rb_iv_set(self, "@iprop_enabled", Qtrue);
  else
    rb_iv_set(self, "@iprop_enabled", Qfalse);

  if(ptr->config.iprop_logfile)
    rb_iv_set(self, "@iprop_logfile", rb_str_new2(ptr->config.iprop_logfile));
  else
    rb_iv_set(self, "@iprop_logfile", Qnil);

  if(ptr->config.iprop_poll_time)
    rb_iv_set(self, "@iprop_poll_time", INT2FIX(ptr->config.iprop_poll_time));
  else
    rb_iv_set(self, "@iprop_poll_time", Qnil);

  if(ptr->config.iprop_port)
    rb_iv_set(self, "@iprop_port", INT2FIX(ptr->config.iprop_port));
  else
    rb_iv_set(self, "@iprop_port", Qnil);

  if(ptr->config.num_keysalts)
    rb_iv_set(self, "@num_keysalts", INT2FIX(ptr->config.num_keysalts));
  else
    rb_iv_set(self, "@num_keysalts", Qnil);

  // Not very useful at the moment. How do you iterate over an enum in C?
  if(ptr->config.keysalts)
    rb_iv_set(self, "@keysalts", INT2FIX(ptr->config.keysalts));
  else
    rb_iv_set(self, "@keysalts", Qnil);

  // This is read only data
  rb_obj_freeze(self);

  return self;
}