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