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.5 2002/02/11 14:05:37 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 (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 free (a); 53 } 54 } 55 56 static krb5_error_code 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 = malloc(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 krb5_set_error_string(context, "malloc: out of memory"); 74 ret = ENOMEM; 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_string(context, "empty ANY: keytab"); 89 return ENOENT; 90 } 91 id->data = a0; 92 return 0; 93 fail: 94 free_list (a0); 95 return ret; 96 } 97 98 static krb5_error_code 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 110 any_close (krb5_context context, 111 krb5_keytab id) 112 { 113 struct any_data *a = id->data; 114 115 free_list (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 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_string (context, "malloc: out of memory"); 136 return ENOMEM; 137 } 138 ed = (struct any_cursor_extra_data *)c->data; 139 ed->a = a; 140 ret = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor); 141 if (ret) { 142 free (c->data); 143 c->data = NULL; 144 return ret; 145 } 146 return 0; 147 } 148 149 static krb5_error_code 150 any_next_entry (krb5_context context, 151 krb5_keytab id, 152 krb5_keytab_entry *entry, 153 krb5_kt_cursor *cursor) 154 { 155 krb5_error_code ret, ret2; 156 struct any_cursor_extra_data *ed; 157 158 ed = (struct any_cursor_extra_data *)cursor->data; 159 do { 160 ret = krb5_kt_next_entry(context, ed->a->kt, entry, &ed->cursor); 161 if (ret == 0) 162 return 0; 163 else if (ret == KRB5_CC_END) { 164 ret2 = krb5_kt_end_seq_get (context, ed->a->kt, &ed->cursor); 165 if (ret2) 166 return ret2; 167 while ((ed->a = ed->a->next) != NULL) { 168 ret2 = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor); 169 if (ret2 == 0) 170 break; 171 } 172 if (ed->a == NULL) { 173 krb5_clear_error_string (context); 174 return KRB5_CC_END; 175 } 176 } else 177 return ret; 178 } while (ret == KRB5_CC_END); 179 return ret; 180 } 181 182 static krb5_error_code 183 any_end_seq_get(krb5_context context, 184 krb5_keytab id, 185 krb5_kt_cursor *cursor) 186 { 187 krb5_error_code ret = 0; 188 struct any_cursor_extra_data *ed; 189 190 ed = (struct any_cursor_extra_data *)cursor->data; 191 if (ed->a != NULL) 192 ret = krb5_kt_end_seq_get(context, ed->a->kt, &ed->cursor); 193 free (ed); 194 cursor->data = NULL; 195 return ret; 196 } 197 198 static krb5_error_code 199 any_add_entry(krb5_context context, 200 krb5_keytab id, 201 krb5_keytab_entry *entry) 202 { 203 struct any_data *a = id->data; 204 krb5_error_code ret; 205 while(a != NULL) { 206 ret = krb5_kt_add_entry(context, a->kt, entry); 207 if(ret != 0 && ret != KRB5_KT_NOWRITE) { 208 krb5_set_error_string(context, "failed to add entry to %s", 209 a->name); 210 return ret; 211 } 212 a = a->next; 213 } 214 return 0; 215 } 216 217 static krb5_error_code 218 any_remove_entry(krb5_context context, 219 krb5_keytab id, 220 krb5_keytab_entry *entry) 221 { 222 struct any_data *a = id->data; 223 krb5_error_code ret; 224 int found = 0; 225 while(a != NULL) { 226 ret = krb5_kt_remove_entry(context, a->kt, entry); 227 if(ret == 0) 228 found++; 229 else { 230 if(ret != KRB5_KT_NOWRITE && ret != KRB5_KT_NOTFOUND) { 231 krb5_set_error_string(context, "failed to remove entry from %s", 232 a->name); 233 return ret; 234 } 235 } 236 a = a->next; 237 } 238 if(!found) 239 return KRB5_KT_NOTFOUND; 240 return 0; 241 } 242 243 const krb5_kt_ops krb5_any_ops = { 244 "ANY", 245 any_resolve, 246 any_get_name, 247 any_close, 248 NULL, /* get */ 249 any_start_seq_get, 250 any_next_entry, 251 any_end_seq_get, 252 any_add_entry, 253 any_remove_entry 254 }; 255