Home | History | Annotate | Line # | Download | only in admin
      1  1.1     elric /*	$NetBSD: change.c,v 1.3 2023/06/19 21:41:38 christos Exp $	*/
      2  1.1     elric 
      3  1.1     elric /*
      4  1.1     elric  * Copyright (c) 1997-2005 Kungliga Tekniska Hgskolan
      5  1.1     elric  * (Royal Institute of Technology, Stockholm, Sweden).
      6  1.1     elric  * All rights reserved.
      7  1.1     elric  *
      8  1.1     elric  * Redistribution and use in source and binary forms, with or without
      9  1.1     elric  * modification, are permitted provided that the following conditions
     10  1.1     elric  * are met:
     11  1.1     elric  *
     12  1.1     elric  * 1. Redistributions of source code must retain the above copyright
     13  1.1     elric  *    notice, this list of conditions and the following disclaimer.
     14  1.1     elric  *
     15  1.1     elric  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1     elric  *    notice, this list of conditions and the following disclaimer in the
     17  1.1     elric  *    documentation and/or other materials provided with the distribution.
     18  1.1     elric  *
     19  1.1     elric  * 3. Neither the name of the Institute nor the names of its contributors
     20  1.1     elric  *    may be used to endorse or promote products derived from this software
     21  1.1     elric  *    without specific prior written permission.
     22  1.1     elric  *
     23  1.1     elric  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  1.1     elric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  1.1     elric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  1.1     elric  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  1.1     elric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  1.1     elric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  1.1     elric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  1.1     elric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  1.1     elric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  1.1     elric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  1.1     elric  * SUCH DAMAGE.
     34  1.1     elric  */
     35  1.1     elric 
     36  1.1     elric #include "ktutil_locl.h"
     37  1.1     elric 
     38  1.1     elric __RCSID("$NetBSD: change.c,v 1.3 2023/06/19 21:41:38 christos Exp $");
     39  1.1     elric 
     40  1.1     elric static krb5_error_code
     41  1.1     elric change_entry (krb5_keytab keytab,
     42  1.1     elric 	      krb5_principal principal, krb5_kvno kvno,
     43  1.1     elric 	      const char *realm, const char *admin_server, int server_port)
     44  1.1     elric {
     45  1.1     elric     krb5_error_code ret;
     46  1.1     elric     kadm5_config_params conf;
     47  1.1     elric     void *kadm_handle;
     48  1.1     elric     char *client_name;
     49  1.1     elric     krb5_keyblock *keys;
     50  1.1     elric     int num_keys;
     51  1.1     elric     int i;
     52  1.1     elric 
     53  1.1     elric     ret = krb5_unparse_name (context, principal, &client_name);
     54  1.1     elric     if (ret) {
     55  1.1     elric 	krb5_warn (context, ret, "krb5_unparse_name");
     56  1.1     elric 	return ret;
     57  1.1     elric     }
     58  1.1     elric 
     59  1.1     elric     memset (&conf, 0, sizeof(conf));
     60  1.1     elric 
     61  1.1     elric     if(realm == NULL)
     62  1.1     elric 	realm = krb5_principal_get_realm(context, principal);
     63  1.1     elric     conf.realm = strdup(realm);
     64  1.1     elric     if (conf.realm == NULL) {
     65  1.1     elric 	free (client_name);
     66  1.1     elric 	krb5_set_error_message(context, ENOMEM, "malloc failed");
     67  1.1     elric 	return ENOMEM;
     68  1.1     elric     }
     69  1.1     elric     conf.mask |= KADM5_CONFIG_REALM;
     70  1.1     elric 
     71  1.1     elric     if (admin_server) {
     72  1.1     elric 	conf.admin_server = strdup(admin_server);
     73  1.1     elric 	if (conf.admin_server == NULL) {
     74  1.1     elric 	    free(client_name);
     75  1.1     elric 	    free(conf.realm);
     76  1.1     elric 	    krb5_set_error_message(context, ENOMEM, "malloc failed");
     77  1.1     elric 	    return ENOMEM;
     78  1.2  christos 	}
     79  1.1     elric 	conf.mask |= KADM5_CONFIG_ADMIN_SERVER;
     80  1.1     elric     }
     81  1.1     elric 
     82  1.1     elric     if (server_port) {
     83  1.1     elric 	conf.kadmind_port = htons(server_port);
     84  1.1     elric 	conf.mask |= KADM5_CONFIG_KADMIND_PORT;
     85  1.1     elric     }
     86  1.1     elric 
     87  1.1     elric     ret = kadm5_init_with_skey_ctx (context,
     88  1.1     elric 				    client_name,
     89  1.1     elric 				    keytab_string,
     90  1.1     elric 				    KADM5_ADMIN_SERVICE,
     91  1.1     elric 				    &conf, 0, 0,
     92  1.1     elric 				    &kadm_handle);
     93  1.1     elric     free(conf.admin_server);
     94  1.1     elric     free(conf.realm);
     95  1.1     elric     if (ret) {
     96  1.1     elric 	krb5_warn (context, ret,
     97  1.1     elric 		   "kadm5_c_init_with_skey_ctx: %s:", client_name);
     98  1.1     elric 	free (client_name);
     99  1.1     elric 	return ret;
    100  1.1     elric     }
    101  1.1     elric     ret = kadm5_randkey_principal (kadm_handle, principal, &keys, &num_keys);
    102  1.1     elric     kadm5_destroy (kadm_handle);
    103  1.1     elric     if (ret) {
    104  1.1     elric 	krb5_warn(context, ret, "kadm5_randkey_principal: %s:", client_name);
    105  1.1     elric 	free (client_name);
    106  1.1     elric 	return ret;
    107  1.1     elric     }
    108  1.1     elric     free (client_name);
    109  1.1     elric     for (i = 0; i < num_keys; ++i) {
    110  1.1     elric 	krb5_keytab_entry new_entry;
    111  1.1     elric 
    112  1.1     elric 	new_entry.principal = principal;
    113  1.1     elric 	new_entry.timestamp = time (NULL);
    114  1.1     elric 	new_entry.vno = kvno + 1;
    115  1.1     elric 	new_entry.keyblock  = keys[i];
    116  1.1     elric 
    117  1.1     elric 	ret = krb5_kt_add_entry (context, keytab, &new_entry);
    118  1.1     elric 	if (ret)
    119  1.1     elric 	    krb5_warn (context, ret, "krb5_kt_add_entry");
    120  1.1     elric 	krb5_free_keyblock_contents (context, &keys[i]);
    121  1.1     elric     }
    122  1.1     elric     return ret;
    123  1.1     elric }
    124  1.1     elric 
    125  1.1     elric /*
    126  1.1     elric  * loop over all the entries in the keytab (or those given) and change
    127  1.1     elric  * their keys, writing the new keys
    128  1.1     elric  */
    129  1.1     elric 
    130  1.1     elric struct change_set {
    131  1.1     elric     krb5_principal principal;
    132  1.1     elric     krb5_kvno kvno;
    133  1.1     elric };
    134  1.1     elric 
    135  1.1     elric int
    136  1.1     elric kt_change (struct change_options *opt, int argc, char **argv)
    137  1.1     elric {
    138  1.1     elric     krb5_error_code ret;
    139  1.1     elric     krb5_keytab keytab;
    140  1.1     elric     krb5_kt_cursor cursor;
    141  1.1     elric     krb5_keytab_entry entry;
    142  1.1     elric     int i, j, max;
    143  1.1     elric     struct change_set *changeset;
    144  1.1     elric     int errors = 0;
    145  1.1     elric 
    146  1.1     elric     if((keytab = ktutil_open_keytab()) == NULL)
    147  1.1     elric 	return 1;
    148  1.1     elric 
    149  1.1     elric     j = 0;
    150  1.1     elric     max = 0;
    151  1.1     elric     changeset = NULL;
    152  1.1     elric 
    153  1.1     elric     ret = krb5_kt_start_seq_get(context, keytab, &cursor);
    154  1.1     elric     if(ret){
    155  1.1     elric 	krb5_warn(context, ret, "%s", keytab_string);
    156  1.1     elric 	goto out;
    157  1.1     elric     }
    158  1.1     elric 
    159  1.1     elric     while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) {
    160  1.1     elric 	int add = 0;
    161  1.1     elric 
    162  1.1     elric 	for (i = 0; i < j; ++i) {
    163  1.1     elric 	    if (krb5_principal_compare (context, changeset[i].principal,
    164  1.1     elric 					entry.principal)) {
    165  1.1     elric 		if (changeset[i].kvno < entry.vno)
    166  1.1     elric 		    changeset[i].kvno = entry.vno;
    167  1.1     elric 		break;
    168  1.1     elric 	    }
    169  1.1     elric 	}
    170  1.1     elric 	if (i < j) {
    171  1.1     elric 	    krb5_kt_free_entry (context, &entry);
    172  1.1     elric 	    continue;
    173  1.1     elric 	}
    174  1.1     elric 
    175  1.1     elric 	if (argc == 0) {
    176  1.1     elric 	    add = 1;
    177  1.1     elric 	} else {
    178  1.1     elric 	    for (i = 0; i < argc; ++i) {
    179  1.1     elric 		krb5_principal princ;
    180  1.1     elric 
    181  1.1     elric 		ret = krb5_parse_name (context, argv[i], &princ);
    182  1.1     elric 		if (ret) {
    183  1.1     elric 		    krb5_warn (context, ret, "%s", argv[i]);
    184  1.1     elric 		    continue;
    185  1.1     elric 		}
    186  1.1     elric 		if (krb5_principal_compare (context, princ, entry.principal))
    187  1.1     elric 		    add = 1;
    188  1.1     elric 
    189  1.1     elric 		krb5_free_principal (context, princ);
    190  1.1     elric 	    }
    191  1.1     elric 	}
    192  1.1     elric 
    193  1.1     elric 	if (add) {
    194  1.1     elric 	    if (j >= max) {
    195  1.1     elric 		void *tmp;
    196  1.1     elric 
    197  1.1     elric 		max = max(max * 2, 1);
    198  1.1     elric 		tmp = realloc (changeset, max * sizeof(*changeset));
    199  1.1     elric 		if (tmp == NULL) {
    200  1.1     elric 		    krb5_kt_free_entry (context, &entry);
    201  1.1     elric 		    krb5_warnx (context, "realloc: out of memory");
    202  1.1     elric 		    ret = ENOMEM;
    203  1.1     elric 		    break;
    204  1.1     elric 		}
    205  1.1     elric 		changeset = tmp;
    206  1.1     elric 	    }
    207  1.1     elric 	    ret = krb5_copy_principal (context, entry.principal,
    208  1.1     elric 				       &changeset[j].principal);
    209  1.1     elric 	    if (ret) {
    210  1.1     elric 		krb5_warn (context, ret, "krb5_copy_principal");
    211  1.1     elric 		krb5_kt_free_entry (context, &entry);
    212  1.1     elric 		break;
    213  1.1     elric 	    }
    214  1.1     elric 	    changeset[j].kvno = entry.vno;
    215  1.1     elric 	    ++j;
    216  1.1     elric 	}
    217  1.1     elric 	krb5_kt_free_entry (context, &entry);
    218  1.1     elric     }
    219  1.1     elric     krb5_kt_end_seq_get(context, keytab, &cursor);
    220  1.1     elric 
    221  1.1     elric     if (ret == KRB5_KT_END) {
    222  1.1     elric 	for (i = 0; i < j; i++) {
    223  1.1     elric 	    if (verbose_flag) {
    224  1.1     elric 		char *client_name;
    225  1.1     elric 
    226  1.1     elric 		ret = krb5_unparse_name (context, changeset[i].principal,
    227  1.1     elric 					 &client_name);
    228  1.1     elric 		if (ret) {
    229  1.1     elric 		    krb5_warn (context, ret, "krb5_unparse_name");
    230  1.1     elric 		} else {
    231  1.1     elric 		    printf("Changing %s kvno %d\n",
    232  1.1     elric 			   client_name, changeset[i].kvno);
    233  1.1     elric 		    free(client_name);
    234  1.1     elric 		}
    235  1.1     elric 	    }
    236  1.1     elric 	    ret = change_entry (keytab,
    237  1.1     elric 				changeset[i].principal, changeset[i].kvno,
    238  1.1     elric 				opt->realm_string,
    239  1.1     elric 				opt->admin_server_string,
    240  1.1     elric 				opt->server_port_integer);
    241  1.1     elric 	    if (ret != 0)
    242  1.1     elric 		errors = 1;
    243  1.1     elric 	}
    244  1.1     elric     } else
    245  1.1     elric 	errors = 1;
    246  1.1     elric     for (i = 0; i < j; i++)
    247  1.1     elric 	krb5_free_principal (context, changeset[i].principal);
    248  1.1     elric     free (changeset);
    249  1.1     elric 
    250  1.1     elric  out:
    251  1.1     elric     krb5_kt_close(context, keytab);
    252  1.1     elric     return errors;
    253  1.1     elric }
    254