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 RCSID("$Id: keytab_any.c,v 1.7 2002/10/21 13:36:59 joda Exp $"); 37 38 struct any_data { 39 krb5_keytab kt; 40 char *name; 41 struct any_data *next; 42 }; 43 44 static void 45 free_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 58 static krb5_error_code 59 any_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 = malloc(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 krb5_set_error_string(context, "malloc: out of memory"); 76 ret = ENOMEM; 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_string(context, "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 100 static krb5_error_code 101 any_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 111 static krb5_error_code 112 any_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 121 struct any_cursor_extra_data { 122 struct any_data *a; 123 krb5_kt_cursor cursor; 124 }; 125 126 static krb5_error_code 127 any_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_string (context, "malloc: out of memory"); 138 return ENOMEM; 139 } 140 ed = (struct any_cursor_extra_data *)c->data; 141 ed->a = a; 142 ret = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor); 143 if (ret) { 144 free (c->data); 145 c->data = NULL; 146 return ret; 147 } 148 return 0; 149 } 150 151 static krb5_error_code 152 any_next_entry (krb5_context context, 153 krb5_keytab id, 154 krb5_keytab_entry *entry, 155 krb5_kt_cursor *cursor) 156 { 157 krb5_error_code ret, ret2; 158 struct any_cursor_extra_data *ed; 159 160 ed = (struct any_cursor_extra_data *)cursor->data; 161 do { 162 ret = krb5_kt_next_entry(context, ed->a->kt, entry, &ed->cursor); 163 if (ret == 0) 164 return 0; 165 else if (ret == KRB5_KT_END) { 166 ret2 = krb5_kt_end_seq_get (context, ed->a->kt, &ed->cursor); 167 if (ret2) 168 return ret2; 169 while ((ed->a = ed->a->next) != NULL) { 170 ret2 = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor); 171 if (ret2 == 0) 172 break; 173 } 174 if (ed->a == NULL) { 175 krb5_clear_error_string (context); 176 return KRB5_KT_END; 177 } 178 } else 179 return ret; 180 } while (ret == KRB5_KT_END); 181 return ret; 182 } 183 184 static krb5_error_code 185 any_end_seq_get(krb5_context context, 186 krb5_keytab id, 187 krb5_kt_cursor *cursor) 188 { 189 krb5_error_code ret = 0; 190 struct any_cursor_extra_data *ed; 191 192 ed = (struct any_cursor_extra_data *)cursor->data; 193 if (ed->a != NULL) 194 ret = krb5_kt_end_seq_get(context, ed->a->kt, &ed->cursor); 195 free (ed); 196 cursor->data = NULL; 197 return ret; 198 } 199 200 static krb5_error_code 201 any_add_entry(krb5_context context, 202 krb5_keytab id, 203 krb5_keytab_entry *entry) 204 { 205 struct any_data *a = id->data; 206 krb5_error_code ret; 207 while(a != NULL) { 208 ret = krb5_kt_add_entry(context, a->kt, entry); 209 if(ret != 0 && ret != KRB5_KT_NOWRITE) { 210 krb5_set_error_string(context, "failed to add entry to %s", 211 a->name); 212 return ret; 213 } 214 a = a->next; 215 } 216 return 0; 217 } 218 219 static krb5_error_code 220 any_remove_entry(krb5_context context, 221 krb5_keytab id, 222 krb5_keytab_entry *entry) 223 { 224 struct any_data *a = id->data; 225 krb5_error_code ret; 226 int found = 0; 227 while(a != NULL) { 228 ret = krb5_kt_remove_entry(context, a->kt, entry); 229 if(ret == 0) 230 found++; 231 else { 232 if(ret != KRB5_KT_NOWRITE && ret != KRB5_KT_NOTFOUND) { 233 krb5_set_error_string(context, "failed to remove entry from %s", 234 a->name); 235 return ret; 236 } 237 } 238 a = a->next; 239 } 240 if(!found) 241 return KRB5_KT_NOTFOUND; 242 return 0; 243 } 244 245 const krb5_kt_ops krb5_any_ops = { 246 "ANY", 247 any_resolve, 248 any_get_name, 249 any_close, 250 NULL, /* get */ 251 any_start_seq_get, 252 any_next_entry, 253 any_end_seq_get, 254 any_add_entry, 255 any_remove_entry 256 }; 257