1 /* 2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 10 * 11 * Openvision retains the copyright to derivative works of 12 * this source code. Do *NOT* create a derivative of this 13 * source code before consulting with your legal department. 14 * Do *NOT* integrate *ANY* of this source code into another 15 * product before consulting with your legal department. 16 * 17 * For further information, read the top-level Openvision 18 * copyright which is contained in the top-level MIT Kerberos 19 * copyright. 20 * 21 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 22 * 23 */ 24 25 26 /* 27 * kadmin/v5server/srv_acl.c 28 * 29 * Copyright 1995 by the Massachusetts Institute of Technology. 30 * All Rights Reserved. 31 * 32 * Export of this software from the United States of America may 33 * require a specific license from the United States Government. 34 * It is the responsibility of any person or organization contemplating 35 * export to obtain such a license before exporting. 36 * 37 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 38 * distribute this software and its documentation for any purpose and 39 * without fee is hereby granted, provided that the above copyright 40 * notice appear in all copies and that both that copyright notice and 41 * this permission notice appear in supporting documentation, and that 42 * the name of M.I.T. not be used in advertising or publicity pertaining 43 * to distribution of the software without specific, written prior 44 * permission. Furthermore if you modify this software you must label 45 * your software as modified software and not distribute it in such a 46 * fashion that it might be confused with the original M.I.T. software. 47 * M.I.T. makes no representations about the suitability of 48 * this software for any purpose. It is provided "as is" without express 49 * or implied warranty. 50 * 51 */ 52 53 /* 54 * srv_acl.c - Handle Kerberos ACL related functions. 55 */ 56 #include <stdio.h> 57 #include <syslog.h> 58 #include <sys/param.h> 59 #include <gssapi_krb5.h> 60 #include "k5-int.h" 61 #include <kadm5/server_internal.h> 62 #include <kadm5/admin.h> 63 #include <adm_proto.h> /* SUNWresync121 XXX */ 64 #include "server_acl.h" 65 #include <ctype.h> 66 #include <libintl.h> /* SUNWresync121 XXX */ 67 68 typedef struct _acl_op_table { 69 char ao_op; 70 krb5_int32 ao_mask; 71 } aop_t; 72 73 typedef struct _acl_entry { 74 struct _acl_entry *ae_next; 75 char *ae_name; 76 krb5_boolean ae_name_bad; 77 krb5_principal ae_principal; 78 krb5_int32 ae_op_allowed; 79 char *ae_target; 80 krb5_boolean ae_target_bad; 81 krb5_principal ae_target_princ; 82 char *ae_restriction_string; 83 /* eg: "-maxlife 3h -service +proxiable" */ 84 krb5_boolean ae_restriction_bad; 85 restriction_t *ae_restrictions; 86 } aent_t; 87 88 static const aop_t acl_op_table[] = { 89 { 'a', ACL_ADD }, 90 { 'd', ACL_DELETE }, 91 { 'm', ACL_MODIFY }, 92 { 'c', ACL_CHANGEPW }, 93 { 'i', ACL_INQUIRE }, 94 { 'l', ACL_LIST }, 95 { 'p', ACL_IPROP }, /* SUNW IProp */ 96 { 's', ACL_SETKEY }, 97 { 'u', ACL_MIGRATE }, /* pam_krb5_migrate */ 98 { 'x', ACL_ALL_MASK }, 99 { '*', ACL_ALL_MASK }, 100 { '\0', 0 } 101 }; 102 103 typedef struct _wildstate { 104 int nwild; 105 krb5_data *backref[9]; 106 } wildstate_t; 107 108 static aent_t *acl_list_head = (aent_t *) NULL; 109 static aent_t *acl_list_tail = (aent_t *) NULL; 110 111 static const char *acl_acl_file = (char *) NULL; 112 static int acl_inited = 0; 113 static int acl_debug_level = 0; 114 /* 115 * This is the catchall entry. If nothing else appropriate is found, or in 116 * the case where the ACL file is not present, this entry controls what can 117 * be done. 118 */ 119 static const char *acl_catchall_entry = NULL; 120 121 #define ACL_LINE2LONG_MSG dgettext(TEXT_DOMAIN, \ 122 "%s: line %d too long, truncated\n") 123 #define ACL_OP_BAD_MSG dgettext(TEXT_DOMAIN, \ 124 "Unrecognized ACL operation '%c' in %s\n") 125 #define ACL_SYN_ERR_MSG dgettext(TEXT_DOMAIN, \ 126 "%s: syntax error at line %d <%10s...>\n") 127 #define ACL_CANTOPEN_MSG dgettext(TEXT_DOMAIN, \ 128 "\007cannot open ACL file") 129 130 131 /* 132 * acl_get_line() - Get a line from the ACL file. 133 * Lines ending with \ are continued on the next line 134 */ 135 static char * 136 acl_get_line(fp, lnp) 137 FILE *fp; 138 int *lnp; /* caller should set to 1 before first call */ 139 { 140 int i, domore; 141 static int line_incr = 0; 142 static char acl_buf[BUFSIZ]; 143 144 *lnp += line_incr; 145 line_incr = 0; 146 for (domore = 1; domore && !feof(fp); ) { 147 /* Copy in the line, with continuations */ 148 for (i=0; ((i < sizeof acl_buf) && !feof(fp)); i++ ) { 149 acl_buf[i] = fgetc(fp); 150 if (acl_buf[i] == (char)EOF) { 151 if (i > 0 && acl_buf[i-1] == '\\') 152 i--; 153 break; /* it gets nulled-out below */ 154 } 155 else if (acl_buf[i] == '\n') { 156 if (i == 0 || acl_buf[i-1] != '\\') 157 break; /* empty line or normal end of line */ 158 else { 159 i -= 2; /* back up over "\\\n" and continue */ 160 line_incr++; 161 } 162 } 163 } 164 /* Check if we exceeded our buffer size */ 165 if (i == sizeof acl_buf && (i--, !feof(fp))) { 166 int c1 = acl_buf[i], c2; 167 168 krb5_klog_syslog(LOG_ERR, ACL_LINE2LONG_MSG, acl_acl_file, *lnp); 169 while ((c2 = fgetc(fp)) != EOF) { 170 if (c2 == '\n') { 171 if (c1 != '\\') 172 break; 173 line_incr++; 174 } 175 c1 = c2; 176 } 177 } 178 acl_buf[i] = '\0'; 179 if (acl_buf[0] == (char) EOF) /* ptooey */ 180 acl_buf[0] = '\0'; 181 else 182 line_incr++; 183 if ((acl_buf[0] != '#') && (acl_buf[0] != '\0')) 184 domore = 0; 185 } 186 if (domore || (strlen(acl_buf) == 0)) 187 return((char *) NULL); 188 else 189 return(acl_buf); 190 } 191 192 /* 193 * acl_parse_line() - Parse the contents of an ACL line. 194 */ 195 static aent_t * 196 acl_parse_line(lp) 197 const char *lp; 198 { 199 static char acle_principal[BUFSIZ]; 200 static char acle_ops[BUFSIZ]; 201 static char acle_object[BUFSIZ]; 202 static char acle_restrictions[BUFSIZ]; 203 aent_t *acle; 204 char *op; 205 int t, found, opok, nmatch; 206 207 DPRINT(DEBUG_CALLS, acl_debug_level, 208 ("* acl_parse_line(line=%20s)\n", lp)); 209 /* 210 * Format is still simple: 211 * entry ::= [<whitespace>] <principal> <whitespace> <opstring> 212 * [<whitespace> <target> [<whitespace> <restrictions> 213 * [<whitespace>]]] 214 */ 215 acle = (aent_t *) NULL; 216 acle_object[0] = '\0'; 217 nmatch = sscanf(lp, "%s %s %s %[^\n]", acle_principal, acle_ops, 218 acle_object, acle_restrictions); 219 if (nmatch >= 2) { 220 acle = (aent_t *) malloc(sizeof(aent_t)); 221 if (acle) { 222 acle->ae_next = (aent_t *) NULL; 223 acle->ae_op_allowed = (krb5_int32) 0; 224 acle->ae_target = 225 (nmatch >= 3) ? strdup(acle_object) : (char *) NULL; 226 acle->ae_target_bad = 0; 227 acle->ae_target_princ = (krb5_principal) NULL; 228 opok = 1; 229 for (op=acle_ops; *op; op++) { 230 char rop; 231 232 rop = (isupper(*op)) ? tolower(*op) : *op; 233 found = 0; 234 for (t=0; acl_op_table[t].ao_op; t++) { 235 if (rop == acl_op_table[t].ao_op) { 236 found = 1; 237 if (rop == *op) 238 acle->ae_op_allowed |= acl_op_table[t].ao_mask; 239 else 240 acle->ae_op_allowed &= ~acl_op_table[t].ao_mask; 241 } 242 } 243 if (!found) { 244 krb5_klog_syslog(LOG_ERR, ACL_OP_BAD_MSG, *op, lp); 245 opok = 0; 246 } 247 } 248 if (opok) { 249 acle->ae_name = (char *) malloc(strlen(acle_principal)+1); 250 if (acle->ae_name) { 251 strcpy(acle->ae_name, acle_principal); 252 acle->ae_principal = (krb5_principal) NULL; 253 acle->ae_name_bad = 0; 254 DPRINT(DEBUG_ACL, acl_debug_level, 255 ("A ACL entry %s -> opmask %x\n", 256 acle->ae_name, acle->ae_op_allowed)); 257 } 258 else { 259 if (acle->ae_target) 260 free(acle->ae_target); 261 free(acle); 262 acle = (aent_t *) NULL; 263 } 264 } 265 else { 266 if (acle->ae_target) 267 free(acle->ae_target); 268 free(acle); 269 acle = (aent_t *) NULL; 270 } 271 if ( nmatch >= 4 ) { 272 char *trailing; 273 274 trailing = &acle_restrictions[strlen(acle_restrictions)-1]; 275 while ( isspace(*trailing) ) 276 trailing--; 277 trailing[1] = '\0'; 278 acle->ae_restriction_string = strdup(acle_restrictions); 279 } 280 else { 281 acle->ae_restriction_string = (char *) NULL; 282 } 283 acle->ae_restriction_bad = 0; 284 acle->ae_restrictions = (restriction_t *) NULL; 285 } 286 } 287 DPRINT(DEBUG_CALLS, acl_debug_level, 288 ("X acl_parse_line() = %x\n", (long) acle)); 289 return(acle); 290 } 291 292 /* 293 * acl_parse_restrictions() - Parse optional restrictions field 294 * 295 * Allowed restrictions are: 296 * [+-]flagname (recognized by krb5_string_to_flags) 297 * flag is forced to indicated value 298 * -clearpolicy policy is forced clear 299 * -policy pol policy is forced to be "pol" 300 * -{expire,pwexpire,maxlife,maxrenewlife} deltat 301 * associated value will be forced to 302 * MIN(deltat, requested value) 303 * 304 * Returns: 0 on success, or system errors 305 */ 306 static krb5_error_code 307 acl_parse_restrictions(s, rpp) 308 char *s; 309 restriction_t **rpp; 310 { 311 char *sp, *tp, *ap; 312 static const char *delims = "\t\n\f\v\r ,"; 313 krb5_error_code ret; 314 krb5_deltat dt; 315 krb5_flags flag; 316 krb5_error_code code; 317 318 DPRINT(DEBUG_CALLS, acl_debug_level, 319 ("* acl_parse_restrictions(s=%20s, rpp=0x%08x)\n", s, (long)rpp)); 320 321 *rpp = (restriction_t *) NULL; 322 code = 0; 323 if (s) 324 if (!(sp = strdup(s)) /* Don't munge the original */ 325 || !(*rpp = (restriction_t *) malloc(sizeof(restriction_t)))) { 326 code = ENOMEM; 327 } else { 328 memset(*rpp, 0, sizeof(**rpp)); 329 for (tp=strtok(sp, delims); tp; tp=strtok((char *)NULL, delims)) { 330 flag = 0; 331 if (!krb5_string_to_flags(tp, "+", "-", &flag)) { 332 /* OK, but was it in the positive or negative sense? */ 333 if (flag) { 334 (*rpp)->require_attrs |= flag; 335 } else { 336 flag = ~0; 337 (void) krb5_string_to_flags(tp, "+", "-", &flag); 338 (*rpp)->forbid_attrs |= ~flag; 339 } 340 (*rpp)->mask |= KADM5_ATTRIBUTES; 341 } else if (!strcmp(tp, "-clearpolicy")) { 342 (*rpp)->mask |= KADM5_POLICY_CLR; 343 } else { 344 /* everything else needs an argument ... */ 345 if (!(ap = strtok((char *)NULL, delims))) { 346 code = EINVAL; 347 break; 348 } 349 if (!strcmp(tp, "-policy")) { 350 if (!((*rpp)->policy = strdup(ap))) { 351 code = ENOMEM; 352 break; 353 } 354 (*rpp)->mask |= KADM5_POLICY; 355 } else { 356 /* all other arguments must be a deltat ... */ 357 if (krb5_string_to_deltat(ap, &dt)) { 358 code = EINVAL; 359 break; 360 } 361 if (!strcmp(tp, "-expire")) { 362 (*rpp)->princ_lifetime = dt; 363 (*rpp)->mask |= KADM5_PRINC_EXPIRE_TIME; 364 } else if (!strcmp(tp, "-pwexpire")) { 365 (*rpp)->pw_lifetime = dt; 366 (*rpp)->mask |= KADM5_PW_EXPIRATION; 367 } else if (!strcmp(tp, "-maxlife")) { 368 (*rpp)->max_life = dt; 369 (*rpp)->mask |= KADM5_MAX_LIFE; 370 } else if (!strcmp(tp, "-maxrenewlife")) { 371 (*rpp)->max_renewable_life = dt; 372 (*rpp)->mask |= KADM5_MAX_RLIFE; 373 } else { 374 code = EINVAL; 375 break; 376 } 377 } 378 } 379 } 380 } 381 if (sp) 382 free(sp); 383 if (*rpp && code) { 384 if ((*rpp)->policy) 385 free((*rpp)->policy); 386 free(*rpp); 387 *rpp = (restriction_t *) NULL; 388 } 389 DPRINT(DEBUG_CALLS, acl_debug_level, 390 ("X acl_parse_restrictions() = %d, mask=0x%08x\n", 391 code, (*rpp) ? (*rpp)->mask : 0)); 392 return code; 393 } 394 395 /* 396 * acl_impose_restrictions() - impose restrictions, modifying *recp, *maskp 397 * 398 * Returns: 0 on success; 399 * malloc or timeofday errors 400 */ 401 krb5_error_code 402 acl_impose_restrictions(kcontext, recp, maskp, rp) 403 krb5_context kcontext; 404 kadm5_principal_ent_rec *recp; 405 long *maskp; 406 restriction_t *rp; 407 { 408 krb5_error_code code; 409 krb5_int32 now; 410 411 DPRINT(DEBUG_CALLS, acl_debug_level, 412 ("* acl_impose_restrictions(..., *maskp=0x%08x, rp=0x%08x)\n", 413 *maskp, (long)rp)); 414 if (!rp) 415 return 0; 416 if (rp->mask & (KADM5_PRINC_EXPIRE_TIME|KADM5_PW_EXPIRATION)) 417 if ((code = krb5_timeofday(kcontext, &now))) 418 return code; 419 420 if (rp->mask & KADM5_ATTRIBUTES) { 421 recp->attributes |= rp->require_attrs; 422 recp->attributes &= ~(rp->forbid_attrs); 423 *maskp |= KADM5_ATTRIBUTES; 424 } 425 if (rp->mask & KADM5_POLICY_CLR) { 426 *maskp &= ~KADM5_POLICY; 427 *maskp |= KADM5_POLICY_CLR; 428 } else if (rp->mask & KADM5_POLICY) { 429 if (recp->policy && strcmp(recp->policy, rp->policy)) { 430 free(recp->policy); 431 recp->policy = (char *) NULL; 432 } 433 if (!recp->policy) { 434 recp->policy = strdup(rp->policy); /* XDR will free it */ 435 if (!recp->policy) 436 return ENOMEM; 437 } 438 *maskp |= KADM5_POLICY; 439 } 440 if (rp->mask & KADM5_PRINC_EXPIRE_TIME) { 441 if (!(*maskp & KADM5_PRINC_EXPIRE_TIME) 442 || (recp->princ_expire_time > (now + rp->princ_lifetime))) 443 recp->princ_expire_time = now + rp->princ_lifetime; 444 *maskp |= KADM5_PRINC_EXPIRE_TIME; 445 } 446 if (rp->mask & KADM5_PW_EXPIRATION) { 447 if (!(*maskp & KADM5_PW_EXPIRATION) 448 || (recp->pw_expiration > (now + rp->pw_lifetime))) 449 recp->pw_expiration = now + rp->pw_lifetime; 450 *maskp |= KADM5_PW_EXPIRATION; 451 } 452 if (rp->mask & KADM5_MAX_LIFE) { 453 if (!(*maskp & KADM5_MAX_LIFE) 454 || (recp->max_life > rp->max_life)) 455 recp->max_life = rp->max_life; 456 *maskp |= KADM5_MAX_LIFE; 457 } 458 if (rp->mask & KADM5_MAX_RLIFE) { 459 if (!(*maskp & KADM5_MAX_RLIFE) 460 || (recp->max_renewable_life > rp->max_renewable_life)) 461 recp->max_renewable_life = rp->max_renewable_life; 462 *maskp |= KADM5_MAX_RLIFE; 463 } 464 DPRINT(DEBUG_CALLS, acl_debug_level, 465 ("X acl_impose_restrictions() = 0, *maskp=0x%08x\n", *maskp)); 466 return 0; 467 } 468 469 /* 470 * acl_free_entries() - Free all ACL entries. 471 */ 472 static void 473 acl_free_entries() 474 { 475 aent_t *ap; 476 aent_t *np; 477 478 DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_free_entries()\n")); 479 for (ap=acl_list_head; ap; ap = np) { 480 if (ap->ae_name) 481 free(ap->ae_name); 482 if (ap->ae_principal) 483 krb5_free_principal((krb5_context) NULL, ap->ae_principal); 484 if (ap->ae_target) 485 free(ap->ae_target); 486 if (ap->ae_target_princ) 487 krb5_free_principal((krb5_context) NULL, ap->ae_target_princ); 488 if (ap->ae_restriction_string) 489 free(ap->ae_restriction_string); 490 if (ap->ae_restrictions) { 491 if (ap->ae_restrictions->policy) 492 free(ap->ae_restrictions->policy); 493 free(ap->ae_restrictions); 494 } 495 np = ap->ae_next; 496 free(ap); 497 } 498 acl_list_head = acl_list_tail = (aent_t *) NULL; 499 acl_inited = 0; 500 DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_free_entries()\n")); 501 } 502 503 /* 504 * acl_load_acl_file() - Open and parse the ACL file. 505 */ 506 static int 507 acl_load_acl_file() 508 { 509 FILE *afp; 510 char *alinep; 511 aent_t **aentpp; 512 int alineno; 513 int retval = 1; 514 515 DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_load_acl_file()\n")); 516 /* Open the ACL file for read */ 517 if (afp = fopen(acl_acl_file, "rF")) { 518 alineno = 1; 519 aentpp = &acl_list_head; 520 521 /* Get a non-comment line */ 522 while (alinep = acl_get_line(afp, &alineno)) { 523 /* Parse it */ 524 *aentpp = acl_parse_line(alinep); 525 /* If syntax error, then fall out */ 526 if (!*aentpp) { 527 krb5_klog_syslog(LOG_ERR, ACL_SYN_ERR_MSG, 528 acl_acl_file, alineno, alinep); 529 retval = 0; 530 break; 531 } 532 acl_list_tail = *aentpp; 533 aentpp = &(*aentpp)->ae_next; 534 } 535 536 fclose(afp); 537 538 if (acl_catchall_entry) { 539 if (*aentpp = acl_parse_line(acl_catchall_entry)) { 540 acl_list_tail = *aentpp; 541 } 542 else { 543 retval = 0; 544 DPRINT(DEBUG_OPERATION, acl_debug_level, 545 ("> catchall acl entry (%s) load failed\n", 546 acl_catchall_entry)); 547 } 548 } 549 } 550 else { 551 krb5_klog_syslog(LOG_ERR, ACL_CANTOPEN_MSG, 552 error_message(errno), acl_acl_file); 553 if (acl_catchall_entry && 554 (acl_list_head = acl_parse_line((char *)acl_catchall_entry))) { 555 acl_list_tail = acl_list_head; 556 } 557 else { 558 retval = 0; 559 DPRINT(DEBUG_OPERATION, acl_debug_level, 560 ("> catchall acl entry (%s) load failed\n", 561 acl_catchall_entry)); 562 } 563 } 564 565 if (!retval) { 566 acl_free_entries(); 567 } 568 DPRINT(DEBUG_CALLS, acl_debug_level, 569 ("X acl_load_acl_file() = %d\n", retval)); 570 return(retval); 571 } 572 573 /* 574 * acl_match_data() - See if two data entries match. 575 * 576 * Wildcarding is only supported for a whole component. 577 */ 578 static krb5_boolean 579 acl_match_data(e1, e2, targetflag, ws) 580 krb5_data *e1, *e2; 581 int targetflag; 582 wildstate_t *ws; 583 { 584 krb5_boolean retval; 585 586 DPRINT(DEBUG_CALLS, acl_debug_level, 587 ("* acl_match_entry(%s, %s)\n", e1->data, e2->data)); 588 retval = 0; 589 if (!strncmp(e1->data, "*", e1->length)) { 590 retval = 1; 591 if (ws && !targetflag) { 592 if (ws->nwild >= 9) { 593 DPRINT(DEBUG_ACL, acl_debug_level, 594 ("Too many wildcards in ACL entry %s\n", e1->data)); 595 } 596 else 597 ws->backref[ws->nwild++] = e2; 598 } 599 } 600 else if (ws && targetflag && (e1->length == 2) && (e1->data[0] == '*') && 601 (e1->data[1] >= '1') && (e1->data[1] <= '9')) { 602 int n = e1->data[1] - '1'; 603 if (n >= ws->nwild) { 604 DPRINT(DEBUG_ACL, acl_debug_level, 605 ("Too many backrefs in ACL entry %s\n", e1->data)); 606 } 607 else if ((ws->backref[n]->length == e2->length) && 608 (!strncmp(ws->backref[n]->data, e2->data, e2->length))) 609 retval = 1; 610 611 } 612 else { 613 if ((e1->length == e2->length) && 614 (!strncmp(e1->data, e2->data, e1->length))) 615 retval = 1; 616 } 617 DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_match_entry()=%d\n",retval)); 618 return(retval); 619 } 620 621 /* 622 * acl_find_entry() - Find a matching entry. 623 */ 624 static aent_t * 625 acl_find_entry(kcontext, principal, dest_princ) 626 krb5_context kcontext; 627 krb5_principal principal; 628 krb5_principal dest_princ; 629 { 630 aent_t *entry; 631 krb5_error_code kret; 632 int i; 633 int matchgood; 634 wildstate_t state; 635 636 DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_find_entry()\n")); 637 memset((char *)&state, 0, sizeof state); 638 for (entry=acl_list_head; entry; entry = entry->ae_next) { 639 if (entry->ae_name_bad) 640 continue; 641 if (!strcmp(entry->ae_name, "*")) { 642 DPRINT(DEBUG_ACL, acl_debug_level, ("A wildcard ACL match\n")); 643 matchgood = 1; 644 } 645 else { 646 if (!entry->ae_principal && !entry->ae_name_bad) { 647 kret = krb5_parse_name(kcontext, 648 entry->ae_name, 649 &entry->ae_principal); 650 if (kret) 651 entry->ae_name_bad = 1; 652 } 653 if (entry->ae_name_bad) { 654 DPRINT(DEBUG_ACL, acl_debug_level, 655 ("Bad ACL entry %s\n", entry->ae_name)); 656 continue; 657 } 658 matchgood = 0; 659 if (acl_match_data(&entry->ae_principal->realm, 660 &principal->realm, 0, (wildstate_t *)0) && 661 (entry->ae_principal->length == principal->length)) { 662 matchgood = 1; 663 for (i=0; i<principal->length; i++) { 664 if (!acl_match_data(&entry->ae_principal->data[i], 665 &principal->data[i], 0, &state)) { 666 matchgood = 0; 667 break; 668 } 669 } 670 } 671 } 672 if (!matchgood) 673 continue; 674 675 /* We've matched the principal. If we have a target, then try it */ 676 if (entry->ae_target) { 677 if (!strcmp(entry->ae_target, "*")) 678 break; 679 if (!entry->ae_target_princ && !entry->ae_target_bad) { 680 kret = krb5_parse_name(kcontext, entry->ae_target, 681 &entry->ae_target_princ); 682 if (kret) 683 entry->ae_target_bad = 1; 684 } 685 } 686 if (entry->ae_target_bad) { 687 DPRINT(DEBUG_ACL, acl_debug_level, 688 ("Bad target in ACL entry for %s\n", entry->ae_name)); 689 entry->ae_name_bad = 1; 690 continue; 691 } 692 if (entry->ae_target && !dest_princ) 693 matchgood = 0; 694 else if (entry->ae_target && entry->ae_target_princ && dest_princ) { 695 if (acl_match_data(&entry->ae_target_princ->realm, 696 &dest_princ->realm, 1, (wildstate_t *)0) && 697 (entry->ae_target_princ->length == dest_princ->length)) { 698 for (i=0; i<dest_princ->length; i++) { 699 if (!acl_match_data(&entry->ae_target_princ->data[i], 700 &dest_princ->data[i], 1, &state)) { 701 matchgood = 0; 702 break; 703 } 704 } 705 } 706 else 707 matchgood = 0; 708 } 709 if (!matchgood) 710 continue; 711 712 if (entry->ae_restriction_string 713 && !entry->ae_restriction_bad 714 && !entry->ae_restrictions 715 && acl_parse_restrictions(entry->ae_restriction_string, 716 &entry->ae_restrictions)) { 717 DPRINT(DEBUG_ACL, acl_debug_level, 718 ("Bad restrictions in ACL entry for %s\n", entry->ae_name)); 719 entry->ae_restriction_bad = 1; 720 } 721 if (entry->ae_restriction_bad) { 722 entry->ae_name_bad = 1; 723 continue; 724 } 725 break; 726 } 727 DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_find_entry()=%x\n",entry)); 728 return(entry); 729 } 730 731 /* 732 * acl_init() - Initialize ACL context. 733 */ 734 krb5_error_code 735 acl_init(kcontext, debug_level, acl_file) 736 krb5_context kcontext; 737 int debug_level; 738 char *acl_file; 739 { 740 krb5_error_code kret; 741 742 kret = 0; 743 acl_debug_level = debug_level; 744 DPRINT(DEBUG_CALLS, acl_debug_level, 745 ("* acl_init(afile=%s)\n", 746 ((acl_file) ? acl_file : "(null)"))); 747 acl_acl_file = (acl_file) ? acl_file : (char *) KRB5_DEFAULT_ADMIN_ACL; 748 acl_inited = acl_load_acl_file(); 749 750 DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_init() = %d\n", kret)); 751 return(kret); 752 } 753 754 /* 755 * acl_finish - Terminate ACL context. 756 */ 757 void 758 acl_finish(kcontext, debug_level) 759 krb5_context kcontext; 760 int debug_level; 761 { 762 DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_finish()\n")); 763 acl_free_entries(); 764 DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_finish()\n")); 765 } 766 767 /* 768 * acl_check() - Is this operation permitted for this principal? 769 * this code used not to be based on gssapi. In order 770 * to minimize porting hassles, I've put all the 771 * gssapi hair in this function. This might not be 772 * the best medium-term solution. (The best long-term 773 * solution is, of course, a real authorization service.) 774 */ 775 krb5_boolean 776 acl_check(kcontext, caller, opmask, principal, restrictions) 777 krb5_context kcontext; 778 gss_name_t caller; 779 krb5_int32 opmask; 780 krb5_principal principal; 781 restriction_t **restrictions; 782 { 783 krb5_boolean retval; 784 aent_t *aentry; 785 gss_buffer_desc caller_buf; 786 gss_OID caller_oid; 787 OM_uint32 emaj, emin; 788 krb5_error_code code; 789 krb5_principal caller_princ; 790 791 DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_op_permitted()\n")); 792 793 if (restrictions) 794 *restrictions = NULL; 795 796 if (GSS_ERROR(emaj = gss_display_name(&emin, caller, &caller_buf, 797 &caller_oid))) 798 return(1); 799 800 code = krb5_parse_name(kcontext, (char *) caller_buf.value, 801 &caller_princ); 802 803 gss_release_buffer(&emin, &caller_buf); 804 805 if (code) 806 return(code); 807 808 retval = 0; 809 if (aentry = acl_find_entry(kcontext, caller_princ, principal)) { 810 if ((aentry->ae_op_allowed & opmask) == opmask) { 811 retval = 1; 812 if (restrictions) { 813 *restrictions = 814 (aentry->ae_restrictions && aentry->ae_restrictions->mask) 815 ? aentry->ae_restrictions 816 : (restriction_t *) NULL; 817 } 818 } 819 } 820 821 krb5_free_principal(kcontext, caller_princ); 822 823 DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_op_permitted()=%d\n", 824 retval)); 825 return(retval); 826 } 827 828 kadm5_ret_t 829 kadm5_get_privs(void *server_handle, long *privs) 830 { 831 kadm5_server_handle_t handle = server_handle; 832 833 CHECK_HANDLE(server_handle); 834 835 /* this is impossible to do with the current interface. For now, 836 return all privs, which will confuse some clients, but not 837 deny any access to users of "smart" clients which try to cache */ 838 839 *privs = ~0; 840 841 return KADM5_OK; 842 } 843 844 /* SUNWresync121 (SEAM1.0) XXX */ 845 kadm5_ret_t 846 __kadm5_get_priv(void *server_handle, long *privs, gss_name_t client) 847 { 848 849 aent_t *aentry; 850 gss_buffer_desc caller_buff; 851 gss_OID caller_oid; 852 krb5_principal caller_principal; 853 OM_uint32 minor, major; 854 krb5_error_code k_error; 855 kadm5_ret_t retval = KADM5_FAILURE; 856 857 kadm5_server_handle_t handle = server_handle; 858 859 CHECK_HANDLE(server_handle); 860 861 if (GSS_ERROR(major = gss_display_name(&minor, client, &caller_buff, 862 &caller_oid))) 863 return(retval); 864 k_error = krb5_parse_name(handle->context, 865 (char *) caller_buff.value, 866 &caller_principal); 867 gss_release_buffer(&minor, &caller_buff); 868 869 if (k_error) 870 return(retval); 871 872 if (aentry = acl_find_entry(handle->context, caller_principal, 873 (krb5_principal)NULL)) 874 *privs = aentry->ae_op_allowed; 875 krb5_free_principal(handle->context, caller_principal); 876 877 return (KADM5_OK); 878 } 879