 387684aa93
			
		
	
	387684aa93
	
	
	
		
			
			On 32-bit Windows Intel builds the __cdecl and __stdcall calling conventions are different so labeling the functions that are exported or assigned to function pointers matters. Change-Id: I03b6f34baeb9ffb2e683fd979f12f27a5078a4da
		
			
				
	
	
		
			287 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2018-2019, AuriStor, Inc.
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  *
 | |
|  * - Redistributions of source code must retain the above copyright
 | |
|  *   notice, this list of conditions and the following disclaimer.
 | |
|  *
 | |
|  * - Redistributions in binary form must reproduce the above copyright
 | |
|  *   notice, this list of conditions and the following disclaimer in
 | |
|  *   the documentation and/or other materials provided with the
 | |
|  *   distribution.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | |
|  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | |
|  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | |
|  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 | |
|  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 | |
|  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | |
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | |
|  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | |
|  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 | |
|  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | |
|  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 | |
|  * OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <assert.h>
 | |
| 
 | |
| #include <krb5.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include "admin.h"
 | |
| #include "kadm5-hook.h"
 | |
| 
 | |
| /*
 | |
|  * Sample kadm5 hook plugin that just logs when it is called. Install it
 | |
|  * somewhere and configure the path in the [kadmin] section of krb5.conf.
 | |
|  * e.g.
 | |
|  *
 | |
|  * [kadmin]
 | |
|  *  plugin_dir = /usr/local/heimdal/lib/plugin/kadm5
 | |
|  *
 | |
|  */
 | |
| 
 | |
| static char sample_data_1, sample_data_2;
 | |
| 
 | |
| static krb5_error_code
 | |
| sample_log(krb5_context context,
 | |
| 	   void *data,
 | |
| 	   enum kadm5_hook_stage stage,
 | |
| 	   const char *tag,
 | |
| 	   krb5_error_code code,
 | |
| 	   krb5_const_principal princ)
 | |
