1/* 2 * Copyright (c) 2001-2002 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "krb5_locl.h" 35 36#ifdef HEIM_KT_ANY 37 38struct any_data { 39 krb5_keytab kt; 40 char *name; 41 struct any_data *next; 42}; 43 44static void 45free_list (krb5_context context, struct any_data *a) 46{ 47 struct any_data *next; 48 49 for (; a != NULL; a = next) { 50 next = a->next; 51 free (a->name); 52 if(a->kt) 53 krb5_kt_close(context, a->kt); 54 free (a); 55 } 56} 57 58static krb5_error_code KRB5_CALLCONV 59any_resolve(krb5_context context, const char *name, krb5_keytab id) 60{ 61 struct any_data *a, *a0 = NULL, *prev = NULL; 62 krb5_error_code ret; 63 char buf[256]; 64 65 while (strsep_copy(&name, ",", buf, sizeof(buf)) != -1) { 66 a = calloc(1, sizeof(*a)); 67 if (a == NULL) { 68 ret = ENOMEM; 69 goto fail; 70 } 71 if (a0 == NULL) { 72 a0 = a; 73 a->name = strdup(buf); 74 if (a->name == NULL) { 75 ret = ENOMEM; 76 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 77 goto fail; 78 } 79 } else 80 a->name = NULL; 81 if (prev != NULL) 82 prev->next = a; 83 a->next = NULL; 84 ret = krb5_kt_resolve (context, buf, &a->kt); 85 if (ret) 86 goto fail; 87 prev = a; 88 } 89 if (a0 == NULL) { 90 krb5_set_error_message(context, ENOENT, N_("empty ANY: keytab", "")); 91 return ENOENT; 92 } 93 id->data = a0; 94 return 0; 95 fail: 96 free_list (context, a0); 97 return ret; 98} 99 100static krb5_error_code KRB5_CALLCONV 101any_get_name (krb5_context context, 102 krb5_keytab id, 103 char *name, 104 size_t namesize) 105{ 106 struct any_data *a = id->data; 107 strlcpy(name, a->name, namesize); 108 return 0; 109} 110 111static krb5_error_code KRB5_CALLCONV 112any_close (krb5_context context, 113 krb5_keytab id) 114{ 115 struct any_data *a = id->data; 116 117 free_list (context, a); 118 return 0; 119} 120 121struct any_cursor_extra_data { 122 struct any_data *a; 123 krb5_kt_cursor cursor; 124}; 125 126static krb5_error_code KRB5_CALLCONV 127any_start_seq_get(krb5_context context, 128 krb5_keytab id, 129 krb5_kt_cursor *c) 130{ 131 struct any_data *a = id->data; 132 struct any_cursor_extra_data *ed; 133 krb5_error_code ret; 134 135 c->data = malloc (sizeof(struct any_cursor_extra_data)); 136 if(c->data == NULL){ 137 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 138 return ENOMEM; 139 } 140 ed = (struct any_cursor_extra_data *)c->data; 141 for (ed->a = a; ed->a != NULL; ed->a = ed->a->next) { 142 ret = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor); 143 if (ret == 0) 144 break; 145 } 146 if (ed->a == NULL) { 147 free (c->data); 148 c->data = NULL; 149 krb5_clear_error_message (context); 150 return KRB5_KT_END; 151 } 152 return 0; 153} 154 155static krb5_error_code KRB5_CALLCONV 156any_next_entry (krb5_context context, 157 krb5_keytab id, 158 krb5_keytab_entry *entry, 159 krb5_kt_cursor *cursor) 160{ 161 krb5_error_code ret, ret2; 162 struct any_cursor_extra_data *ed; 163 164 ed = (struct any_cursor_extra_data *)cursor->data; 165 do { 166 ret = krb5_kt_next_entry(context, ed->a->kt, entry, &ed->cursor); 167 if (ret == 0) 168 return 0; 169 else if (ret != KRB5_KT_END) 170 return ret; 171 172 ret2 = krb5_kt_end_seq_get (context, ed->a->kt, &ed->cursor); 173 if (ret2) 174 return ret2; 175 while ((ed->a = ed->a->next) != NULL) { 176 ret2 = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor); 177 if (ret2 == 0) 178 break; 179 } 180 if (ed->a == NULL) { 181 krb5_clear_error_message (context); 182 return KRB5_KT_END; 183 } 184 } while (1); 185} 186 187static krb5_error_code KRB5_CALLCONV 188any_end_seq_get(krb5_context context, 189 krb5_keytab id, 190 krb5_kt_cursor *cursor) 191{ 192 krb5_error_code ret = 0; 193 struct any_cursor_extra_data *ed; 194 195 ed = (struct any_cursor_extra_data *)cursor->data; 196 if (ed->a != NULL) 197 ret = krb5_kt_end_seq_get(context, ed->a->kt, &ed->cursor); 198 free (ed); 199 cursor->data = NULL; 200 return ret; 201} 202 203static krb5_error_code KRB5_CALLCONV 204any_add_entry(krb5_context context, 205 krb5_keytab id, 206 krb5_keytab_entry *entry) 207{ 208 struct any_data *a = id->data; 209 krb5_error_code ret; 210 while(a != NULL) { 211 ret = krb5_kt_add_entry(context, a->kt, entry); 212 if(ret != 0 && ret != KRB5_KT_NOWRITE) { 213 krb5_set_error_message(context, ret, 214 N_("failed to add entry to %s", ""), 215 a->name); 216 return ret; 217 } 218 a = a->next; 219 } 220 return 0; 221} 222 223static krb5_error_code KRB5_CALLCONV 224any_remove_entry(krb5_context context, 225 krb5_keytab id, 226 krb5_keytab_entry *entry) 227{ 228 struct any_data *a = id->data; 229 krb5_error_code ret; 230 int found = 0; 231 while(a != NULL) { 232 ret = krb5_kt_remove_entry(context, a->kt, entry); 233 if(ret == 0) 234 found++; 235 else { 236 if(ret != KRB5_KT_NOWRITE && ret != KRB5_KT_NOTFOUND) { 237 krb5_set_error_message(context, ret, 238 N_("Failed to remove keytab " 239 "entry from %s", "keytab name"), 240 a->name); 241 return ret; 242 } 243 } 244 a = a->next; 245 } 246 if(!found) 247 return KRB5_KT_NOTFOUND; 248 return 0; 249} 250 251const krb5_kt_ops krb5_any_ops = { 252 "ANY", 253 any_resolve, 254 any_get_name, 255 any_close, 256 NULL, /* destroy */ 257 NULL, /* get */ 258 any_start_seq_get, 259 any_next_entry, 260 any_end_seq_get, 261 any_add_entry, 262 any_remove_entry 263}; 264 265#endif /* HEIM_KT_ANY */ 266