1 1.1 elric /* $NetBSD: ext.c,v 1.2 2017/01/28 21:31:48 christos Exp $ */ 2 1.1 elric 3 1.1 elric /* 4 1.1 elric * Copyright (c) 2004 - 2005 Kungliga Tekniska Hgskolan 5 1.1 elric * (Royal Institute of Technology, Stockholm, Sweden). 6 1.1 elric * All rights reserved. 7 1.1 elric * 8 1.1 elric * Redistribution and use in source and binary forms, with or without 9 1.1 elric * modification, are permitted provided that the following conditions 10 1.1 elric * are met: 11 1.1 elric * 12 1.1 elric * 1. Redistributions of source code must retain the above copyright 13 1.1 elric * notice, this list of conditions and the following disclaimer. 14 1.1 elric * 15 1.1 elric * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 elric * notice, this list of conditions and the following disclaimer in the 17 1.1 elric * documentation and/or other materials provided with the distribution. 18 1.1 elric * 19 1.1 elric * 3. Neither the name of the Institute nor the names of its contributors 20 1.1 elric * may be used to endorse or promote products derived from this software 21 1.1 elric * without specific prior written permission. 22 1.1 elric * 23 1.1 elric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 1.1 elric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.1 elric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.1 elric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 1.1 elric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.1 elric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.1 elric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.1 elric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.1 elric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.1 elric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.1 elric * SUCH DAMAGE. 34 1.1 elric */ 35 1.1 elric 36 1.1 elric #include "hdb_locl.h" 37 1.1 elric #include <krb5/der.h> 38 1.1 elric 39 1.1 elric krb5_error_code 40 1.1 elric hdb_entry_check_mandatory(krb5_context context, const hdb_entry *ent) 41 1.1 elric { 42 1.2 christos size_t i; 43 1.1 elric 44 1.1 elric if (ent->extensions == NULL) 45 1.1 elric return 0; 46 1.1 elric 47 1.1 elric /* 48 1.1 elric * check for unknown extensions and if they where tagged mandatory 49 1.1 elric */ 50 1.1 elric 51 1.1 elric for (i = 0; i < ent->extensions->len; i++) { 52 1.1 elric if (ent->extensions->val[i].data.element != 53 1.1 elric choice_HDB_extension_data_asn1_ellipsis) 54 1.1 elric continue; 55 1.1 elric if (ent->extensions->val[i].mandatory) { 56 1.1 elric krb5_set_error_message(context, HDB_ERR_MANDATORY_OPTION, 57 1.1 elric "Principal have unknown " 58 1.1 elric "mandatory extension"); 59 1.1 elric return HDB_ERR_MANDATORY_OPTION; 60 1.1 elric } 61 1.1 elric } 62 1.1 elric return 0; 63 1.1 elric } 64 1.1 elric 65 1.1 elric HDB_extension * 66 1.1 elric hdb_find_extension(const hdb_entry *entry, int type) 67 1.1 elric { 68 1.2 christos size_t i; 69 1.1 elric 70 1.1 elric if (entry->extensions == NULL) 71 1.1 elric return NULL; 72 1.1 elric 73 1.1 elric for (i = 0; i < entry->extensions->len; i++) 74 1.2 christos if (entry->extensions->val[i].data.element == (unsigned)type) 75 1.1 elric return &entry->extensions->val[i]; 76 1.1 elric return NULL; 77 1.1 elric } 78 1.1 elric 79 1.1 elric /* 80 1.1 elric * Replace the extension `ext' in `entry'. Make a copy of the 81 1.1 elric * extension, so the caller must still free `ext' on both success and 82 1.1 elric * failure. Returns 0 or error code. 83 1.1 elric */ 84 1.1 elric 85 1.1 elric krb5_error_code 86 1.1 elric hdb_replace_extension(krb5_context context, 87 1.1 elric hdb_entry *entry, 88 1.1 elric const HDB_extension *ext) 89 1.1 elric { 90 1.1 elric HDB_extension *ext2; 91 1.1 elric HDB_extension *es; 92 1.1 elric int ret; 93 1.1 elric 94 1.1 elric ext2 = NULL; 95 1.1 elric 96 1.1 elric if (entry->extensions == NULL) { 97 1.1 elric entry->extensions = calloc(1, sizeof(*entry->extensions)); 98 1.1 elric if (entry->extensions == NULL) { 99 1.1 elric krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 100 1.1 elric return ENOMEM; 101 1.1 elric } 102 1.1 elric } else if (ext->data.element != choice_HDB_extension_data_asn1_ellipsis) { 103 1.1 elric ext2 = hdb_find_extension(entry, ext->data.element); 104 1.1 elric } else { 105 1.1 elric /* 106 1.2 christos * This is an unknown extension, and we are asked to replace a 107 1.1 elric * possible entry in `entry' that is of the same type. This 108 1.1 elric * might seem impossible, but ASN.1 CHOICE comes to our 109 1.1 elric * rescue. The first tag in each branch in the CHOICE is 110 1.1 elric * unique, so just find the element in the list that have the 111 1.1 elric * same tag was we are putting into the list. 112 1.1 elric */ 113 1.1 elric Der_class replace_class, list_class; 114 1.1 elric Der_type replace_type, list_type; 115 1.1 elric unsigned int replace_tag, list_tag; 116 1.1 elric size_t size; 117 1.2 christos size_t i; 118 1.1 elric 119 1.1 elric ret = der_get_tag(ext->data.u.asn1_ellipsis.data, 120 1.1 elric ext->data.u.asn1_ellipsis.length, 121 1.1 elric &replace_class, &replace_type, &replace_tag, 122 1.1 elric &size); 123 1.1 elric if (ret) { 124 1.1 elric krb5_set_error_message(context, ret, "hdb: failed to decode " 125 1.2 christos "replacement hdb extension"); 126 1.1 elric return ret; 127 1.1 elric } 128 1.1 elric 129 1.1 elric for (i = 0; i < entry->extensions->len; i++) { 130 1.1 elric HDB_extension *ext3 = &entry->extensions->val[i]; 131 1.1 elric 132 1.1 elric if (ext3->data.element != choice_HDB_extension_data_asn1_ellipsis) 133 1.1 elric continue; 134 1.1 elric 135 1.1 elric ret = der_get_tag(ext3->data.u.asn1_ellipsis.data, 136 1.1 elric ext3->data.u.asn1_ellipsis.length, 137 1.1 elric &list_class, &list_type, &list_tag, 138 1.1 elric &size); 139 1.1 elric if (ret) { 140 1.1 elric krb5_set_error_message(context, ret, "hdb: failed to decode " 141 1.2 christos "present hdb extension"); 142 1.1 elric return ret; 143 1.1 elric } 144 1.1 elric 145 1.1 elric if (MAKE_TAG(replace_class,replace_type,replace_type) == 146 1.1 elric MAKE_TAG(list_class,list_type,list_type)) { 147 1.1 elric ext2 = ext3; 148 1.1 elric break; 149 1.1 elric } 150 1.1 elric } 151 1.1 elric } 152 1.1 elric 153 1.1 elric if (ext2) { 154 1.1 elric free_HDB_extension(ext2); 155 1.1 elric ret = copy_HDB_extension(ext, ext2); 156 1.1 elric if (ret) 157 1.1 elric krb5_set_error_message(context, ret, "hdb: failed to copy replacement " 158 1.2 christos "hdb extension"); 159 1.1 elric return ret; 160 1.1 elric } 161 1.1 elric 162 1.1 elric es = realloc(entry->extensions->val, 163 1.1 elric (entry->extensions->len+1)*sizeof(entry->extensions->val[0])); 164 1.1 elric if (es == NULL) { 165 1.1 elric krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 166 1.1 elric return ENOMEM; 167 1.1 elric } 168 1.1 elric entry->extensions->val = es; 169 1.1 elric 170 1.1 elric ret = copy_HDB_extension(ext, 171 1.1 elric &entry->extensions->val[entry->extensions->len]); 172 1.1 elric if (ret == 0) 173 1.1 elric entry->extensions->len++; 174 1.1 elric else 175 1.1 elric krb5_set_error_message(context, ret, "hdb: failed to copy new extension"); 176 1.1 elric 177 1.1 elric return ret; 178 1.1 elric } 179 1.1 elric 180 1.1 elric krb5_error_code 181 1.1 elric hdb_clear_extension(krb5_context context, 182 1.1 elric hdb_entry *entry, 183 1.1 elric int type) 184 1.1 elric { 185 1.2 christos size_t i; 186 1.1 elric 187 1.1 elric if (entry->extensions == NULL) 188 1.1 elric return 0; 189 1.1 elric 190 1.1 elric for (i = 0; i < entry->extensions->len; i++) { 191 1.2 christos if (entry->extensions->val[i].data.element == (unsigned)type) { 192 1.1 elric free_HDB_extension(&entry->extensions->val[i]); 193 1.1 elric memmove(&entry->extensions->val[i], 194 1.1 elric &entry->extensions->val[i + 1], 195 1.1 elric sizeof(entry->extensions->val[i]) * (entry->extensions->len - i - 1)); 196 1.1 elric entry->extensions->len--; 197 1.1 elric } 198 1.1 elric } 199 1.1 elric if (entry->extensions->len == 0) { 200 1.1 elric free(entry->extensions->val); 201 1.1 elric free(entry->extensions); 202 1.1 elric entry->extensions = NULL; 203 1.1 elric } 204 1.1 elric 205 1.1 elric return 0; 206 1.1 elric } 207 1.1 elric 208 1.1 elric 209 1.1 elric krb5_error_code 210 1.1 elric hdb_entry_get_pkinit_acl(const hdb_entry *entry, const HDB_Ext_PKINIT_acl **a) 211 1.1 elric { 212 1.1 elric const HDB_extension *ext; 213 1.1 elric 214 1.1 elric ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_acl); 215 1.1 elric if (ext) 216 1.1 elric *a = &ext->data.u.pkinit_acl; 217 1.1 elric else 218 1.1 elric *a = NULL; 219 1.1 elric 220 1.1 elric return 0; 221 1.1 elric } 222 1.1 elric 223 1.1 elric krb5_error_code 224 1.1 elric hdb_entry_get_pkinit_hash(const hdb_entry *entry, const HDB_Ext_PKINIT_hash **a) 225 1.1 elric { 226 1.1 elric const HDB_extension *ext; 227 1.1 elric 228 1.1 elric ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_cert_hash); 229 1.1 elric if (ext) 230 1.1 elric *a = &ext->data.u.pkinit_cert_hash; 231 1.1 elric else 232 1.1 elric *a = NULL; 233 1.1 elric 234 1.1 elric return 0; 235 1.1 elric } 236 1.1 elric 237 1.1 elric krb5_error_code 238 1.1 elric hdb_entry_get_pkinit_cert(const hdb_entry *entry, const HDB_Ext_PKINIT_cert **a) 239 1.1 elric { 240 1.1 elric const HDB_extension *ext; 241 1.1 elric 242 1.1 elric ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_cert); 243 1.1 elric if (ext) 244 1.1 elric *a = &ext->data.u.pkinit_cert; 245 1.1 elric else 246 1.1 elric *a = NULL; 247 1.1 elric 248 1.1 elric return 0; 249 1.1 elric } 250 1.1 elric 251 1.1 elric krb5_error_code 252 1.1 elric hdb_entry_get_pw_change_time(const hdb_entry *entry, time_t *t) 253 1.1 elric { 254 1.1 elric const HDB_extension *ext; 255 1.1 elric 256 1.1 elric ext = hdb_find_extension(entry, choice_HDB_extension_data_last_pw_change); 257 1.1 elric if (ext) 258 1.1 elric *t = ext->data.u.last_pw_change; 259 1.1 elric else 260 1.1 elric *t = 0; 261 1.1 elric 262 1.1 elric return 0; 263 1.1 elric } 264 1.1 elric 265 1.1 elric krb5_error_code 266 1.1 elric hdb_entry_set_pw_change_time(krb5_context context, 267 1.1 elric hdb_entry *entry, 268 1.1 elric time_t t) 269 1.1 elric { 270 1.1 elric HDB_extension ext; 271 1.1 elric 272 1.1 elric ext.mandatory = FALSE; 273 1.1 elric ext.data.element = choice_HDB_extension_data_last_pw_change; 274 1.1 elric if (t == 0) 275 1.1 elric t = time(NULL); 276 1.1 elric ext.data.u.last_pw_change = t; 277 1.1 elric 278 1.1 elric return hdb_replace_extension(context, entry, &ext); 279 1.1 elric } 280 1.1 elric 281 1.1 elric int 282 1.1 elric hdb_entry_get_password(krb5_context context, HDB *db, 283 1.1 elric const hdb_entry *entry, char **p) 284 1.1 elric { 285 1.1 elric HDB_extension *ext; 286 1.1 elric char *str; 287 1.1 elric int ret; 288 1.1 elric 289 1.1 elric ext = hdb_find_extension(entry, choice_HDB_extension_data_password); 290 1.1 elric if (ext) { 291 1.2 christos heim_utf8_string xstr; 292 1.1 elric heim_octet_string pw; 293 1.1 elric 294 1.1 elric if (db->hdb_master_key_set && ext->data.u.password.mkvno) { 295 1.1 elric hdb_master_key key; 296 1.1 elric 297 1.1 elric key = _hdb_find_master_key(ext->data.u.password.mkvno, 298 1.1 elric db->hdb_master_key); 299 1.1 elric 300 1.1 elric if (key == NULL) { 301 1.1 elric krb5_set_error_message(context, HDB_ERR_NO_MKEY, 302 1.1 elric "master key %d missing", 303 1.1 elric *ext->data.u.password.mkvno); 304 1.1 elric return HDB_ERR_NO_MKEY; 305 1.1 elric } 306 1.1 elric 307 1.1 elric ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY, 308 1.1 elric ext->data.u.password.password.data, 309 1.1 elric ext->data.u.password.password.length, 310 1.1 elric &pw); 311 1.1 elric } else { 312 1.1 elric ret = der_copy_octet_string(&ext->data.u.password.password, &pw); 313 1.1 elric } 314 1.1 elric if (ret) { 315 1.1 elric krb5_clear_error_message(context); 316 1.1 elric return ret; 317 1.1 elric } 318 1.1 elric 319 1.2 christos xstr = pw.data; 320 1.2 christos if (xstr[pw.length - 1] != '\0') { 321 1.1 elric krb5_set_error_message(context, EINVAL, "malformed password"); 322 1.1 elric return EINVAL; 323 1.1 elric } 324 1.1 elric 325 1.2 christos *p = strdup(xstr); 326 1.1 elric 327 1.1 elric der_free_octet_string(&pw); 328 1.1 elric if (*p == NULL) { 329 1.1 elric krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 330 1.1 elric return ENOMEM; 331 1.1 elric } 332 1.1 elric return 0; 333 1.1 elric } 334 1.1 elric 335 1.1 elric ret = krb5_unparse_name(context, entry->principal, &str); 336 1.1 elric if (ret == 0) { 337 1.1 elric krb5_set_error_message(context, ENOENT, 338 1.1 elric "no password attribute for %s", str); 339 1.1 elric free(str); 340 1.1 elric } else 341 1.1 elric krb5_clear_error_message(context); 342 1.1 elric 343 1.1 elric return ENOENT; 344 1.1 elric } 345 1.1 elric 346 1.1 elric int 347 1.1 elric hdb_entry_set_password(krb5_context context, HDB *db, 348 1.1 elric hdb_entry *entry, const char *p) 349 1.1 elric { 350 1.1 elric HDB_extension ext; 351 1.1 elric hdb_master_key key; 352 1.1 elric int ret; 353 1.1 elric 354 1.1 elric ext.mandatory = FALSE; 355 1.1 elric ext.data.element = choice_HDB_extension_data_password; 356 1.1 elric 357 1.1 elric if (db->hdb_master_key_set) { 358 1.1 elric 359 1.1 elric key = _hdb_find_master_key(NULL, db->hdb_master_key); 360 1.1 elric if (key == NULL) { 361 1.1 elric krb5_set_error_message(context, HDB_ERR_NO_MKEY, 362 1.1 elric "hdb_entry_set_password: " 363 1.1 elric "failed to find masterkey"); 364 1.1 elric return HDB_ERR_NO_MKEY; 365 1.1 elric } 366 1.1 elric 367 1.1 elric ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY, 368 1.1 elric p, strlen(p) + 1, 369 1.1 elric &ext.data.u.password.password); 370 1.1 elric if (ret) 371 1.1 elric return ret; 372 1.1 elric 373 1.1 elric ext.data.u.password.mkvno = 374 1.1 elric malloc(sizeof(*ext.data.u.password.mkvno)); 375 1.1 elric if (ext.data.u.password.mkvno == NULL) { 376 1.1 elric free_HDB_extension(&ext); 377 1.1 elric krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 378 1.1 elric return ENOMEM; 379 1.1 elric } 380 1.1 elric *ext.data.u.password.mkvno = _hdb_mkey_version(key); 381 1.1 elric 382 1.1 elric } else { 383 1.1 elric ext.data.u.password.mkvno = NULL; 384 1.1 elric 385 1.1 elric ret = krb5_data_copy(&ext.data.u.password.password, 386 1.1 elric p, strlen(p) + 1); 387 1.1 elric if (ret) { 388 1.1 elric krb5_set_error_message(context, ret, "malloc: out of memory"); 389 1.1 elric free_HDB_extension(&ext); 390 1.1 elric return ret; 391 1.1 elric } 392 1.1 elric } 393 1.1 elric 394 1.1 elric ret = hdb_replace_extension(context, entry, &ext); 395 1.1 elric 396 1.1 elric free_HDB_extension(&ext); 397 1.1 elric 398 1.1 elric return ret; 399 1.1 elric } 400 1.1 elric 401 1.1 elric int 402 1.1 elric hdb_entry_clear_password(krb5_context context, hdb_entry *entry) 403 1.1 elric { 404 1.1 elric return hdb_clear_extension(context, entry, 405 1.1 elric choice_HDB_extension_data_password); 406 1.1 elric } 407 1.1 elric 408 1.1 elric krb5_error_code 409 1.1 elric hdb_entry_get_ConstrainedDelegACL(const hdb_entry *entry, 410 1.1 elric const HDB_Ext_Constrained_delegation_acl **a) 411 1.1 elric { 412 1.1 elric const HDB_extension *ext; 413 1.1 elric 414 1.1 elric ext = hdb_find_extension(entry, 415 1.1 elric choice_HDB_extension_data_allowed_to_delegate_to); 416 1.1 elric if (ext) 417 1.1 elric *a = &ext->data.u.allowed_to_delegate_to; 418 1.1 elric else 419 1.1 elric *a = NULL; 420 1.1 elric 421 1.1 elric return 0; 422 1.1 elric } 423 1.1 elric 424 1.1 elric krb5_error_code 425 1.1 elric hdb_entry_get_aliases(const hdb_entry *entry, const HDB_Ext_Aliases **a) 426 1.1 elric { 427 1.1 elric const HDB_extension *ext; 428 1.1 elric 429 1.1 elric ext = hdb_find_extension(entry, choice_HDB_extension_data_aliases); 430 1.1 elric if (ext) 431 1.1 elric *a = &ext->data.u.aliases; 432 1.1 elric else 433 1.1 elric *a = NULL; 434 1.1 elric 435 1.1 elric return 0; 436 1.1 elric } 437 1.2 christos 438 1.2 christos unsigned int 439 1.2 christos hdb_entry_get_kvno_diff_clnt(const hdb_entry *entry) 440 1.2 christos { 441 1.2 christos const HDB_extension *ext; 442 1.2 christos 443 1.2 christos ext = hdb_find_extension(entry, 444 1.2 christos choice_HDB_extension_data_hist_kvno_diff_clnt); 445 1.2 christos if (ext) 446 1.2 christos return ext->data.u.hist_kvno_diff_clnt; 447 1.2 christos return 1; 448 1.2 christos } 449 1.2 christos 450 1.2 christos krb5_error_code 451 1.2 christos hdb_entry_set_kvno_diff_clnt(krb5_context context, hdb_entry *entry, 452 1.2 christos unsigned int diff) 453 1.2 christos { 454 1.2 christos HDB_extension ext; 455 1.2 christos 456 1.2 christos if (diff > 16384) 457 1.2 christos return EINVAL; 458 1.2 christos ext.mandatory = FALSE; 459 1.2 christos ext.data.element = choice_HDB_extension_data_hist_kvno_diff_clnt; 460 1.2 christos ext.data.u.hist_kvno_diff_clnt = diff; 461 1.2 christos return hdb_replace_extension(context, entry, &ext); 462 1.2 christos } 463 1.2 christos 464 1.2 christos krb5_error_code 465 1.2 christos hdb_entry_clear_kvno_diff_clnt(krb5_context context, hdb_entry *entry) 466 1.2 christos { 467 1.2 christos return hdb_clear_extension(context, entry, 468 1.2 christos choice_HDB_extension_data_hist_kvno_diff_clnt); 469 1.2 christos } 470 1.2 christos 471 1.2 christos unsigned int 472 1.2 christos hdb_entry_get_kvno_diff_svc(const hdb_entry *entry) 473 1.2 christos { 474 1.2 christos const HDB_extension *ext; 475 1.2 christos 476 1.2 christos ext = hdb_find_extension(entry, 477 1.2 christos choice_HDB_extension_data_hist_kvno_diff_svc); 478 1.2 christos if (ext) 479 1.2 christos return ext->data.u.hist_kvno_diff_svc; 480 1.2 christos return 1024; /* max_life effectively provides a better default */ 481 1.2 christos } 482 1.2 christos 483 1.2 christos krb5_error_code 484 1.2 christos hdb_entry_set_kvno_diff_svc(krb5_context context, hdb_entry *entry, 485 1.2 christos unsigned int diff) 486 1.2 christos { 487 1.2 christos HDB_extension ext; 488 1.2 christos 489 1.2 christos if (diff > 16384) 490 1.2 christos return EINVAL; 491 1.2 christos ext.mandatory = FALSE; 492 1.2 christos ext.data.element = choice_HDB_extension_data_hist_kvno_diff_svc; 493 1.2 christos ext.data.u.hist_kvno_diff_svc = diff; 494 1.2 christos return hdb_replace_extension(context, entry, &ext); 495 1.2 christos } 496 1.2 christos 497 1.2 christos krb5_error_code 498 1.2 christos hdb_entry_clear_kvno_diff_svc(krb5_context context, hdb_entry *entry) 499 1.2 christos { 500 1.2 christos return hdb_clear_extension(context, entry, 501 1.2 christos choice_HDB_extension_data_hist_kvno_diff_svc); 502 1.2 christos } 503 1.2 christos 504 1.2 christos krb5_error_code 505 1.2 christos hdb_set_last_modified_by(krb5_context context, hdb_entry *entry, 506 1.2 christos krb5_principal modby, time_t modtime) 507 1.2 christos { 508 1.2 christos krb5_error_code ret; 509 1.2 christos Event *old_ev; 510 1.2 christos Event *ev; 511 1.2 christos 512 1.2 christos old_ev = entry->modified_by; 513 1.2 christos 514 1.2 christos ev = calloc(1, sizeof (*ev)); 515 1.2 christos if (!ev) 516 1.2 christos return ENOMEM; 517 1.2 christos if (modby) 518 1.2 christos ret = krb5_copy_principal(context, modby, &ev->principal); 519 1.2 christos else 520 1.2 christos ret = krb5_parse_name(context, "root/admin", &ev->principal); 521 1.2 christos if (ret) { 522 1.2 christos free(ev); 523 1.2 christos return ret; 524 1.2 christos } 525 1.2 christos ev->time = modtime; 526 1.2 christos if (!ev->time) 527 1.2 christos time(&ev->time); 528 1.2 christos 529 1.2 christos entry->modified_by = ev; 530 1.2 christos if (old_ev) 531 1.2 christos free_Event(old_ev); 532 1.2 christos return 0; 533 1.2 christos } 534 1.2 christos 535