| {
 | |
|     char *p = NULL;
 | |
|     int which = 0;
 | |
| 
 | |
|     /* verify we get called with the right contex tpointer */
 | |
|     if (data == &sample_data_1)
 | |
| 	which = 1;
 | |
|     else if (data == &sample_data_2)
 | |
| 	which = 2;
 | |
| 
 | |
|     assert(which != 0);
 | |
| 
 | |
|     /* code should always be zero on pre-commit */
 | |
|     assert(code == 0 || stage == KADM5_HOOK_STAGE_POSTCOMMIT);
 | |
| 
 | |
|     if (princ)
 | |
| 	(void) krb5_unparse_name(context, princ, &p);
 | |
| 
 | |
|     krb5_warn(context, code, "sample_hook_%d: %s %s hook princ '%s'", which, tag,
 | |
| 	      stage == KADM5_HOOK_STAGE_PRECOMMIT ? "pre-commit" : "post-commit",
 | |
| 	      p != NULL ? p : "<unknown>");
 | |
| 
 | |
|     krb5_xfree(p);
 | |
| 
 | |
|     /* returning zero and KRB5_PLUGIN_NO_HANDLE are the same for hook plugins */
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static krb5_error_code KRB5_CALLCONV
 | |
| sample_init_1(krb5_context context, void **data)
 | |
| {
 | |
|     *data = &sample_data_1;
 | |
|     krb5_warn(context, 0, "sample_hook_1: initializing");
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static krb5_error_code KRB5_CALLCONV
 | |
| sample_init_2(krb5_context context, void **data)
 | |
| {
 | |
|     *data = &sample_data_2;
 | |
|     krb5_warn(context, 0, "sample_hook_2: initializing");
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static void KRB5_CALLCONV
 | |
| sample_fini(void *data)
 | |
| {
 | |
|     krb5_warn(NULL, 0, "sample_fini: finalizing");
 | |
| }
 | |
| 
 | |
| static krb5_error_code KRB5_CALLCONV
 | |
| sample_chpass_hook(krb5_context context,
 | |
| 		   void *data,
 | |
| 		   enum kadm5_hook_stage stage,
 | |
| 		   krb5_error_code code,
 | |
| 		   krb5_const_principal princ,
 | |
| 		   uint32_t flags,
 | |
| 		   size_t n_ks_tuple,
 | |
| 		   krb5_key_salt_tuple *ks_tuple,
 | |
| 		   const char *password)
 | |
| {
 | |
|     return sample_log(context, data, stage, "chpass", code, princ);
 | |
| }
 | |
| 
 | |
| static krb5_error_code KRB5_CALLCONV
 | |
| sample_chpass_with_key_hook(krb5_context context,
 | |
| 			    void *data,
 | |
| 			    enum kadm5_hook_stage stage,
 | |
| 			    krb5_error_code code,
 | |
| 			    krb5_const_principal princ,
 | |
| 			    uint32_t flags,
 | |
| 			    size_t n_key_data,
 | |
| 			    krb5_key_data *key_data)
 | |
| {
 | |
|     return sample_log(context, data, stage, "chpass_with_key", code, princ);
 | |
| }
 | |
| 
 | |
| static krb5_error_code KRB5_CALLCONV
 | |
| sample_create_hook(krb5_context context,
 | |
| 		   void *data,
 | |
| 		   enum kadm5_hook_stage stage,
 | |
| 		   krb5_error_code code,
 | |
| 		   kadm5_principal_ent_t ent,
 | |
| 		   uint32_t mask,
 | |
| 		   const char *password)
 | |
| {
 | |
|     return sample_log(context, data, stage, "create", code, ent->principal);
 | |
| }
 | |
| 
 | |
| static krb5_error_code KRB5_CALLCONV
 | |
| sample_modify_hook(krb5_context context,
 | |
| 		   void *data,
 | |
| 		   enum kadm5_hook_stage stage,
 | |
| 		   krb5_error_code code,
 | |
| 		   kadm5_principal_ent_t ent,
 | |
| 		   uint32_t mask)
 | |
| {
 | |
|     return sample_log(context, data, stage, "modify", code, ent->principal);
 | |
| }
 | |
| 
 | |
| static krb5_error_code KRB5_CALLCONV
 | |
| sample_delete_hook(krb5_context context,
 | |
| 		   void *data,
 | |
| 		   enum kadm5_hook_stage stage,
 | |
| 		   krb5_error_code code,
 | |
| 		   krb5_const_principal princ)
 | |
| {
 | |
|     return sample_log(context, data, stage, "delete", code, princ);
 | |
| }
 | |
| 
 | |
| static krb5_error_code KRB5_CALLCONV
 | |
| sample_randkey_hook(krb5_context context,
 | |
| 		    void *data,
 | |
| 		    enum kadm5_hook_stage stage,
 | |
| 		    krb5_error_code code,
 | |
| 		    krb5_const_principal princ)
 | |
| {
 | |
|     return sample_log(context, data, stage, "randkey", code, princ);
 | |
| }
 | |
| 
 | |
| static krb5_error_code KRB5_CALLCONV
 | |
| sample_rename_hook(krb5_context context,
 | |
| 		   void *data,
 | |
| 		   enum kadm5_hook_stage stage,
 | |
| 		   krb5_error_code code,
 | |
| 		   krb5_const_principal source,
 | |
| 		   krb5_const_principal target)
 | |
| {
 | |
|     return sample_log(context, data, stage, "rename", code, source);
 | |
| }
 | |
| 
 | |
| static krb5_error_code KRB5_CALLCONV
 | |
| sample_set_keys_hook(krb5_context context,
 | |
| 		     void *data,
 | |
| 		     enum kadm5_hook_stage stage,
 | |
| 		     krb5_error_code code,
 | |
| 		     krb5_const_principal princ,
 | |
| 		     uint32_t flags,
 | |
| 		     size_t n_ks_tuple,
 | |
| 		     krb5_key_salt_tuple *ks_tuple,
 | |
| 		     size_t n_keys,
 | |
| 		     krb5_keyblock *keyblocks)
 | |
| {
 | |
|     return sample_log(context, data, stage, "set_keys", code, princ);
 | |
| }
 | |
| 
 | |
| static krb5_error_code KRB5_CALLCONV
 | |
| sample_prune_hook(krb5_context context,
 | |
| 		  void *data,
 | |
| 		  enum kadm5_hook_stage stage,
 | |
| 		  krb5_error_code code,
 | |
| 		  krb5_const_principal princ,
 | |
| 		  int kvno)
 | |
| {
 | |
|     return sample_log(context, data, stage, "prune", code, princ);
 | |
| }
 | |
| 
 | |
| 
 | |
| static const kadm5_hook_ftable sample_hook_1 = {
 | |
|     KADM5_HOOK_VERSION_V1,
 | |
|     sample_init_1,
 | |
|     sample_fini,
 | |
|     "sample_hook_1",
 | |
|     "Heimdal",
 | |
|     sample_chpass_hook,
 | |
|     sample_chpass_with_key_hook,
 | |
|     sample_create_hook,
 | |
|     sample_modify_hook,
 | |
|     sample_delete_hook,
 | |
|     sample_randkey_hook,
 | |
|     sample_rename_hook,
 | |
|     sample_set_keys_hook,
 | |
|     sample_prune_hook,
 | |
| };
 | |
| 
 | |
| static const kadm5_hook_ftable sample_hook_2 = {
 | |
|     KADM5_HOOK_VERSION_V1,
 | |
|     sample_init_2,
 | |
|     sample_fini,
 | |
|     "sample_hook_2",
 | |
|     "Heimdal",
 | |
|     sample_chpass_hook,
 | |
|     sample_chpass_with_key_hook,
 | |
|     sample_create_hook,
 | |
|     sample_modify_hook,
 | |
|     sample_delete_hook,
 | |
|     sample_randkey_hook,
 | |
|     sample_rename_hook,
 | |
|     sample_set_keys_hook,
 | |
|     sample_prune_hook,
 | |
| };
 | |
| 
 | |
| /* Arrays of pointers, because hooks may be different versions/sizes */
 | |
| static const kadm5_hook_ftable *const sample_hooks[] = {
 | |
|     &sample_hook_1,
 | |
|     &sample_hook_2,
 | |
| };
 | |
| 
 | |
| krb5_error_code
 | |
| kadm5_hook_plugin_load(krb5_context context,
 | |
| 		       krb5_get_instance_func_t *get_instance,
 | |
| 		       size_t *num_hooks,
 | |
| 		       const kadm5_hook_ftable *const **hooks);
 | |
| 
 | |
| static uintptr_t KRB5_LIB_CALL
 | |
| sample_hook_get_instance(const char *libname)
 | |
| {
 | |
|     if (strcmp(libname, "kadm5") == 0)
 | |
| 	return kadm5_get_instance(libname);
 | |
|     else if (strcmp(libname, "krb5") == 0)
 | |
| 	return krb5_get_instance(libname);
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| krb5_error_code
 | |
| kadm5_hook_plugin_load(krb5_context context,
 | |
| 		       krb5_get_instance_func_t *get_instance,
 | |
| 		       size_t *num_hooks,
 | |
| 		       const kadm5_hook_ftable *const **hooks)
 | |
| {
 | |
|     *get_instance = sample_hook_get_instance;
 | |
|     *num_hooks = sizeof(sample_hooks) / sizeof(sample_hooks[0]);
 | |
|     *hooks = sample_hooks;
 | |
| 
 | |
|     return 0;
 | |
| }
 |