1 /* 2 * Copyright (c) 1997 - 2000 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_keyfile.c,v 1.7 2000/01/02 04:00:22 assar Exp $"); 37 38 /* afs keyfile operations --------------------------------------- */ 39 40 /* 41 * Minimum tools to handle the AFS KeyFile. 42 * 43 * Format of the KeyFile is: 44 * <int32_t numkeys> {[<int32_t kvno> <char[8] deskey>] * numkeys} 45 * 46 * It just adds to the end of the keyfile, deleting isn't implemented. 47 * Use your favorite text/hex editor to delete keys. 48 * 49 */ 50 51 #define AFS_SERVERTHISCELL "/usr/afs/etc/ThisCell" 52 #define AFS_SERVERMAGICKRBCONF "/usr/afs/etc/krb.conf" 53 54 struct akf_data { 55 int num_entries; 56 char *filename; 57 char *cell; 58 char *realm; 59 }; 60 61 /* 62 * set `d->cell' and `d->realm' 63 */ 64 65 static int 66 get_cell_and_realm (struct akf_data *d) 67 { 68 FILE *f; 69 char buf[BUFSIZ], *cp; 70 71 f = fopen (AFS_SERVERTHISCELL, "r"); 72 if (f == NULL) 73 return errno; 74 if (fgets (buf, sizeof(buf), f) == NULL) { 75 fclose (f); 76 return EINVAL; 77 } 78 if (buf[strlen(buf) - 1] == '\n') 79 buf[strlen(buf) - 1] = '\0'; 80 fclose(f); 81 82 d->cell = strdup (buf); 83 if (d->cell == NULL) 84 return errno; 85 86 f = fopen (AFS_SERVERMAGICKRBCONF, "r"); 87 if (f != NULL) { 88 if (fgets (buf, sizeof(buf), f) == NULL) { 89 fclose (f); 90 return EINVAL; 91 } 92 if (buf[strlen(buf)-1] == '\n') 93 buf[strlen(buf)-1] = '\0'; 94 fclose(f); 95 } 96 /* uppercase */ 97 for (cp = buf; *cp != '\0'; cp++) 98 *cp = toupper(*cp); 99 100 d->realm = strdup (buf); 101 if (d->realm == NULL) { 102 free (d->cell); 103 return errno; 104 } 105 return 0; 106 } 107 108 /* 109 * init and get filename 110 */ 111 112 static krb5_error_code 113 akf_resolve(krb5_context context, const char *name, krb5_keytab id) 114 { 115 int ret; 116 struct akf_data *d = malloc(sizeof (struct akf_data)); 117 118 if (d == NULL) 119 return errno; 120 121 d->num_entries = 0; 122 ret = get_cell_and_realm (d); 123 if (ret) { 124 free (d); 125 return ret; 126 } 127 d->filename = strdup (name); 128 if (d->filename == NULL) { 129 free (d->cell); 130 free (d->realm); 131 free (d); 132 return ENOMEM; 133 } 134 id->data = d; 135 136 return 0; 137 } 138 139 /* 140 * cleanup 141 */ 142 143 static krb5_error_code 144 akf_close(krb5_context context, krb5_keytab id) 145 { 146 struct akf_data *d = id->data; 147 148 free (d->filename); 149 free (d->cell); 150 free (d); 151 return 0; 152 } 153 154 /* 155 * Return filename 156 */ 157 158 static krb5_error_code 159 akf_get_name(krb5_context context, 160 krb5_keytab id, 161 char *name, 162 size_t name_sz) 163 { 164 struct akf_data *d = id->data; 165 166 strlcpy (name, d->filename, name_sz); 167 return 0; 168 } 169 170 /* 171 * Init 172 */ 173 174 static krb5_error_code 175 akf_start_seq_get(krb5_context context, 176 krb5_keytab id, 177 krb5_kt_cursor *c) 178 { 179 int32_t ret; 180 struct akf_data *d = id->data; 181 182 c->fd = open (d->filename, O_RDONLY|O_BINARY, 0600); 183 if (c->fd < 0) 184 return errno; 185 186 c->sp = krb5_storage_from_fd(c->fd); 187 ret = krb5_ret_int32(c->sp, &d->num_entries); 188 if(ret) { 189 krb5_storage_free(c->sp); 190 close(c->fd); 191 return ret; 192 } 193 194 return 0; 195 } 196 197 static krb5_error_code 198 akf_next_entry(krb5_context context, 199 krb5_keytab id, 200 krb5_keytab_entry *entry, 201 krb5_kt_cursor *cursor) 202 { 203 struct akf_data *d = id->data; 204 int32_t kvno; 205 off_t pos; 206 int ret; 207 208 pos = cursor->sp->seek(cursor->sp, 0, SEEK_CUR); 209 210 if ((pos - 4) / (4 + 8) >= d->num_entries) 211 return KRB5_KT_END; 212 213 ret = krb5_make_principal (context, &entry->principal, 214 d->realm, "afs", d->cell, NULL); 215 if (ret) 216 goto out; 217 218 ret = krb5_ret_int32(cursor->sp, &kvno); 219 if (ret) { 220 krb5_free_principal (context, entry->principal); 221 goto out; 222 } 223 224 entry->vno = (int8_t) kvno; 225 226 entry->keyblock.keytype = ETYPE_DES_CBC_MD5; 227 entry->keyblock.keyvalue.length = 8; 228 entry->keyblock.keyvalue.data = malloc (8); 229 if (entry->keyblock.keyvalue.data == NULL) { 230 krb5_free_principal (context, entry->principal); 231 ret = ENOMEM; 232 goto out; 233 } 234 235 ret = cursor->sp->fetch(cursor->sp, entry->keyblock.keyvalue.data, 8); 236 if(ret != 8) 237 ret = (ret < 0) ? errno : KRB5_KT_END; 238 239 entry->timestamp = time(NULL); 240 241 out: 242 cursor->sp->seek(cursor->sp, pos + 4 + 8, SEEK_SET); 243 return ret; 244 } 245 246 static krb5_error_code 247 akf_end_seq_get(krb5_context context, 248 krb5_keytab id, 249 krb5_kt_cursor *cursor) 250 { 251 krb5_storage_free(cursor->sp); 252 close(cursor->fd); 253 return 0; 254 } 255 256 static krb5_error_code 257 akf_add_entry(krb5_context context, 258 krb5_keytab id, 259 krb5_keytab_entry *entry) 260 { 261 struct akf_data *d = id->data; 262 int fd, created = 0; 263 int32_t kvno; 264 265 fd = open (d->filename, O_RDWR | O_BINARY); 266 if (fd < 0) { 267 fd = open (d->filename, 268 O_RDWR | O_BINARY | O_CREAT, 0600); 269 if (fd < 0) 270 return errno; 271 created = 1; 272 } 273 274 if (entry->keyblock.keyvalue.length == 8 275 && entry->keyblock.keytype == ETYPE_DES_CBC_MD5) { 276 277 int32_t len = 0; 278 279 if (!created) { 280 if (lseek (fd, 0, SEEK_SET)) 281 return errno; 282 283 if (read (fd, &len, sizeof(len)) != sizeof(len)) 284 return errno; 285 } 286 len += 1; 287 288 if (lseek (fd, 0, SEEK_SET)) 289 return errno; 290 291 if (write (fd, &len, sizeof(len)) != sizeof(len)) 292 return errno; 293 294 if (lseek (fd, 4 + (len-1) * (8+4), SEEK_SET)) 295 return errno; 296 297 kvno = entry->vno; 298 write(fd, &kvno, sizeof(kvno)); 299 write(fd, entry->keyblock.keyvalue.data, 8); 300 } 301 close (fd); 302 return 0; 303 } 304 305 const krb5_kt_ops krb5_akf_ops = { 306 "AFSKEYFILE", 307 akf_resolve, 308 akf_get_name, 309 akf_close, 310 NULL, /* get */ 311 akf_start_seq_get, 312 akf_next_entry, 313 akf_end_seq_get, 314 akf_add_entry, 315 NULL /* remove */ 316 }; 317