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 struct any_data { 37 krb5_keytab kt; 38 char *name; 39 struct any_data *next; 40 }; 41 42 static void 43 free_list (krb5_context context, struct any_data *a) 44 { 45 struct any_data *next; 46 47 for (; a != NULL; a = next) { 48 next = a->next; 49 free (a->name); 50 if(a->kt) 51 krb5_kt_close(context, a->kt); 52 free (a); 53 } 54 } 55 56 static krb5_error_code KRB5_CALLCONV 57 any_resolve(krb5_context context, const char *name, krb5_keytab id) 58 { 59 struct any_data *a, *a0 = NULL, *prev = NULL; 60 krb5_error_code ret; 61 char buf[256]; 62 63 while (strsep_copy(&name, ",", buf, sizeof(buf)) != -1) { 64 a = calloc(1, sizeof(*a)); 65 if (a == NULL) { 66 ret = ENOMEM; 67 goto fail; 68 } 69 if (a0 == NULL) { 70 a0 = a; 71 a->name = strdup(buf); 72 if (a->name == NULL) { 73 ret = ENOMEM; 74 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 75 goto fail; 76 } 77 } else 78 a->name = NULL; 79 if (prev != NULL) 80 prev->next = a; 81 a->next = NULL; 82 ret = krb5_kt_resolve (context, buf, &a->kt); 83 if (ret) 84 goto fail; 85 prev = a; 86 } 87 if (a0 == NULL) { 88 krb5_set_error_message(context, ENOENT, N_("empty ANY: keytab", "")); 89 return ENOENT; 90 } 91 id->data = a0; 92 return 0; 93 fail: 94 free_list (context, a0); 95 return ret; 96 } 97 98 static krb5_error_code KRB5_CALLCONV 99 any_get_name (krb5_context context, 100 krb5_keytab id, 101 char *name, 102 size_t namesize) 103 { 104 struct any_data *a = id->data; 105 strlcpy(name, a->name, namesize); 106 return 0; 107 } 108 109 static krb5_error_code KRB5_CALLCONV 110 any_close (krb5_context context, 111 krb5_keytab id) 112 { 113 struct any_data *a = id->data; 114 115 free_list (context, a); 116 return 0; 117 } 118 119 struct any_cursor_extra_data { 120 struct any_data *a; 121 krb5_kt_cursor cursor; 122 }; 123 124 static krb5_error_code KRB5_CALLCONV 125 any_start_seq_get(krb5_context context, 126 krb5_keytab id, 127 krb5_kt_cursor *c) 128 { 129 struct any_data *a = id->data; 130 struct any_cursor_extra_data *ed; 131 krb5_error_code ret; 132 133 c->data = malloc (sizeof(struct any_cursor_extra_data)); 134 if(c->data == NULL){ 135 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 136 return ENOMEM; 137 } 138 ed = (struct any_cursor_extra_data *)c->data; 139 for (ed->a = a; ed->a != NULL; ed->a = ed->a->next) { 140 ret = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor); 141 if (ret == 0) 142 break; 143 } 144 if (ed->a == NULL) { 145 free (c->data); 146 c->data = NULL; 147 krb5_clear_error_message (context); 148 return KRB5_KT_END; 149 } 150 return 0; 151 } 152 153 static krb5_error_code KRB5_CALLCONV 154 any_next_entry (krb5_context context, 155 krb5_keytab id, 156 krb5_keytab_entry *entry, 157 krb5_kt_cursor *cursor) 158 { 159 krb5_error_code ret, ret2; 160 struct any_cursor_extra_data *ed; 161 162 ed = (struct any_cursor_extra_data *)cursor->data; 163 do { 164 ret = krb5_kt_next_entry(context, ed->a->kt, entry, &ed->cursor); 165 if (ret == 0) 166 return 0; 167 else if (ret != KRB5_KT_END) 168 return ret; 169 170 ret2 = krb5_kt_end_seq_get (context, ed->a->kt, &ed->cursor); 171 if (ret2) 172 return ret2; 173 while ((ed->a = ed->a->next) != NULL) { 174 ret2 = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor); 175 if (ret2 == 0) 176 break; 177 } 178 if (ed->a == NULL) { 179 krb5_clear_error_message (context); 180 return KRB5_KT_END; 181 } 182 } while (1); 183 } 184 185 static krb5_error_code KRB5_CALLCONV 186 any_end_seq_get(krb5_context context, 187 krb5_keytab id, 188 krb5_kt_cursor *cursor) 189 { 190 krb5_error_code ret = 0; 191 struct any_cursor_extra_data *ed; 192 193 ed = (struct any_cursor_extra_data *)cursor->data; 194 if (ed->a != NULL) 195 ret = krb5_kt_end_seq_get(context, ed->a->kt, &ed->cursor); 196 free (ed); 197 cursor->data = NULL; 198 return ret; 199 } 200 201 static krb5_error_code KRB5_CALLCONV 202 any_add_entry(krb5_context context, 203 krb5_keytab id, 204 krb5_keytab_entry *entry) 205 { 206 struct any_data *a = id->data; 207 krb5_error_code ret; 208 while(a != NULL) { 209 ret = krb5_kt_add_entry(context, a->kt, entry); 210 if(ret != 0 && ret != KRB5_KT_NOWRITE) { 211 krb5_set_error_message(context, ret, 212 N_("failed to add entry to %s", ""), 213 a->name); 214 return ret; 215 } 216 a = a->next; 217 } 218 return 0; 219 } 220 221 static krb5_error_code KRB5_CALLCONV 222 any_remove_entry(krb5_context context, 223 krb5_keytab id, 224 krb5_keytab_entry *entry) 225 { 226 struct any_data *a = id->data; 227 krb5_error_code ret; 228 int found = 0; 229 while(a != NULL) { 230 ret = krb5_kt_remove_entry(context, a->kt, entry); 231 if(ret == 0) 232 found++; 233 else { 234 if(ret != KRB5_KT_NOWRITE && ret != KRB5_KT_NOTFOUND) { 235 krb5_set_error_message(context, ret, 236 N_("Failed to remove keytab " 237 "entry from %s", "keytab name"), 238 a->name); 239 return ret; 240 } 241 } 242 a = a->next; 243 } 244 if(!found) 245 return KRB5_KT_NOTFOUND; 246 return 0; 247 } 248 249 const krb5_kt_ops krb5_any_ops = { 250 "ANY", 251 any_resolve, 252 any_get_name, 253 any_close, 254 NULL, /* destroy */ 255 NULL, /* get */ 256 any_start_seq_get, 257 any_next_entry, 258 any_end_seq_get, 259 any_add_entry, 260 any_remove_entry 261 }; 262