1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* kadmin/server/auth_acl.c - ACL kadm5_auth module */ 3 /* 4 * Copyright 1995-2004, 2007, 2008, 2017 by the Massachusetts Institute of 5 * Technology. All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 27 #include "k5-int.h" 28 #include <syslog.h> 29 #include <kadm5/admin.h> 30 #include <krb5/kadm5_auth_plugin.h> 31 #include "adm_proto.h" 32 #include <ctype.h> 33 #include "auth.h" 34 35 /* 36 * Access control bits. 37 */ 38 #define ACL_ADD 1 39 #define ACL_DELETE 2 40 #define ACL_MODIFY 4 41 #define ACL_CHANGEPW 8 42 /* #define ACL_CHANGE_OWN_PW 16 */ 43 #define ACL_INQUIRE 32 44 #define ACL_EXTRACT 64 45 #define ACL_LIST 128 46 #define ACL_SETKEY 256 47 #define ACL_IPROP 512 48 49 #define ACL_ALL_MASK (ACL_ADD | \ 50 ACL_DELETE | \ 51 ACL_MODIFY | \ 52 ACL_CHANGEPW | \ 53 ACL_INQUIRE | \ 54 ACL_LIST | \ 55 ACL_IPROP | \ 56 ACL_SETKEY) 57 58 struct acl_op_table { 59 char op; 60 uint32_t mask; 61 }; 62 63 struct acl_entry { 64 struct acl_entry *next; 65 krb5_principal client; 66 uint32_t op_allowed; 67 krb5_principal target; 68 struct kadm5_auth_restrictions *rs; 69 }; 70 71 static const struct acl_op_table acl_op_table[] = { 72 { 'a', ACL_ADD }, 73 { 'd', ACL_DELETE }, 74 { 'm', ACL_MODIFY }, 75 { 'c', ACL_CHANGEPW }, 76 { 'i', ACL_INQUIRE }, 77 { 'l', ACL_LIST }, 78 { 'p', ACL_IPROP }, 79 { 's', ACL_SETKEY }, 80 { 'x', ACL_ALL_MASK }, 81 { '*', ACL_ALL_MASK }, 82 { 'e', ACL_EXTRACT }, 83 { '\0', 0 } 84 }; 85 86 struct wildstate { 87 int nwild; 88 const krb5_data *backref[9]; 89 }; 90 91 struct acl_state { 92 struct acl_entry *list; 93 }; 94 95 /* 96 * Get a line from the ACL file. Lines ending with \ are continued on the next 97 * line. The caller should set *lineno to 1 and *incr to 0 before the first 98 * call. On successful return, *lineno will be the line number of the line 99 * read. Return a pointer to the line on success, or NULL on end of file or 100 * read failure. 101 */ 102 static char * 103 get_line(FILE *fp, const char *fname, int *lineno, int *incr) 104 { 105 const int chunksize = 128; 106 struct k5buf buf; 107 size_t old_len; 108 char *p; 109 110 /* Increment *lineno by the number of newlines from the last line. */ 111 *lineno += *incr; 112 *incr = 0; 113 114 k5_buf_init_dynamic(&buf); 115 for (;;) { 116 /* Read at least part of a line into the buffer. */ 117 old_len = buf.len; 118 p = k5_buf_get_space(&buf, chunksize); 119 if (p == NULL) 120 return NULL; 121 122 if (fgets(p, chunksize, fp) == NULL) { 123 /* We reached the end. Return a final unterminated line, if there 124 * is one and it's not a comment. */ 125 k5_buf_truncate(&buf, old_len); 126 if (buf.len > 0 && *(char *)buf.data != '#') 127 return buf.data; 128 k5_buf_free(&buf); 129 return NULL; 130 } 131 132 /* Set the buffer length based on the actual amount read. */ 133 k5_buf_truncate(&buf, old_len + strlen(p)); 134 135 p = buf.data; 136 if (buf.len > 0 && p[buf.len - 1] == '\n') { 137 /* We have a complete raw line in the buffer. */ 138 (*incr)++; 139 k5_buf_truncate(&buf, buf.len - 1); 140 if (buf.len > 0 && p[buf.len - 1] == '\\') { 141 /* This line has a continuation marker; keep reading. */ 142 k5_buf_truncate(&buf, buf.len - 1); 143 } else if (buf.len == 0 || *p == '#') { 144 /* This line is empty or a comment. Start over. */ 145 *lineno += *incr; 146 *incr = 0; 147 k5_buf_truncate(&buf, 0); 148 } else { 149 return k5_buf_cstring(&buf); 150 } 151 } 152 } 153 } 154 155 /* 156 * Parse a restrictions field. Return NULL on failure. 157 * 158 * Allowed restrictions are: 159 * [+-]flagname (recognized by krb5_flagspec_to_mask) 160 * flag is forced to indicated value 161 * -clearpolicy policy is forced clear 162 * -policy pol policy is forced to be "pol" 163 * -{expire,pwexpire,maxlife,maxrenewlife} deltat 164 * associated value will be forced to 165 * MIN(deltat, requested value) 166 */ 167 static struct kadm5_auth_restrictions * 168 parse_restrictions(const char *str, const char *fname) 169 { 170 char *copy = NULL, *token, *arg, *save; 171 const char *delims = "\t\n\f\v\r ,"; 172 krb5_deltat delta; 173 struct kadm5_auth_restrictions *rs; 174 175 copy = strdup(str); 176 if (copy == NULL) 177 return NULL; 178 179 rs = calloc(1, sizeof(*rs)); 180 if (rs == NULL) { 181 free(copy); 182 return NULL; 183 } 184 185 rs->forbid_attrs = ~(krb5_flags)0; 186 for (token = strtok_r(copy, delims, &save); token != NULL; 187 token = strtok_r(NULL, delims, &save)) { 188 189 if (krb5_flagspec_to_mask(token, &rs->require_attrs, 190 &rs->forbid_attrs) == 0) { 191 rs->mask |= KADM5_ATTRIBUTES; 192 continue; 193 } 194 195 if (strcmp(token, "-clearpolicy") == 0) { 196 rs->mask |= KADM5_POLICY_CLR; 197 continue; 198 } 199 200 /* Everything else needs an argument. */ 201 arg = strtok_r(NULL, delims, &save); 202 if (arg == NULL) 203 goto error; 204 205 if (strcmp(token, "-policy") == 0) { 206 if (rs->policy != NULL) 207 goto error; 208 rs->policy = strdup(arg); 209 if (rs->policy == NULL) 210 goto error; 211 rs->mask |= KADM5_POLICY; 212 continue; 213 } 214 215 /* All other arguments must be a deltat. */ 216 if (krb5_string_to_deltat(arg, &delta) != 0) 217 goto error; 218 219 if (strcmp(token, "-expire") == 0) { 220 rs->princ_lifetime = delta; 221 rs->mask |= KADM5_PRINC_EXPIRE_TIME; 222 } else if (strcmp(token, "-pwexpire") == 0) { 223 rs->pw_lifetime = delta; 224 rs->mask |= KADM5_PW_EXPIRATION; 225 } else if (strcmp(token, "-maxlife") == 0) { 226 rs->max_life = delta; 227 rs->mask |= KADM5_MAX_LIFE; 228 } else if (strcmp(token, "-maxrenewlife") == 0) { 229 rs->max_renewable_life = delta; 230 rs->mask |= KADM5_MAX_RLIFE; 231 } else { 232 goto error; 233 } 234 } 235 236 free(copy); 237 return rs; 238 239 error: 240 krb5_klog_syslog(LOG_ERR, _("%s: invalid restrictions: %s"), fname, str); 241 free(copy); 242 free(rs->policy); 243 free(rs); 244 return NULL; 245 } 246 247 static void 248 free_acl_entry(struct acl_entry *entry) 249 { 250 krb5_free_principal(NULL, entry->client); 251 krb5_free_principal(NULL, entry->target); 252 if (entry->rs != NULL) { 253 free(entry->rs->policy); 254 free(entry->rs); 255 } 256 free(entry); 257 } 258 259 /* Parse the four fields of an ACL entry and return a structure representing 260 * it. Log a message and return NULL on error. */ 261 static struct acl_entry * 262 parse_entry(krb5_context context, const char *client, const char *ops, 263 const char *target, const char *rs, const char *line, 264 const char *fname) 265 { 266 struct acl_entry *entry; 267 const char *op; 268 char rop; 269 int t; 270 271 entry = calloc(1, sizeof(*entry)); 272 if (entry == NULL) 273 return NULL; 274 275 for (op = ops; *op; op++) { 276 rop = isupper((unsigned char)*op) ? tolower((unsigned char)*op) : *op; 277 for (t = 0; acl_op_table[t].op; t++) { 278 if (rop == acl_op_table[t].op) { 279 if (rop == *op) 280 entry->op_allowed |= acl_op_table[t].mask; 281 else 282 entry->op_allowed &= ~acl_op_table[t].mask; 283 break; 284 } 285 } 286 if (!acl_op_table[t].op) { 287 krb5_klog_syslog(LOG_ERR, 288 _("Unrecognized ACL operation '%c' in %s"), 289 *op, line); 290 goto error; 291 } 292 } 293 294 if (strcmp(client, "*") != 0) { 295 if (krb5_parse_name(context, client, &entry->client) != 0) { 296 krb5_klog_syslog(LOG_ERR, _("Cannot parse client principal '%s'"), 297 client); 298 goto error; 299 } 300 } 301 302 if (target != NULL && strcmp(target, "*") != 0) { 303 if (krb5_parse_name(context, target, &entry->target) != 0) { 304 krb5_klog_syslog(LOG_ERR, _("Cannot parse target principal '%s'"), 305 target); 306 goto error; 307 } 308 } 309 310 if (rs != NULL) { 311 entry->rs = parse_restrictions(rs, fname); 312 if (entry->rs == NULL) 313 goto error; 314 } 315 316 return entry; 317 318 error: 319 free_acl_entry(entry); 320 return NULL; 321 } 322 323 /* Parse the contents of an ACL line. */ 324 static struct acl_entry * 325 parse_line(krb5_context context, const char *line, const char *fname) 326 { 327 struct acl_entry *entry = NULL; 328 char *copy; 329 char *client, *client_end, *ops, *ops_end, *target, *target_end, *rs, *end; 330 const char *ws = "\t\n\f\v\r ,"; 331 332 /* 333 * Format: 334 * entry ::= [<whitespace>] <principal> <whitespace> <opstring> 335 * [<whitespace> <target> [<whitespace> <restrictions> 336 * [<whitespace>]]] 337 */ 338 339 /* Make a copy and remove any trailing whitespace. */ 340 copy = strdup(line); 341 if (copy == NULL) 342 return NULL; 343 end = copy + strlen(copy); 344 while (end > copy && isspace(end[-1])) 345 *--end = '\0'; 346 347 /* Find the beginning and end of each field. The end of restrictions is 348 * the end of copy. */ 349 client = copy + strspn(copy, ws); 350 client_end = client + strcspn(client, ws); 351 ops = client_end + strspn(client_end, ws); 352 ops_end = ops + strcspn(ops, ws); 353 target = ops_end + strspn(ops_end, ws); 354 target_end = target + strcspn(target, ws); 355 rs = target_end + strspn(target_end, ws); 356 357 /* Terminate the first three fields. */ 358 *client_end = *ops_end = *target_end = '\0'; 359 360 /* The last two fields are optional; represent them as NULL if not present. 361 * The first two fields are required. */ 362 if (*target == '\0') 363 target = NULL; 364 if (*rs == '\0') 365 rs = NULL; 366 if (*client != '\0' && *ops != '\0') 367 entry = parse_entry(context, client, ops, target, rs, line, fname); 368 free(copy); 369 return entry; 370 } 371 372 /* Free all ACL entries. */ 373 static void 374 free_acl_entries(struct acl_state *state) 375 { 376 struct acl_entry *entry, *next; 377 378 for (entry = state->list; entry != NULL; entry = next) { 379 next = entry->next; 380 free_acl_entry(entry); 381 } 382 state->list = NULL; 383 } 384 385 /* Open and parse the ACL file. */ 386 static krb5_error_code 387 load_acl_file(krb5_context context, const char *fname, struct acl_state *state) 388 { 389 krb5_error_code ret; 390 FILE *fp; 391 char *line; 392 struct acl_entry **entry_slot; 393 int lineno, incr; 394 395 state->list = NULL; 396 397 /* Open the ACL file for reading. */ 398 fp = fopen(fname, "r"); 399 if (fp == NULL) { 400 krb5_klog_syslog(LOG_ERR, _("%s while opening ACL file %s"), 401 error_message(errno), fname); 402 ret = errno; 403 k5_setmsg(context, errno, _("Cannot open %s: %s"), fname, 404 error_message(ret)); 405 return ret; 406 } 407 408 set_cloexec_file(fp); 409 lineno = 1; 410 incr = 0; 411 entry_slot = &state->list; 412 413 /* Get a non-comment line. */ 414 while ((line = get_line(fp, fname, &lineno, &incr)) != NULL) { 415 /* Parse it. Fail out on syntax error. */ 416 *entry_slot = parse_line(context, line, fname); 417 if (*entry_slot == NULL) { 418 krb5_klog_syslog(LOG_ERR, 419 _("%s: syntax error at line %d <%.10s...>"), 420 fname, lineno, line); 421 k5_setmsg(context, EINVAL, 422 _("%s: syntax error at line %d <%.10s...>"), 423 fname, lineno, line); 424 free_acl_entries(state); 425 free(line); 426 fclose(fp); 427 return EINVAL; 428 } 429 entry_slot = &(*entry_slot)->next; 430 free(line); 431 } 432 433 fclose(fp); 434 return 0; 435 } 436 437 /* 438 * See if two data entries match. If e1 is a wildcard (matching a whole 439 * component only) and targetflag is false, save an alias to e2 into 440 * ws->backref. If e1 is a back-reference and targetflag is true, compare the 441 * appropriate entry in ws->backref to e2. If ws is NULL, do not store or 442 * match back-references. 443 */ 444 static krb5_boolean 445 match_data(const krb5_data *e1, const krb5_data *e2, krb5_boolean targetflag, 446 struct wildstate *ws) 447 { 448 int n; 449 450 if (data_eq_string(*e1, "*")) { 451 if (ws != NULL && !targetflag) { 452 if (ws->nwild < 9) 453 ws->backref[ws->nwild++] = e2; 454 } 455 return TRUE; 456 } 457 458 if (ws != NULL && targetflag && e1->length == 2 && e1->data[0] == '*' && 459 e1->data[1] >= '1' && e1->data[1] <= '9') { 460 n = e1->data[1] - '1'; 461 if (n >= ws->nwild) 462 return FALSE; 463 return data_eq(*e2, *ws->backref[n]); 464 } else { 465 return data_eq(*e2, *e1); 466 } 467 } 468 469 /* Return true if p1 matches p2. p1 may contain wildcards if targetflag is 470 * false, or backreferences if it is true. */ 471 static krb5_boolean 472 match_princ(krb5_const_principal p1, krb5_const_principal p2, 473 krb5_boolean targetflag, struct wildstate *ws) 474 { 475 int i; 476 477 /* The principals must be of the same length. */ 478 if (p1->length != p2->length) 479 return FALSE; 480 481 /* The realm must match, and does not interact with wildcard state. */ 482 if (!match_data(&p1->realm, &p2->realm, targetflag, NULL)) 483 return FALSE; 484 485 /* All components of the principals must match. */ 486 for (i = 0; i < p1->length; i++) { 487 if (!match_data(&p1->data[i], &p2->data[i], targetflag, ws)) 488 return FALSE; 489 } 490 491 return TRUE; 492 } 493 494 /* Find an ACL entry matching principal and target_principal. Return NULL if 495 * none is found. */ 496 static struct acl_entry * 497 find_entry(struct acl_state *state, krb5_const_principal client, 498 krb5_const_principal target) 499 { 500 struct acl_entry *entry; 501 struct wildstate ws; 502 503 for (entry = state->list; entry != NULL; entry = entry->next) { 504 memset(&ws, 0, sizeof(ws)); 505 if (entry->client != NULL) { 506 if (!match_princ(entry->client, client, FALSE, &ws)) 507 continue; 508 } 509 510 if (entry->target != NULL) { 511 if (target == NULL) 512 continue; 513 if (!match_princ(entry->target, target, TRUE, &ws)) 514 continue; 515 } 516 517 return entry; 518 } 519 520 return NULL; 521 } 522 523 /* Return true if op is permitted for this principal. Set *rs_out (if not 524 * NULL) according to any restrictions in the ACL entry. */ 525 static krb5_error_code 526 acl_check(kadm5_auth_moddata data, uint32_t op, krb5_const_principal client, 527 krb5_const_principal target, struct kadm5_auth_restrictions **rs_out) 528 { 529 struct acl_entry *entry; 530 531 if (rs_out != NULL) 532 *rs_out = NULL; 533 534 entry = find_entry((struct acl_state *)data, client, target); 535 if (entry == NULL) 536 return KRB5_PLUGIN_NO_HANDLE; 537 if (!(entry->op_allowed & op)) 538 return KRB5_PLUGIN_NO_HANDLE; 539 540 if (rs_out != NULL && entry->rs != NULL && entry->rs->mask) 541 *rs_out = entry->rs; 542 543 return 0; 544 } 545 546 static krb5_error_code 547 acl_init(krb5_context context, const char *acl_file, 548 kadm5_auth_moddata *data_out) 549 { 550 krb5_error_code ret; 551 struct acl_state *state; 552 553 *data_out = NULL; 554 if (acl_file == NULL) 555 return KRB5_PLUGIN_NO_HANDLE; 556 state = malloc(sizeof(*state)); 557 state->list = NULL; 558 ret = load_acl_file(context, acl_file, state); 559 if (ret) { 560 free(state); 561 return ret; 562 } 563 *data_out = (kadm5_auth_moddata)state; 564 return 0; 565 } 566 567 static void 568 acl_fini(krb5_context context, kadm5_auth_moddata data) 569 { 570 if (data == NULL) 571 return; 572 free_acl_entries((struct acl_state *)data); 573 free(data); 574 } 575 576 static krb5_error_code 577 acl_addprinc(krb5_context context, kadm5_auth_moddata data, 578 krb5_const_principal client, krb5_const_principal target, 579 const struct _kadm5_principal_ent_t *ent, long mask, 580 struct kadm5_auth_restrictions **rs_out) 581 { 582 return acl_check(data, ACL_ADD, client, target, rs_out); 583 } 584 585 static krb5_error_code 586 acl_modprinc(krb5_context context, kadm5_auth_moddata data, 587 krb5_const_principal client, krb5_const_principal target, 588 const struct _kadm5_principal_ent_t *ent, long mask, 589 struct kadm5_auth_restrictions **rs_out) 590 { 591 return acl_check(data, ACL_MODIFY, client, target, rs_out); 592 } 593 594 static krb5_error_code 595 acl_setstr(krb5_context context, kadm5_auth_moddata data, 596 krb5_const_principal client, krb5_const_principal target, 597 const char *key, const char *value) 598 { 599 return acl_check(data, ACL_MODIFY, client, target, NULL); 600 } 601 602 static krb5_error_code 603 acl_cpw(krb5_context context, kadm5_auth_moddata data, 604 krb5_const_principal client, krb5_const_principal target) 605 { 606 return acl_check(data, ACL_CHANGEPW, client, target, NULL); 607 } 608 609 static krb5_error_code 610 acl_chrand(krb5_context context, kadm5_auth_moddata data, 611 krb5_const_principal client, krb5_const_principal target) 612 { 613 return acl_check(data, ACL_CHANGEPW, client, target, NULL); 614 } 615 616 static krb5_error_code 617 acl_setkey(krb5_context context, kadm5_auth_moddata data, 618 krb5_const_principal client, krb5_const_principal target) 619 { 620 return acl_check(data, ACL_SETKEY, client, target, NULL); 621 } 622 623 static krb5_error_code 624 acl_purgekeys(krb5_context context, kadm5_auth_moddata data, 625 krb5_const_principal client, krb5_const_principal target) 626 { 627 return acl_check(data, ACL_MODIFY, client, target, NULL); 628 } 629 630 static krb5_error_code 631 acl_delprinc(krb5_context context, kadm5_auth_moddata data, 632 krb5_const_principal client, krb5_const_principal target) 633 { 634 return acl_check(data, ACL_DELETE, client, target, NULL); 635 } 636 637 static krb5_error_code 638 acl_renprinc(krb5_context context, kadm5_auth_moddata data, 639 krb5_const_principal client, krb5_const_principal src, 640 krb5_const_principal dest) 641 { 642 struct kadm5_auth_restrictions *rs; 643 644 if (acl_check(data, ACL_DELETE, client, src, NULL) == 0 && 645 acl_check(data, ACL_ADD, client, dest, &rs) == 0 && rs == NULL) 646 return 0; 647 return KRB5_PLUGIN_NO_HANDLE; 648 } 649 650 static krb5_error_code 651 acl_getprinc(krb5_context context, kadm5_auth_moddata data, 652 krb5_const_principal client, krb5_const_principal target) 653 { 654 return acl_check(data, ACL_INQUIRE, client, target, NULL); 655 } 656 657 static krb5_error_code 658 acl_getstrs(krb5_context context, kadm5_auth_moddata data, 659 krb5_const_principal client, krb5_const_principal target) 660 { 661 return acl_check(data, ACL_INQUIRE, client, target, NULL); 662 } 663 664 static krb5_error_code 665 acl_extract(krb5_context context, kadm5_auth_moddata data, 666 krb5_const_principal client, krb5_const_principal target) 667 { 668 return acl_check(data, ACL_EXTRACT, client, target, NULL); 669 } 670 671 static krb5_error_code 672 acl_listprincs(krb5_context context, kadm5_auth_moddata data, 673 krb5_const_principal client) 674 { 675 return acl_check(data, ACL_LIST, client, NULL, NULL); 676 } 677 678 static krb5_error_code 679 acl_addpol(krb5_context context, kadm5_auth_moddata data, 680 krb5_const_principal client, const char *policy, 681 const struct _kadm5_policy_ent_t *ent, long mask) 682 { 683 return acl_check(data, ACL_ADD, client, NULL, NULL); 684 } 685 686 static krb5_error_code 687 acl_modpol(krb5_context context, kadm5_auth_moddata data, 688 krb5_const_principal client, const char *policy, 689 const struct _kadm5_policy_ent_t *ent, long mask) 690 { 691 return acl_check(data, ACL_MODIFY, client, NULL, NULL); 692 } 693 694 static krb5_error_code 695 acl_delpol(krb5_context context, kadm5_auth_moddata data, 696 krb5_const_principal client, const char *policy) 697 { 698 return acl_check(data, ACL_DELETE, client, NULL, NULL); 699 } 700 701 static krb5_error_code 702 acl_getpol(krb5_context context, kadm5_auth_moddata data, 703 krb5_const_principal client, const char *policy, 704 const char *client_policy) 705 { 706 return acl_check(data, ACL_INQUIRE, client, NULL, NULL); 707 } 708 709 static krb5_error_code 710 acl_listpols(krb5_context context, kadm5_auth_moddata data, 711 krb5_const_principal client) 712 { 713 return acl_check(data, ACL_LIST, client, NULL, NULL); 714 } 715 716 static krb5_error_code 717 acl_iprop(krb5_context context, kadm5_auth_moddata data, 718 krb5_const_principal client) 719 { 720 return acl_check(data, ACL_IPROP, client, NULL, NULL); 721 } 722 723 static krb5_error_code 724 acl_addalias(krb5_context context, kadm5_auth_moddata data, 725 krb5_const_principal client, krb5_const_principal alias, 726 krb5_const_principal target) 727 { 728 struct kadm5_auth_restrictions *rs; 729 730 if (acl_check(data, ACL_ADD, client, alias, &rs) == 0 && rs == NULL && 731 acl_check(data, ACL_MODIFY, client, target, &rs) == 0) 732 return 0; 733 return KRB5_PLUGIN_NO_HANDLE; 734 } 735 736 krb5_error_code 737 kadm5_auth_acl_initvt(krb5_context context, int maj_ver, int min_ver, 738 krb5_plugin_vtable vtable) 739 { 740 kadm5_auth_vtable vt; 741 742 if (maj_ver != 1) 743 return KRB5_PLUGIN_VER_NOTSUPP; 744 vt = (kadm5_auth_vtable)vtable; 745 vt->name = "acl"; 746 vt->init = acl_init; 747 vt->fini = acl_fini; 748 vt->addprinc = acl_addprinc; 749 vt->modprinc = acl_modprinc; 750 vt->setstr = acl_setstr; 751 vt->cpw = acl_cpw; 752 vt->chrand = acl_chrand; 753 vt->setkey = acl_setkey; 754 vt->purgekeys = acl_purgekeys; 755 vt->delprinc = acl_delprinc; 756 vt->renprinc = acl_renprinc; 757 vt->getprinc = acl_getprinc; 758 vt->getstrs = acl_getstrs; 759 vt->extract = acl_extract; 760 vt->listprincs = acl_listprincs; 761 vt->addpol = acl_addpol; 762 vt->modpol = acl_modpol; 763 vt->delpol = acl_delpol; 764 vt->getpol = acl_getpol; 765 vt->listpols = acl_listpols; 766 vt->iprop = acl_iprop; 767 vt->addalias = acl_addalias; 768 return 0; 769 } 770