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 38struct any_data { 39 krb5_keytab kt; 40 char *name; 41 struct any_data *next; 42}; 43 44static void 45free_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 58static krb5_error_code KRB5_CALLCONV 59any_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 99static krb5_error_code KRB5_CALLCONV 100any_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 110static krb5_error_code KRB5_CALLCONV 111any_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 120struct any_cursor_extra_data { 121 struct any_data *a; 122 krb5_kt_cursor cursor; 123}; 124 125static krb5_error_code KRB5_CALLCONV 126any_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 152static krb5_error_code KRB5_CALLCONV 153any_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 184static krb5_error_code KRB5_CALLCONV 185any_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 200static krb5_error_code KRB5_CALLCONV 201any_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 220static krb5_error_code KRB5_CALLCONV 221any_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 248const 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