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 17035 2006-04-10 09:20:13Z lha $"); 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 return ret; 167 168 ret2 = krb5_kt_end_seq_get (context, ed->a->kt, &ed->cursor); 169 if (ret2) 170 return ret2; 171 while ((ed->a = ed->a->next) != NULL) { 172 ret2 = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor); 173 if (ret2 == 0) 174 break; 175 } 176 if (ed->a == NULL) { 177 krb5_clear_error_string (context); 178 return KRB5_KT_END; 179 } 180 } while (1); 181 } 182 183 static krb5_error_code 184 any_end_seq_get(krb5_context context, 185 krb5_keytab id, 186 krb5_kt_cursor *cursor) 187 { 188 krb5_error_code ret = 0; 189 struct any_cursor_extra_data *ed; 190 191 ed = (struct any_cursor_extra_data *)cursor->data; 192 if (ed->a != NULL) 193 ret = krb5_kt_end_seq_get(context, ed->a->kt, &ed->cursor); 194 free (ed); 195 cursor->data = NULL; 196 return ret; 197 } 198 199 static krb5_error_code 200 any_add_entry(krb5_context context, 201 krb5_keytab id, 202 krb5_keytab_entry *entry) 203 { 204 struct any_data *a = id->data; 205 krb5_error_code ret; 206 while(a != NULL) { 207 ret = krb5_kt_add_entry(context, a->kt, entry); 208 if(ret != 0 && ret != KRB5_KT_NOWRITE) { 209 krb5_set_error_string(context, "failed to add entry to %s", 210 a->name); 211 return ret; 212 } 213 a = a->next; 214 } 215 return 0; 216 } 217 218 static krb5_error_code 219 any_remove_entry(krb5_context context, 220 krb5_keytab id, 221 krb5_keytab_entry *entry) 222 { 223 struct any_data *a = id->data; 224 krb5_error_code ret; 225 int found = 0; 226 while(a != NULL) { 227 ret = krb5_kt_remove_entry(context, a->kt, entry); 228 if(ret == 0) 229 found++; 230 else { 231 if(ret != KRB5_KT_NOWRITE && ret != KRB5_KT_NOTFOUND) { 232 krb5_set_error_string(context, "failed to remove entry from %s", 233 a->name); 234 return ret; 235 } 236 } 237 a = a->next; 238 } 239 if(!found) 240 return KRB5_KT_NOTFOUND; 241 return 0; 242 } 243 244 const krb5_kt_ops krb5_any_ops = { 245 "ANY", 246 any_resolve, 247 any_get_name, 248 any_close, 249 NULL, /* get */ 250 any_start_seq_get, 251 any_next_entry, 252 any_end_seq_get, 253 any_add_entry, 254 any_remove_entry 255 }; 256