dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / krb5 / kadm5 / srv / server_acl.c
blob04654ee6f10b68c378c7055c85a48d6c6fd479ab
1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
7 /*
8 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
10 * Openvision retains the copyright to derivative works of
11 * this source code. Do *NOT* create a derivative of this
12 * source code before consulting with your legal department.
13 * Do *NOT* integrate *ANY* of this source code into another
14 * product before consulting with your legal department.
16 * For further information, read the top-level Openvision
17 * copyright which is contained in the top-level MIT Kerberos
18 * copyright.
20 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
26 * kadmin/v5server/srv_acl.c
28 * Copyright 1995 by the Massachusetts Institute of Technology.
29 * All Rights Reserved.
31 * Export of this software from the United States of America may
32 * require a specific license from the United States Government.
33 * It is the responsibility of any person or organization contemplating
34 * export to obtain such a license before exporting.
36 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
37 * distribute this software and its documentation for any purpose and
38 * without fee is hereby granted, provided that the above copyright
39 * notice appear in all copies and that both that copyright notice and
40 * this permission notice appear in supporting documentation, and that
41 * the name of M.I.T. not be used in advertising or publicity pertaining
42 * to distribution of the software without specific, written prior
43 * permission. Furthermore if you modify this software you must label
44 * your software as modified software and not distribute it in such a
45 * fashion that it might be confused with the original M.I.T. software.
46 * M.I.T. makes no representations about the suitability of
47 * this software for any purpose. It is provided "as is" without express
48 * or implied warranty.
53 * srv_acl.c - Handle Kerberos ACL related functions.
55 #include <stdio.h>
56 #include <syslog.h>
57 #include <sys/param.h>
58 #include "k5-int.h"
59 #include <gssapi_krb5.h>
60 #include <kadm5/server_internal.h>
61 #include <kadm5/admin.h>
62 #include <adm_proto.h> /* SUNWresync121 XXX */
63 #include "server_acl.h"
64 #include <ctype.h>
65 #include <libintl.h> /* SUNWresync121 XXX */
67 typedef struct _acl_op_table {
68 char ao_op;
69 krb5_int32 ao_mask;
70 } aop_t;
72 typedef struct _acl_entry {
73 struct _acl_entry *ae_next;
74 char *ae_name;
75 krb5_boolean ae_name_bad;
76 krb5_principal ae_principal;
77 krb5_int32 ae_op_allowed;
78 char *ae_target;
79 krb5_boolean ae_target_bad;
80 krb5_principal ae_target_princ;
81 char *ae_restriction_string;
82 /* eg: "-maxlife 3h -service +proxiable" */
83 krb5_boolean ae_restriction_bad;
84 restriction_t *ae_restrictions;
85 } aent_t;
87 static const aop_t acl_op_table[] = {
88 { 'a', ACL_ADD },
89 { 'd', ACL_DELETE },
90 { 'm', ACL_MODIFY },
91 { 'c', ACL_CHANGEPW },
92 { 'i', ACL_INQUIRE },
93 { 'l', ACL_LIST },
94 { 'p', ACL_IPROP }, /* SUNW IProp */
95 { 's', ACL_SETKEY },
96 { 'u', ACL_MIGRATE }, /* pam_krb5_migrate */
97 { 'x', ACL_ALL_MASK },
98 { '*', ACL_ALL_MASK },
99 { '\0', 0 }
102 typedef struct _wildstate {
103 int nwild;
104 krb5_data *backref[9];
105 } wildstate_t;
107 static aent_t *acl_list_head = (aent_t *) NULL;
108 static aent_t *acl_list_tail = (aent_t *) NULL;
110 static const char *acl_acl_file = (char *) NULL;
111 static int acl_inited = 0;
112 static int acl_debug_level = 0;
114 * This is the catchall entry. If nothing else appropriate is found, or in
115 * the case where the ACL file is not present, this entry controls what can
116 * be done.
118 static const char *acl_catchall_entry = NULL;
120 /* Solaris Kerberos */
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")
132 * kadm5int_acl_get_line() - Get a line from the ACL file.
133 * Lines ending with \ are continued on the next line
135 static char *
136 kadm5int_acl_get_line(fp, lnp)
137 FILE *fp;
138 int *lnp; /* caller should set to 1 before first call */
140 int i, domore;
141 static int line_incr = 0;
142 static char acl_buf[BUFSIZ];
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 */
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++;
164 /* Check if we exceeded our buffer size */
165 if (i == sizeof acl_buf && (i--, !feof(fp))) {
166 int c1 = acl_buf[i], c2;
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++;
175 c1 = c2;
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;
186 if (domore || (strlen(acl_buf) == 0))
187 return((char *) NULL);
188 else
189 return(acl_buf);
193 * kadm5int_acl_parse_line() - Parse the contents of an ACL line.
195 static aent_t *
196 kadm5int_acl_parse_line(lp)
197 const char *lp;
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;
207 DPRINT(DEBUG_CALLS, acl_debug_level,
208 ("* kadm5int_acl_parse_line(line=%20s)\n", lp));
210 * Format is still simple:
211 * entry ::= [<whitespace>] <principal> <whitespace> <opstring>
212 * [<whitespace> <target> [<whitespace> <restrictions>
213 * [<whitespace>]]]
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;
232 rop = (isupper((unsigned char) *op)) ? tolower((unsigned char) *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;
243 if (!found) {
244 krb5_klog_syslog(LOG_ERR, ACL_OP_BAD_MSG, *op, lp);
245 opok = 0;
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));
258 else {
259 free(acle->ae_target);
260 free(acle);
261 acle = (aent_t *) NULL;
264 else {
265 free(acle->ae_target);
266 free(acle);
267 acle = (aent_t *) NULL;
269 if ( nmatch >= 4 ) {
270 char *trailing;
272 trailing = &acle_restrictions[strlen(acle_restrictions)-1];
273 while ( isspace((int) *trailing) )
274 trailing--;
275 trailing[1] = '\0';
276 acle->ae_restriction_string = strdup(acle_restrictions);
278 else {
279 acle->ae_restriction_string = (char *) NULL;
281 acle->ae_restriction_bad = 0;
282 acle->ae_restrictions = (restriction_t *) NULL;
285 DPRINT(DEBUG_CALLS, acl_debug_level,
286 ("X kadm5int_acl_parse_line() = %x\n", (long) acle));
287 return(acle);
291 * kadm5int_acl_parse_restrictions() - Parse optional restrictions field
293 * Allowed restrictions are:
294 * [+-]flagname (recognized by krb5_string_to_flags)
295 * flag is forced to indicated value
296 * -clearpolicy policy is forced clear
297 * -policy pol policy is forced to be "pol"
298 * -{expire,pwexpire,maxlife,maxrenewlife} deltat
299 * associated value will be forced to
300 * MIN(deltat, requested value)
302 * Returns: 0 on success, or system errors
304 static krb5_error_code
305 kadm5int_acl_parse_restrictions(s, rpp)
306 char *s;
307 restriction_t **rpp;
309 char *sp, *tp, *ap;
310 static const char *delims = "\t\n\f\v\r ,";
311 krb5_deltat dt;
312 krb5_flags flag;
313 krb5_error_code code;
315 DPRINT(DEBUG_CALLS, acl_debug_level,
316 ("* kadm5int_acl_parse_restrictions(s=%20s, rpp=0x%08x)\n", s, (long)rpp));
318 *rpp = (restriction_t *) NULL;
319 code = 0;
320 if (s) {
321 if (!(sp = strdup(s)) /* Don't munge the original */
322 || !(*rpp = (restriction_t *) malloc(sizeof(restriction_t)))) {
323 code = ENOMEM;
324 } else {
325 memset(*rpp, 0, sizeof(**rpp));
326 for (tp=strtok(sp, delims); tp; tp=strtok(NULL, delims)) {
327 flag = 0;
328 if (!krb5_string_to_flags(tp, "+", "-", &flag)) {
329 /* OK, but was it in the positive or negative sense? */
330 if (flag) {
331 (*rpp)->require_attrs |= flag;
332 } else {
333 flag = ~0;
334 (void) krb5_string_to_flags(tp, "+", "-", &flag);
335 (*rpp)->forbid_attrs |= ~flag;
337 (*rpp)->mask |= KADM5_ATTRIBUTES;
338 } else if (!strcmp(tp, "-clearpolicy")) {
339 (*rpp)->mask |= KADM5_POLICY_CLR;
340 } else {
341 /* everything else needs an argument ... */
342 if (!(ap = strtok(NULL, delims))) {
343 code = EINVAL;
344 break;
346 if (!strcmp(tp, "-policy")) {
347 if (!((*rpp)->policy = strdup(ap))) {
348 code = ENOMEM;
349 break;
351 (*rpp)->mask |= KADM5_POLICY;
352 } else {
353 /* all other arguments must be a deltat ... */
354 if (krb5_string_to_deltat(ap, &dt)) {
355 code = EINVAL;
356 break;
358 if (!strcmp(tp, "-expire")) {
359 (*rpp)->princ_lifetime = dt;
360 (*rpp)->mask |= KADM5_PRINC_EXPIRE_TIME;
361 } else if (!strcmp(tp, "-pwexpire")) {
362 (*rpp)->pw_lifetime = dt;
363 (*rpp)->mask |= KADM5_PW_EXPIRATION;
364 } else if (!strcmp(tp, "-maxlife")) {
365 (*rpp)->max_life = dt;
366 (*rpp)->mask |= KADM5_MAX_LIFE;
367 } else if (!strcmp(tp, "-maxrenewlife")) {
368 (*rpp)->max_renewable_life = dt;
369 (*rpp)->mask |= KADM5_MAX_RLIFE;
370 } else {
371 code = EINVAL;
372 break;
379 free(sp);
380 if (*rpp && code) {
381 free((*rpp)->policy);
382 free(*rpp);
383 *rpp = (restriction_t *) NULL;
385 DPRINT(DEBUG_CALLS, acl_debug_level,
386 ("X kadm5int_acl_parse_restrictions() = %d, mask=0x%08x\n",
387 code, (*rpp) ? (*rpp)->mask : 0));
388 return code;
392 * kadm5int_acl_impose_restrictions() - impose restrictions, modifying *recp, *maskp
394 * Returns: 0 on success;
395 * malloc or timeofday errors
397 krb5_error_code
398 kadm5int_acl_impose_restrictions(kcontext, recp, maskp, rp)
399 krb5_context kcontext;
400 kadm5_principal_ent_rec *recp;
401 long *maskp;
402 restriction_t *rp;
404 krb5_error_code code;
405 krb5_int32 now;
407 DPRINT(DEBUG_CALLS, acl_debug_level,
408 ("* kadm5int_acl_impose_restrictions(..., *maskp=0x%08x, rp=0x%08x)\n",
409 *maskp, (long)rp));
410 if (!rp)
411 return 0;
412 if (rp->mask & (KADM5_PRINC_EXPIRE_TIME|KADM5_PW_EXPIRATION))
413 if ((code = krb5_timeofday(kcontext, &now)))
414 return code;
416 if (rp->mask & KADM5_ATTRIBUTES) {
417 recp->attributes |= rp->require_attrs;
418 recp->attributes &= ~(rp->forbid_attrs);
419 *maskp |= KADM5_ATTRIBUTES;
421 if (rp->mask & KADM5_POLICY_CLR) {
422 *maskp &= ~KADM5_POLICY;
423 *maskp |= KADM5_POLICY_CLR;
424 } else if (rp->mask & KADM5_POLICY) {
425 if (recp->policy && strcmp(recp->policy, rp->policy)) {
426 free(recp->policy);
427 recp->policy = (char *) NULL;
429 if (!recp->policy) {
430 recp->policy = strdup(rp->policy); /* XDR will free it */
431 if (!recp->policy)
432 return ENOMEM;
434 *maskp |= KADM5_POLICY;
436 if (rp->mask & KADM5_PRINC_EXPIRE_TIME) {
437 if (!(*maskp & KADM5_PRINC_EXPIRE_TIME)
438 || (recp->princ_expire_time > (now + rp->princ_lifetime)))
439 recp->princ_expire_time = now + rp->princ_lifetime;
440 *maskp |= KADM5_PRINC_EXPIRE_TIME;
442 if (rp->mask & KADM5_PW_EXPIRATION) {
443 if (!(*maskp & KADM5_PW_EXPIRATION)
444 || (recp->pw_expiration > (now + rp->pw_lifetime)))
445 recp->pw_expiration = now + rp->pw_lifetime;
446 *maskp |= KADM5_PW_EXPIRATION;
448 if (rp->mask & KADM5_MAX_LIFE) {
449 if (!(*maskp & KADM5_MAX_LIFE)
450 || (recp->max_life > rp->max_life))
451 recp->max_life = rp->max_life;
452 *maskp |= KADM5_MAX_LIFE;
454 if (rp->mask & KADM5_MAX_RLIFE) {
455 if (!(*maskp & KADM5_MAX_RLIFE)
456 || (recp->max_renewable_life > rp->max_renewable_life))
457 recp->max_renewable_life = rp->max_renewable_life;
458 *maskp |= KADM5_MAX_RLIFE;
460 DPRINT(DEBUG_CALLS, acl_debug_level,
461 ("X kadm5int_acl_impose_restrictions() = 0, *maskp=0x%08x\n", *maskp));
462 return 0;
466 * kadm5int_acl_free_entries() - Free all ACL entries.
468 static void
469 kadm5int_acl_free_entries()
471 aent_t *ap;
472 aent_t *np;
474 DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_free_entries()\n"));
475 for (ap=acl_list_head; ap; ap = np) {
476 free(ap->ae_name);
477 if (ap->ae_principal)
478 krb5_free_principal((krb5_context) NULL, ap->ae_principal);
479 free(ap->ae_target);
480 if (ap->ae_target_princ)
481 krb5_free_principal((krb5_context) NULL, ap->ae_target_princ);
482 free(ap->ae_restriction_string);
483 if (ap->ae_restrictions) {
484 free(ap->ae_restrictions->policy);
485 free(ap->ae_restrictions);
487 np = ap->ae_next;
488 free(ap);
490 acl_list_head = acl_list_tail = (aent_t *) NULL;
491 acl_inited = 0;
492 DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_free_entries()\n"));
496 * kadm5int_acl_load_acl_file() - Open and parse the ACL file.
498 static int
499 kadm5int_acl_load_acl_file()
501 FILE *afp;
502 char *alinep;
503 aent_t **aentpp;
504 int alineno;
505 int retval = 1;
507 DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_load_acl_file()\n"));
508 /* Open the ACL file for read */
509 afp = fopen(acl_acl_file, "rF"); /* Solaris Kerberos */
510 if (afp) {
511 alineno = 1;
512 aentpp = &acl_list_head;
514 /* Get a non-comment line */
515 while ((alinep = kadm5int_acl_get_line(afp, &alineno))) {
516 /* Parse it */
517 *aentpp = kadm5int_acl_parse_line(alinep);
518 /* If syntax error, then fall out */
519 if (!*aentpp) {
520 krb5_klog_syslog(LOG_ERR, ACL_SYN_ERR_MSG,
521 acl_acl_file, alineno, alinep);
522 retval = 0;
523 break;
525 acl_list_tail = *aentpp;
526 aentpp = &(*aentpp)->ae_next;
529 fclose(afp);
531 if (acl_catchall_entry) {
532 *aentpp = kadm5int_acl_parse_line(acl_catchall_entry);
533 if (*aentpp) {
534 acl_list_tail = *aentpp;
536 else {
537 retval = 0;
538 DPRINT(DEBUG_OPERATION, acl_debug_level,
539 ("> catchall acl entry (%s) load failed\n",
540 acl_catchall_entry));
544 else {
545 krb5_klog_syslog(LOG_ERR, ACL_CANTOPEN_MSG,
546 error_message(errno), acl_acl_file);
547 if (acl_catchall_entry &&
548 (acl_list_head = kadm5int_acl_parse_line((char *)acl_catchall_entry))) {
549 acl_list_tail = acl_list_head;
551 else {
552 retval = 0;
553 DPRINT(DEBUG_OPERATION, acl_debug_level,
554 ("> catchall acl entry (%s) load failed\n",
555 acl_catchall_entry));
559 if (!retval) {
560 kadm5int_acl_free_entries();
562 DPRINT(DEBUG_CALLS, acl_debug_level,
563 ("X kadm5int_acl_load_acl_file() = %d\n", retval));
564 return(retval);
568 * kadm5int_acl_match_data() - See if two data entries match.
570 * Wildcarding is only supported for a whole component.
572 static krb5_boolean
573 kadm5int_acl_match_data(e1, e2, targetflag, ws)
574 krb5_data *e1, *e2;
575 int targetflag;
576 wildstate_t *ws;
578 krb5_boolean retval;
580 DPRINT(DEBUG_CALLS, acl_debug_level,
581 ("* acl_match_entry(%s, %s)\n", e1->data, e2->data));
582 retval = 0;
583 if (!strncmp(e1->data, "*", e1->length)) {
584 retval = 1;
585 if (ws && !targetflag) {
586 if (ws->nwild >= 9) {
587 /* Solaris Kerberos */
588 DPRINT(DEBUG_ACL, acl_debug_level,
589 ("Too many wildcards in ACL entry %s\n", e1->data));
591 else
592 ws->backref[ws->nwild++] = e2;
595 else if (ws && targetflag && (e1->length == 2) && (e1->data[0] == '*') &&
596 (e1->data[1] >= '1') && (e1->data[1] <= '9')) {
597 int n = e1->data[1] - '1';
598 if (n >= ws->nwild) {
599 /* Solaris Kerberos */
600 DPRINT(DEBUG_ACL, acl_debug_level,
601 ("Too many backrefs in ACL entry %s\n", e1->data));
603 else if ((ws->backref[n]->length == e2->length) &&
604 (!strncmp(ws->backref[n]->data, e2->data, e2->length)))
605 retval = 1;
608 else {
609 if ((e1->length == e2->length) &&
610 (!strncmp(e1->data, e2->data, e1->length)))
611 retval = 1;
613 DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_match_entry()=%d\n",retval));
614 return(retval);
618 * kadm5int_acl_find_entry() - Find a matching entry.
620 static aent_t *
621 kadm5int_acl_find_entry(kcontext, principal, dest_princ)
622 krb5_context kcontext;
623 krb5_principal principal;
624 krb5_principal dest_princ;
626 aent_t *entry;
627 krb5_error_code kret;
628 int i;
629 int matchgood;
630 wildstate_t state;
632 DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_find_entry()\n"));
633 memset((char *)&state, 0, sizeof state);
634 for (entry=acl_list_head; entry; entry = entry->ae_next) {
635 if (entry->ae_name_bad)
636 continue;
637 if (!strcmp(entry->ae_name, "*")) {
638 DPRINT(DEBUG_ACL, acl_debug_level, ("A wildcard ACL match\n"));
639 matchgood = 1;
641 else {
642 if (!entry->ae_principal && !entry->ae_name_bad) {
643 kret = krb5_parse_name(kcontext,
644 entry->ae_name,
645 &entry->ae_principal);
646 if (kret)
647 entry->ae_name_bad = 1;
649 if (entry->ae_name_bad) {
650 DPRINT(DEBUG_ACL, acl_debug_level,
651 ("Bad ACL entry %s\n", entry->ae_name));
652 continue;
654 matchgood = 0;
655 if (kadm5int_acl_match_data(&entry->ae_principal->realm,
656 &principal->realm, 0, (wildstate_t *)0) &&
657 (entry->ae_principal->length == principal->length)) {
658 matchgood = 1;
659 for (i=0; i<principal->length; i++) {
660 if (!kadm5int_acl_match_data(&entry->ae_principal->data[i],
661 &principal->data[i], 0, &state)) {
662 matchgood = 0;
663 break;
668 if (!matchgood)
669 continue;
671 /* We've matched the principal. If we have a target, then try it */
672 if (entry->ae_target && strcmp(entry->ae_target, "*")) {
673 if (!entry->ae_target_princ && !entry->ae_target_bad) {
674 kret = krb5_parse_name(kcontext, entry->ae_target,
675 &entry->ae_target_princ);
676 if (kret)
677 entry->ae_target_bad = 1;
679 if (entry->ae_target_bad) {
680 DPRINT(DEBUG_ACL, acl_debug_level,
681 ("Bad target in ACL entry for %s\n", entry->ae_name));
682 entry->ae_name_bad = 1;
683 continue;
685 if (!dest_princ)
686 matchgood = 0;
687 else if (entry->ae_target_princ && dest_princ) {
688 if (kadm5int_acl_match_data(&entry->ae_target_princ->realm,
689 &dest_princ->realm, 1, (wildstate_t *)0) &&
690 (entry->ae_target_princ->length == dest_princ->length)) {
691 for (i=0; i<dest_princ->length; i++) {
692 if (!kadm5int_acl_match_data(&entry->ae_target_princ->data[i],
693 &dest_princ->data[i], 1, &state)) {
694 matchgood = 0;
695 break;
699 else
700 matchgood = 0;
703 if (!matchgood)
704 continue;
706 if (entry->ae_restriction_string
707 && !entry->ae_restriction_bad
708 && !entry->ae_restrictions
709 && kadm5int_acl_parse_restrictions(entry->ae_restriction_string,
710 &entry->ae_restrictions)) {
711 DPRINT(DEBUG_ACL, acl_debug_level,
712 ("Bad restrictions in ACL entry for %s\n", entry->ae_name));
713 entry->ae_restriction_bad = 1;
715 if (entry->ae_restriction_bad) {
716 entry->ae_name_bad = 1;
717 continue;
719 break;
721 DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_find_entry()=%x\n",entry));
722 return(entry);
726 * kadm5int_acl_init() - Initialize ACL context.
728 krb5_error_code
729 kadm5int_acl_init(kcontext, debug_level, acl_file)
730 krb5_context kcontext;
731 int debug_level;
732 char *acl_file;
734 krb5_error_code kret;
736 kret = 0;
737 acl_debug_level = debug_level;
738 DPRINT(DEBUG_CALLS, acl_debug_level,
739 ("* kadm5int_acl_init(afile=%s)\n",
740 ((acl_file) ? acl_file : "(null)")));
741 acl_acl_file = (acl_file) ? acl_file : (char *) KRB5_DEFAULT_ADMIN_ACL;
742 acl_inited = kadm5int_acl_load_acl_file();
744 DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_init() = %d\n", kret));
745 return(kret);
749 * kadm5int_acl_finish - Terminate ACL context.
751 void
752 kadm5int_acl_finish(kcontext, debug_level)
753 krb5_context kcontext;
754 int debug_level;
756 DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_finish()\n"));
757 kadm5int_acl_free_entries();
758 DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_finish()\n"));
762 * kadm5int_acl_check() - Is this operation permitted for this principal?
763 * this code used not to be based on gssapi. In order
764 * to minimize porting hassles, I've put all the
765 * gssapi hair in this function. This might not be
766 * the best medium-term solution. (The best long-term
767 * solution is, of course, a real authorization service.)
769 krb5_boolean
770 kadm5int_acl_check(kcontext, caller, opmask, principal, restrictions)
771 krb5_context kcontext;
772 gss_name_t caller;
773 krb5_int32 opmask;
774 krb5_principal principal;
775 restriction_t **restrictions;
777 krb5_boolean retval;
778 aent_t *aentry;
779 gss_buffer_desc caller_buf;
780 gss_OID caller_oid;
781 OM_uint32 emaj, emin;
782 krb5_error_code code;
783 krb5_principal caller_princ;
785 DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_op_permitted()\n"));
787 /* Solaris Kerberos */
788 if (restrictions)
789 *restrictions = NULL;
791 if (GSS_ERROR(emaj = gss_display_name(&emin, caller, &caller_buf,
792 &caller_oid)))
793 return(1);
795 code = krb5_parse_name(kcontext, (char *) caller_buf.value,
796 &caller_princ);
798 gss_release_buffer(&emin, &caller_buf);
800 if (code)
801 return(code);
803 retval = 0;
805 aentry = kadm5int_acl_find_entry(kcontext, caller_princ, principal);
806 if (aentry) {
807 if ((aentry->ae_op_allowed & opmask) == opmask) {
808 retval = 1;
809 if (restrictions) {
810 *restrictions =
811 (aentry->ae_restrictions && aentry->ae_restrictions->mask)
812 ? aentry->ae_restrictions
813 : (restriction_t *) NULL;
818 krb5_free_principal(kcontext, caller_princ);
820 DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_op_permitted()=%d\n",
821 retval));
822 return(retval);
825 kadm5_ret_t
826 kadm5_get_privs(void *server_handle, long *privs)
828 CHECK_HANDLE(server_handle);
830 /* this is impossible to do with the current interface. For now,
831 return all privs, which will confuse some clients, but not
832 deny any access to users of "smart" clients which try to cache */
834 *privs = ~0;
836 return KADM5_OK;
839 /* SUNWresync121 (SEAM1.0) XXX */
840 kadm5_ret_t
841 __kadm5_get_priv(void *server_handle, long *privs, gss_name_t client)
844 aent_t *aentry;
845 gss_buffer_desc caller_buff;
846 gss_OID caller_oid;
847 krb5_principal caller_principal;
848 OM_uint32 minor, major;
849 krb5_error_code k_error;
850 kadm5_ret_t retval = KADM5_FAILURE;
852 kadm5_server_handle_t handle = server_handle;
854 CHECK_HANDLE(server_handle);
856 if (GSS_ERROR(major = gss_display_name(&minor, client, &caller_buff,
857 &caller_oid)))
858 return(retval);
859 k_error = krb5_parse_name(handle->context,
860 (char *) caller_buff.value,
861 &caller_principal);
862 gss_release_buffer(&minor, &caller_buff);
864 if (k_error)
865 return(retval);
867 if (aentry = kadm5int_acl_find_entry(handle->context, caller_principal,
868 (krb5_principal)NULL))
869 *privs = aentry->ae_op_allowed;
870 krb5_free_principal(handle->context, caller_principal);
872 return (KADM5_OK);