Make kadm5_lock() and unlock work, and add kadmin commands for them.
The libkadm5 functions hdb_open() and close around all HDB ops. This meant the previous implementation of kadm5_lock() and unlock would always result in a core dump. Now we hdb_open() for write in kadm5_lock() and hdb_close() in kadm5_unlock(), with all kadm5_s_*() functions now not opening nor closing the HDB when the server context keep_open flag is set. Also, there's now kadmin(8) lock and unlock commands. These are there primarily as a way to test the kadm5_lock()/unlock() operations, but MIT's kadmin.local also has lock/unlock commands, and these can be useful for scripting (though they require much care).
This commit is contained in:
		| @@ -459,6 +459,22 @@ command = { | |||||||
| 	max_args = "1" | 	max_args = "1" | ||||||
| 	help = "Check the realm (if not given, the default realm) for configuration errors." | 	help = "Check the realm (if not given, the default realm) for configuration errors." | ||||||
| } | } | ||||||
|  | command = { | ||||||
|  | 	name = "lock" | ||||||
|  | 	function = "lock" | ||||||
|  | 	argument = "" | ||||||
|  | 	min_args = "0" | ||||||
|  | 	max_args = "0" | ||||||
|  | 	help = "Lock the database for writing (use with care)." | ||||||
|  | } | ||||||
|  | command = { | ||||||
|  | 	name = "unlock" | ||||||
|  | 	function = "unlock" | ||||||
|  | 	argument = "" | ||||||
|  | 	min_args = "0" | ||||||
|  | 	max_args = "0" | ||||||
|  | 	help = "Unlock the database." | ||||||
|  | } | ||||||
| command = { | command = { | ||||||
| 	name = "help" | 	name = "help" | ||||||
| 	name = "?" | 	name = "?" | ||||||
|   | |||||||
| @@ -112,6 +112,18 @@ exit_kadmin (void *opt, int argc, char **argv) | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | lock(void *opt, int argc, char **argv) | ||||||
|  | { | ||||||
|  |     return kadm5_lock(kadm_handle); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | unlock(void *opt, int argc, char **argv) | ||||||
|  | { | ||||||
|  |     return kadm5_unlock(kadm_handle); | ||||||
|  | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| usage(int ret) | usage(int ret) | ||||||
| { | { | ||||||
|   | |||||||
| @@ -50,9 +50,11 @@ change(void *server_handle, | |||||||
|     int existsp = 0; |     int existsp = 0; | ||||||
|  |  | ||||||
|     memset(&ent, 0, sizeof(ent)); |     memset(&ent, 0, sizeof(ent)); | ||||||
|  |     if (!context->keep_open) { | ||||||
| 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | ||||||
| 	if(ret) | 	if(ret) | ||||||
| 	    return ret; | 	    return ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, |     ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, | ||||||
| 				      HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); | 				      HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); | ||||||
| @@ -145,6 +147,7 @@ change(void *server_handle, | |||||||
| out2: | out2: | ||||||
|     hdb_free_entry(context->context, &ent); |     hdb_free_entry(context->context, &ent); | ||||||
| out: | out: | ||||||
|  |     if (!context->keep_open) | ||||||
| 	context->db->hdb_close(context->context, context->db); | 	context->db->hdb_close(context->context, context->db); | ||||||
|     return _kadm5_error_code(ret); |     return _kadm5_error_code(ret); | ||||||
| } | } | ||||||
| @@ -193,9 +196,11 @@ kadm5_s_chpass_principal_with_key(void *server_handle, | |||||||
|     kadm5_ret_t ret; |     kadm5_ret_t ret; | ||||||
|  |  | ||||||
|     memset(&ent, 0, sizeof(ent)); |     memset(&ent, 0, sizeof(ent)); | ||||||
|  |     if (!context->keep_open) { | ||||||
| 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | ||||||
| 	if(ret) | 	if(ret) | ||||||
| 	    return ret; | 	    return ret; | ||||||
|  |     } | ||||||
|     ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, 0, |     ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, 0, | ||||||
| 				      HDB_F_GET_ANY|HDB_F_ADMIN_DATA, &ent); | 				      HDB_F_GET_ANY|HDB_F_ADMIN_DATA, &ent); | ||||||
|     if(ret == HDB_ERR_NOENTRY) |     if(ret == HDB_ERR_NOENTRY) | ||||||
| @@ -244,6 +249,7 @@ kadm5_s_chpass_principal_with_key(void *server_handle, | |||||||
| out2: | out2: | ||||||
|     hdb_free_entry(context->context, &ent); |     hdb_free_entry(context->context, &ent); | ||||||
| out: | out: | ||||||
|  |     if (!context->keep_open) | ||||||
| 	context->db->hdb_close(context->context, context->db); | 	context->db->hdb_close(context->context, context->db); | ||||||
|     return _kadm5_error_code(ret); |     return _kadm5_error_code(ret); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -39,16 +39,46 @@ static kadm5_ret_t | |||||||
| kadm5_s_lock(void *server_handle) | kadm5_s_lock(void *server_handle) | ||||||
| { | { | ||||||
|     kadm5_server_context *context = server_handle; |     kadm5_server_context *context = server_handle; | ||||||
|  |     kadm5_ret_t ret; | ||||||
|  |  | ||||||
|     return context->db->hdb_lock(context->context, context->db, HDB_WLOCK); |     if (context->keep_open) { | ||||||
|  | 	/* | ||||||
|  | 	 * We open/close around every operation, but we retain the DB | ||||||
|  | 	 * open if the DB was locked with a prior call to kadm5_lock(), | ||||||
|  | 	 * so if it's open here that must be because the DB is locked. | ||||||
|  | 	 */ | ||||||
|  | 	assert( context->db->lock_count > 0 ); | ||||||
|  | 	return KADM5_ALREADY_LOCKED; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | ||||||
|  |     if (ret) | ||||||
|  | 	return ret; | ||||||
|  |  | ||||||
|  |     ret = context->db->hdb_lock(context->context, context->db, HDB_WLOCK); | ||||||
|  |     if (ret) | ||||||
|  | 	return ret; | ||||||
|  |  | ||||||
|  |     context->keep_open = 1; | ||||||
|  |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static kadm5_ret_t | static kadm5_ret_t | ||||||
| kadm5_s_unlock(void *server_handle) | kadm5_s_unlock(void *server_handle) | ||||||
| { | { | ||||||
|     kadm5_server_context *context = server_handle; |     kadm5_server_context *context = server_handle; | ||||||
|  |     kadm5_ret_t ret; | ||||||
|  |  | ||||||
|     return context->db->hdb_unlock(context->context, context->db); |     if (!context->keep_open) | ||||||
|  | 	return KADM5_NOT_LOCKED; | ||||||
|  |  | ||||||
|  |     (void) context->db->hdb_close(context->context, context->db); | ||||||
|  |  | ||||||
|  |     context->keep_open = 0; | ||||||
|  |     ret = context->db->hdb_unlock(context->context, context->db); | ||||||
|  |     if (ret) | ||||||
|  | 	return ret; | ||||||
|  |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
|   | |||||||
| @@ -131,10 +131,13 @@ kadm5_s_create_principal_with_key(void *server_handle, | |||||||
|     if (ret) |     if (ret) | ||||||
| 	goto out; | 	goto out; | ||||||
|  |  | ||||||
|  |     if (!context->keep_open) { | ||||||
| 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | ||||||
| 	if(ret) | 	if(ret) | ||||||
| 	    goto out; | 	    goto out; | ||||||
|  |     } | ||||||
|     ret = context->db->hdb_store(context->context, context->db, 0, &ent); |     ret = context->db->hdb_store(context->context, context->db, 0, &ent); | ||||||
|  |     if (!context->keep_open) | ||||||
| 	context->db->hdb_close(context->context, context->db); | 	context->db->hdb_close(context->context, context->db); | ||||||
|     if (ret) |     if (ret) | ||||||
| 	goto out; | 	goto out; | ||||||
| @@ -183,10 +186,13 @@ kadm5_s_create_principal(void *server_handle, | |||||||
|     if (ret) |     if (ret) | ||||||
| 	goto out; | 	goto out; | ||||||
|  |  | ||||||
|  |     if (!context->keep_open) { | ||||||
| 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | ||||||
| 	if(ret) | 	if(ret) | ||||||
| 	    goto out; | 	    goto out; | ||||||
|  |     } | ||||||
|     ret = context->db->hdb_store(context->context, context->db, 0, &ent); |     ret = context->db->hdb_store(context->context, context->db, 0, &ent); | ||||||
|  |     if (!context->keep_open) | ||||||
| 	context->db->hdb_close(context->context, context->db); | 	context->db->hdb_close(context->context, context->db); | ||||||
|     if (ret) |     if (ret) | ||||||
| 	goto out; | 	goto out; | ||||||
|   | |||||||
| @@ -43,11 +43,13 @@ kadm5_s_delete_principal(void *server_handle, krb5_principal princ) | |||||||
|     hdb_entry_ex ent; |     hdb_entry_ex ent; | ||||||
|  |  | ||||||
|     memset(&ent, 0, sizeof(ent)); |     memset(&ent, 0, sizeof(ent)); | ||||||
|  |     if (!context->keep_open) { | ||||||
| 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | ||||||
| 	if(ret) { | 	if(ret) { | ||||||
| 	    krb5_warn(context->context, ret, "opening database"); | 	    krb5_warn(context->context, ret, "opening database"); | ||||||
| 	    return ret; | 	    return ret; | ||||||
| 	} | 	} | ||||||
|  |     } | ||||||
|     ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, |     ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, | ||||||
| 				      HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); | 				      HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); | ||||||
|     if(ret == HDB_ERR_NOENTRY) |     if(ret == HDB_ERR_NOENTRY) | ||||||
| @@ -70,6 +72,7 @@ kadm5_s_delete_principal(void *server_handle, krb5_principal princ) | |||||||
| out2: | out2: | ||||||
|     hdb_free_entry(context->context, &ent); |     hdb_free_entry(context->context, &ent); | ||||||
| out: | out: | ||||||
|  |     if (!context->keep_open) | ||||||
| 	context->db->hdb_close(context->context, context->db); | 	context->db->hdb_close(context->context, context->db); | ||||||
|     return _kadm5_error_code(ret); |     return _kadm5_error_code(ret); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -85,11 +85,14 @@ kadm5_s_get_principals(void *server_handle, | |||||||
|     struct foreach_data d; |     struct foreach_data d; | ||||||
|     kadm5_server_context *context = server_handle; |     kadm5_server_context *context = server_handle; | ||||||
|     kadm5_ret_t ret; |     kadm5_ret_t ret; | ||||||
|  |  | ||||||
|  |     if (!context->keep_open) { | ||||||
| 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | ||||||
| 	if(ret) { | 	if(ret) { | ||||||
| 	    krb5_warn(context->context, ret, "opening database"); | 	    krb5_warn(context->context, ret, "opening database"); | ||||||
| 	    return ret; | 	    return ret; | ||||||
| 	} | 	} | ||||||
|  |     } | ||||||
|     d.exp = expression; |     d.exp = expression; | ||||||
|     { |     { | ||||||
| 	krb5_realm r; | 	krb5_realm r; | ||||||
| @@ -100,6 +103,7 @@ kadm5_s_get_principals(void *server_handle, | |||||||
|     d.princs = NULL; |     d.princs = NULL; | ||||||
|     d.count = 0; |     d.count = 0; | ||||||
|     ret = hdb_foreach(context->context, context->db, HDB_F_ADMIN_DATA, foreach, &d); |     ret = hdb_foreach(context->context, context->db, HDB_F_ADMIN_DATA, foreach, &d); | ||||||
|  |     if (!context->keep_open) | ||||||
| 	context->db->hdb_close(context->context, context->db); | 	context->db->hdb_close(context->context, context->db); | ||||||
|     if(ret == 0) |     if(ret == 0) | ||||||
| 	ret = add_princ(&d, NULL); | 	ret = add_princ(&d, NULL); | ||||||
|   | |||||||
| @@ -127,12 +127,16 @@ kadm5_s_get_principal(void *server_handle, | |||||||
|     hdb_entry_ex ent; |     hdb_entry_ex ent; | ||||||
|  |  | ||||||
|     memset(&ent, 0, sizeof(ent)); |     memset(&ent, 0, sizeof(ent)); | ||||||
|  |  | ||||||
|  |     if (!context->keep_open) { | ||||||
| 	ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0); | 	ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0); | ||||||
| 	if(ret) | 	if(ret) | ||||||
| 	    return ret; | 	    return ret; | ||||||
|  |     } | ||||||
|     ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, |     ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, | ||||||
| 				      HDB_F_DECRYPT|HDB_F_ALL_KVNOS| | 				      HDB_F_DECRYPT|HDB_F_ALL_KVNOS| | ||||||
| 				      HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); | 				      HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); | ||||||
|  |     if (!context->keep_open) | ||||||
| 	context->db->hdb_close(context->context, context->db); | 	context->db->hdb_close(context->context, context->db); | ||||||
|     if(ret) |     if(ret) | ||||||
| 	return _kadm5_error_code(ret); | 	return _kadm5_error_code(ret); | ||||||
|   | |||||||
| @@ -63,3 +63,5 @@ error_code DECRYPT_USAGE_NOSUPP,	"Given usage of kadm5_decrypt() not supported" | |||||||
| error_code POLICY_OP_NOSUPP,	"Policy operations not supported" | error_code POLICY_OP_NOSUPP,	"Policy operations not supported" | ||||||
| error_code KEEPOLD_NOSUPP,	"Keep old keys option not supported" | error_code KEEPOLD_NOSUPP,	"Keep old keys option not supported" | ||||||
| error_code AUTH_GET_KEYS,	"Operation requires `get-keys' privilege" | error_code AUTH_GET_KEYS,	"Operation requires `get-keys' privilege" | ||||||
|  | error_code ALREADY_LOCKED,	"Database already locked" | ||||||
|  | error_code NOT_LOCKED,		"Database not locked" | ||||||
|   | |||||||
| @@ -52,9 +52,11 @@ modify_principal(void *server_handle, | |||||||
|     if((mask & KADM5_POLICY) && strcmp(princ->policy, "default")) |     if((mask & KADM5_POLICY) && strcmp(princ->policy, "default")) | ||||||
| 	return KADM5_UNK_POLICY; | 	return KADM5_UNK_POLICY; | ||||||
|  |  | ||||||
|  |     if (!context->keep_open) { | ||||||
| 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | ||||||
| 	if(ret) | 	if(ret) | ||||||
| 	    return ret; | 	    return ret; | ||||||
|  |     } | ||||||
|     ret = context->db->hdb_fetch_kvno(context->context, context->db, |     ret = context->db->hdb_fetch_kvno(context->context, context->db, | ||||||
| 				      princ->principal, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); | 				      princ->principal, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); | ||||||
|     if(ret) |     if(ret) | ||||||
| @@ -97,6 +99,7 @@ modify_principal(void *server_handle, | |||||||
| out2: | out2: | ||||||
|     hdb_free_entry(context->context, &ent); |     hdb_free_entry(context->context, &ent); | ||||||
| out: | out: | ||||||
|  |     if (!context->keep_open) | ||||||
| 	context->db->hdb_close(context->context, context->db); | 	context->db->hdb_close(context->context, context->db); | ||||||
|     return _kadm5_error_code(ret); |     return _kadm5_error_code(ret); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -92,6 +92,7 @@ typedef struct kadm5_server_context { | |||||||
|     /* */ |     /* */ | ||||||
|     kadm5_config_params config; |     kadm5_config_params config; | ||||||
|     HDB *db; |     HDB *db; | ||||||
|  |     int keep_open; | ||||||
|     krb5_principal caller; |     krb5_principal caller; | ||||||
|     unsigned acl_flags; |     unsigned acl_flags; | ||||||
|     kadm5_log_context log_context; |     kadm5_log_context log_context; | ||||||
|   | |||||||
| @@ -54,9 +54,11 @@ kadm5_s_randkey_principal(void *server_handle, | |||||||
|     kadm5_ret_t ret; |     kadm5_ret_t ret; | ||||||
|  |  | ||||||
|     memset(&ent, 0, sizeof(ent)); |     memset(&ent, 0, sizeof(ent)); | ||||||
|  |     if (!context->keep_open) { | ||||||
| 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | ||||||
| 	if(ret) | 	if(ret) | ||||||
| 	    return ret; | 	    return ret; | ||||||
|  |     } | ||||||
|     ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, |     ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, | ||||||
| 				      HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); | 				      HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); | ||||||
|     if(ret) |     if(ret) | ||||||
| @@ -122,6 +124,7 @@ out3: | |||||||
| out2: | out2: | ||||||
|     hdb_free_entry(context->context, &ent); |     hdb_free_entry(context->context, &ent); | ||||||
| out: | out: | ||||||
|  |     if (!context->keep_open) | ||||||
| 	context->db->hdb_close(context->context, context->db); | 	context->db->hdb_close(context->context, context->db); | ||||||
|     return _kadm5_error_code(ret); |     return _kadm5_error_code(ret); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -48,12 +48,15 @@ kadm5_s_rename_principal(void *server_handle, | |||||||
|     memset(&ent, 0, sizeof(ent)); |     memset(&ent, 0, sizeof(ent)); | ||||||
|     if(krb5_principal_compare(context->context, source, target)) |     if(krb5_principal_compare(context->context, source, target)) | ||||||
| 	return KADM5_DUP; /* XXX is this right? */ | 	return KADM5_DUP; /* XXX is this right? */ | ||||||
|  |     if (!context->keep_open) { | ||||||
| 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | 	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); | ||||||
| 	if(ret) | 	if(ret) | ||||||
| 	    return ret; | 	    return ret; | ||||||
|  |     } | ||||||
|     ret = context->db->hdb_fetch_kvno(context->context, context->db, |     ret = context->db->hdb_fetch_kvno(context->context, context->db, | ||||||
| 				      source, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); | 				      source, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); | ||||||
|     if(ret){ |     if(ret){ | ||||||
|  | 	if (!context->keep_open) | ||||||
| 	    context->db->hdb_close(context->context, context->db); | 	    context->db->hdb_close(context->context, context->db); | ||||||
| 	goto out; | 	goto out; | ||||||
|     } |     } | ||||||
| @@ -103,6 +106,7 @@ kadm5_s_rename_principal(void *server_handle, | |||||||
|     ret = context->db->hdb_remove(context->context, context->db, oldname); |     ret = context->db->hdb_remove(context->context, context->db, oldname); | ||||||
|     ent.entry.principal = oldname; |     ent.entry.principal = oldname; | ||||||
| out2: | out2: | ||||||
|  |     if (!context->keep_open) | ||||||
| 	context->db->hdb_close(context->context, context->db); | 	context->db->hdb_close(context->context, context->db); | ||||||
|     hdb_free_entry(context->context, &ent); |     hdb_free_entry(context->context, &ent); | ||||||
| out: | out: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Nicolas Williams
					Nicolas Williams