1/* 2 * Copyright (c) 1997 - 2005 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 "heim.h" 35#include <string.h> 36#include <errno.h> 37 38mit_krb5_error_code KRB5_CALLCONV 39krb5_kt_start_seq_get(mit_krb5_context context, mit_krb5_keytab keytab, 40 mit_krb5_kt_cursor *cursor) 41{ 42 krb5_error_code ret; 43 44 LOG_ENTRY(); 45 46 *cursor = calloc(1, sizeof(krb5_kt_cursor)); 47 48 ret = heim_krb5_kt_start_seq_get(HC(context), (krb5_keytab)keytab, (krb5_kt_cursor *)*cursor); 49 if (ret) { 50 free(*cursor); 51 *cursor = NULL; 52 } 53 return ret; 54} 55 56mit_krb5_error_code KRB5_CALLCONV 57krb5_kt_next_entry(mit_krb5_context context, mit_krb5_keytab keytab, 58 mit_krb5_keytab_entry *entry, mit_krb5_kt_cursor *cursor) 59{ 60 krb5_error_code ret; 61 krb5_keytab_entry e; 62 63 LOG_ENTRY(); 64 65 ret = heim_krb5_kt_next_entry(HC(context), (krb5_keytab)keytab, 66 &e, (krb5_kt_cursor *)*cursor); 67 if (ret) 68 return ret; 69 70 entry->magic = 0; 71 entry->principal = mshim_hprinc2mprinc(HC(context), e.principal); 72 entry->timestamp = e.timestamp; 73 entry->vno = e.vno; 74 mshim_hkeyblock2mkeyblock(&e.keyblock, &entry->key); 75 76 heim_krb5_kt_free_entry(HC(context), &e); 77 78 return 0; 79} 80 81mit_krb5_error_code KRB5_CALLCONV 82krb5_free_keytab_entry_contents(mit_krb5_context context, 83 mit_krb5_keytab_entry *entry) 84{ 85 int eric = entry->vno; 86 LOG_ENTRY(); 87 88 krb5_free_principal(context, entry->principal); 89 memset(entry->key.contents, 0, entry->key.length); 90 free(entry->key.contents); 91 memset(entry, 0, sizeof(*entry)); 92 entry->vno = eric; 93 94 return 0; 95} 96 97 98mit_krb5_error_code KRB5_CALLCONV 99krb5_kt_end_seq_get(mit_krb5_context context, mit_krb5_keytab keytab, 100 mit_krb5_kt_cursor *cursor) 101{ 102 krb5_error_code ret; 103 104 LOG_ENTRY(); 105 106 ret = heim_krb5_kt_end_seq_get(HC(context), (krb5_keytab)keytab, (krb5_kt_cursor *)*cursor); 107 free(*cursor); 108 *cursor = NULL; 109 110 return ret; 111} 112 113static int 114krb5_kt_compare(mit_krb5_context context, 115 mit_krb5_keytab_entry *entry, 116 mit_krb5_const_principal principal, 117 mit_krb5_kvno vno, 118 mit_krb5_enctype enctype) 119{ 120 LOG_ENTRY(); 121 122 if(principal != NULL && 123 !krb5_principal_compare(context, entry->principal, principal)) 124 return 0; 125 if(vno && vno != entry->vno) 126 return 0; 127 if(enctype && enctype != entry->key.enctype) 128 return 0; 129 return 1; 130} 131 132static mit_krb5_error_code 133krb5_kt_free_entry(mit_krb5_context context, 134 mit_krb5_keytab_entry *entry) 135{ 136 LOG_ENTRY(); 137 138 krb5_free_principal (context, entry->principal); 139 krb5_free_keyblock_contents (context, &entry->key); 140 memset(entry, 0, sizeof(*entry)); 141 return 0; 142} 143 144static mit_krb5_error_code 145krb5_kt_copy_entry_contents(mit_krb5_context context, 146 const mit_krb5_keytab_entry *in, 147 mit_krb5_keytab_entry *out) 148{ 149 krb5_error_code ret; 150 151 LOG_ENTRY(); 152 153 memset(out, 0, sizeof(*out)); 154 out->vno = in->vno; 155 156 ret = krb5_copy_principal (context, in->principal, &out->principal); 157 if (ret) 158 goto fail; 159 ret = krb5_copy_keyblock_contents (context, &in->key, &out->key); 160 if (ret) 161 goto fail; 162 out->timestamp = in->timestamp; 163 return 0; 164fail: 165 krb5_kt_free_entry (context, out); 166 return ret; 167} 168 169 170mit_krb5_error_code KRB5_CALLCONV 171krb5_kt_get_entry(mit_krb5_context context, 172 mit_krb5_keytab id, 173 mit_krb5_const_principal principal, 174 mit_krb5_kvno kvno, 175 mit_krb5_enctype enctype, 176 mit_krb5_keytab_entry *entry) 177{ 178 mit_krb5_keytab_entry tmp; 179 mit_krb5_error_code ret; 180 mit_krb5_kt_cursor cursor; 181 182 LOG_ENTRY(); 183 184 memset(entry, 0, sizeof(*entry)); 185 186 ret = krb5_kt_start_seq_get (context, id, &cursor); 187 if (ret) 188 return KRB5_KT_NOTFOUND; 189 190 entry->vno = 0; 191 while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) { 192 if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) { 193 /* the file keytab might only store the lower 8 bits of 194 the kvno, so only compare those bits */ 195 if (kvno == tmp.vno 196 || (tmp.vno < 256 && kvno % 256 == tmp.vno)) { 197 krb5_kt_copy_entry_contents (context, &tmp, entry); 198 krb5_kt_free_entry (context, &tmp); 199 krb5_kt_end_seq_get(context, id, &cursor); 200 return 0; 201 } else if (kvno == 0 && tmp.vno > entry->vno) { 202 if (entry->vno) 203 krb5_kt_free_entry (context, entry); 204 krb5_kt_copy_entry_contents (context, &tmp, entry); 205 } 206 } 207 krb5_kt_free_entry(context, &tmp); 208 } 209 krb5_kt_end_seq_get (context, id, &cursor); 210 if (entry->vno == 0) 211 return KRB5_KT_NOTFOUND; 212 return 0; 213} 214 215mit_krb5_error_code KRB5_CALLCONV 216krb5_kt_get_name(mit_krb5_context context, 217 mit_krb5_keytab keytab, 218 char *name, 219 unsigned int namelen) 220{ 221 return heim_krb5_kt_get_name(HC(context), (krb5_keytab)keytab, name, namelen); 222} 223 224mit_krb5_error_code KRB5_CALLCONV 225krb5_kt_read_service_key(mit_krb5_context context, 226 mit_krb5_pointer keyprocarg, 227 mit_krb5_principal principal, 228 mit_krb5_kvno vno, 229 mit_krb5_enctype enctype, 230 mit_krb5_keyblock **key) 231{ 232 mit_krb5_keytab keytab; 233 mit_krb5_keytab_entry entry; 234 mit_krb5_error_code ret; 235 236 LOG_ENTRY(); 237 238 if (keyprocarg) 239 ret = krb5_kt_resolve (context, keyprocarg, &keytab); 240 else 241 ret = krb5_kt_default (context, &keytab); 242 243 if (ret) 244 return ret; 245 246 ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry); 247 krb5_kt_close (context, keytab); 248 if (ret) 249 return ret; 250 ret = krb5_copy_keyblock (context, &entry.key, key); 251 krb5_kt_free_entry(context, &entry); 252 return ret; 253} 254 255mit_krb5_error_code KRB5_LIB_FUNCTION 256krb5_kt_remove_entry(mit_krb5_context context, 257 mit_krb5_keytab id, 258 mit_krb5_keytab_entry *entry) 259{ 260 struct comb_principal *p = (struct comb_principal *)entry->principal; 261 krb5_keytab_entry e; 262 263 LOG_ENTRY(); 264 265 memset(&e, 0, sizeof(e)); 266 267 e.principal = p->heim; 268 e.vno = entry->vno; 269 e.timestamp = entry->timestamp; 270 271 return heim_krb5_kt_remove_entry(HC(context), (krb5_keytab)id, &e); 272} 273 274mit_krb5_error_code KRB5_CALLCONV 275krb5_kt_add_entry(mit_krb5_context context, 276 mit_krb5_keytab id, 277 mit_krb5_keytab_entry *entry) 278{ 279 struct comb_principal *p = (struct comb_principal *)entry->principal; 280 krb5_keytab_entry e; 281 282 LOG_ENTRY(); 283 284 memset(&e, 0, sizeof(e)); 285 286 e.principal = p->heim; 287 e.vno = entry->vno; 288 e.timestamp = entry->timestamp; 289 e.keyblock.keytype = entry->key.enctype; 290 e.keyblock.keyvalue.data = entry->key.contents; 291 e.keyblock.keyvalue.length = entry->key.length; 292 293 return heim_krb5_kt_add_entry(HC(context), (krb5_keytab)id, &e); 294} 295 296 297 298const char * KRB5_CALLCONV 299krb5_kt_get_type(mit_krb5_context context, mit_krb5_keytab id) 300{ 301 krb5_error_code ret; 302 static char name[80]; 303 304 LOG_ENTRY(); 305 306 ret = heim_krb5_kt_get_type (HC(context), 307 (krb5_keytab)id, 308 name, 309 sizeof(name)); 310 if (ret) 311 name[0] = '\0'; 312 return name; 313} 314