xref: /onnv-gate/usr/src/lib/krb5/kadm5/srv/server_acl.c (revision 7934:6aeeafc994de)
10Sstevel@tonic-gate /*
2*7934SMark.Phalan@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate 
70Sstevel@tonic-gate /*
80Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
90Sstevel@tonic-gate  *
100Sstevel@tonic-gate  *	Openvision retains the copyright to derivative works of
110Sstevel@tonic-gate  *	this source code.  Do *NOT* create a derivative of this
120Sstevel@tonic-gate  *	source code before consulting with your legal department.
130Sstevel@tonic-gate  *	Do *NOT* integrate *ANY* of this source code into another
140Sstevel@tonic-gate  *	product before consulting with your legal department.
150Sstevel@tonic-gate  *
160Sstevel@tonic-gate  *	For further information, read the top-level Openvision
170Sstevel@tonic-gate  *	copyright which is contained in the top-level MIT Kerberos
180Sstevel@tonic-gate  *	copyright.
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
210Sstevel@tonic-gate  *
220Sstevel@tonic-gate  */
230Sstevel@tonic-gate 
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate  * kadmin/v5server/srv_acl.c
270Sstevel@tonic-gate  *
280Sstevel@tonic-gate  * Copyright 1995 by the Massachusetts Institute of Technology.
290Sstevel@tonic-gate  * All Rights Reserved.
300Sstevel@tonic-gate  *
310Sstevel@tonic-gate  * Export of this software from the United States of America may
320Sstevel@tonic-gate  *   require a specific license from the United States Government.
330Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
340Sstevel@tonic-gate  *   export to obtain such a license before exporting.
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
370Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
380Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
390Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
400Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
410Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
420Sstevel@tonic-gate  * to distribution of the software without specific, written prior
430Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
440Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
450Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
460Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
470Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
480Sstevel@tonic-gate  * or implied warranty.
490Sstevel@tonic-gate  *
500Sstevel@tonic-gate  */
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate  * srv_acl.c - Handle Kerberos ACL related functions.
540Sstevel@tonic-gate  */
550Sstevel@tonic-gate #include <stdio.h>
560Sstevel@tonic-gate #include <syslog.h>
570Sstevel@tonic-gate #include <sys/param.h>
58*7934SMark.Phalan@Sun.COM #include "k5-int.h"
590Sstevel@tonic-gate #include <gssapi_krb5.h>
600Sstevel@tonic-gate #include <kadm5/server_internal.h>
610Sstevel@tonic-gate #include <kadm5/admin.h>
620Sstevel@tonic-gate #include <adm_proto.h> /* SUNWresync121 XXX */
630Sstevel@tonic-gate #include "server_acl.h"
640Sstevel@tonic-gate #include <ctype.h>
650Sstevel@tonic-gate #include <libintl.h> /* SUNWresync121 XXX */
660Sstevel@tonic-gate 
670Sstevel@tonic-gate typedef struct _acl_op_table {
680Sstevel@tonic-gate     char	ao_op;
690Sstevel@tonic-gate     krb5_int32	ao_mask;
700Sstevel@tonic-gate } aop_t;
710Sstevel@tonic-gate 
720Sstevel@tonic-gate typedef struct _acl_entry {
730Sstevel@tonic-gate     struct _acl_entry	*ae_next;
740Sstevel@tonic-gate     char		*ae_name;
750Sstevel@tonic-gate     krb5_boolean	ae_name_bad;
760Sstevel@tonic-gate     krb5_principal	ae_principal;
770Sstevel@tonic-gate     krb5_int32		ae_op_allowed;
780Sstevel@tonic-gate     char		*ae_target;
790Sstevel@tonic-gate     krb5_boolean	ae_target_bad;
800Sstevel@tonic-gate     krb5_principal	ae_target_princ;
810Sstevel@tonic-gate     char		*ae_restriction_string;
820Sstevel@tonic-gate 			/* eg: "-maxlife 3h -service +proxiable" */
830Sstevel@tonic-gate     krb5_boolean	ae_restriction_bad;
840Sstevel@tonic-gate     restriction_t	*ae_restrictions;
850Sstevel@tonic-gate } aent_t;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate static const aop_t acl_op_table[] = {
880Sstevel@tonic-gate     { 'a',	ACL_ADD },
890Sstevel@tonic-gate     { 'd',	ACL_DELETE },
900Sstevel@tonic-gate     { 'm',	ACL_MODIFY },
910Sstevel@tonic-gate     { 'c',	ACL_CHANGEPW },
920Sstevel@tonic-gate     { 'i',	ACL_INQUIRE },
930Sstevel@tonic-gate     { 'l',	ACL_LIST },
940Sstevel@tonic-gate     { 'p',	ACL_IPROP },		/* SUNW IProp */
950Sstevel@tonic-gate     { 's',	ACL_SETKEY },
960Sstevel@tonic-gate     { 'u',	ACL_MIGRATE },		/* pam_krb5_migrate */
970Sstevel@tonic-gate     { 'x',	ACL_ALL_MASK },
980Sstevel@tonic-gate     { '*',	ACL_ALL_MASK },
990Sstevel@tonic-gate     { '\0',	0 }
1000Sstevel@tonic-gate };
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate typedef struct _wildstate {
1030Sstevel@tonic-gate     int		nwild;
1040Sstevel@tonic-gate     krb5_data	*backref[9];
1050Sstevel@tonic-gate } wildstate_t;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate static aent_t	*acl_list_head = (aent_t *) NULL;
1080Sstevel@tonic-gate static aent_t	*acl_list_tail = (aent_t *) NULL;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate static const char *acl_acl_file = (char *) NULL;
1110Sstevel@tonic-gate static int acl_inited = 0;
1120Sstevel@tonic-gate static int acl_debug_level = 0;
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * This is the catchall entry.  If nothing else appropriate is found, or in
1150Sstevel@tonic-gate  * the case where the ACL file is not present, this entry controls what can
1160Sstevel@tonic-gate  * be done.
1170Sstevel@tonic-gate  */
1180Sstevel@tonic-gate static const char *acl_catchall_entry = NULL;
1190Sstevel@tonic-gate 
120*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
1210Sstevel@tonic-gate #define ACL_LINE2LONG_MSG dgettext(TEXT_DOMAIN, \
1220Sstevel@tonic-gate 			"%s: line %d too long, truncated\n")
1230Sstevel@tonic-gate #define ACL_OP_BAD_MSG dgettext(TEXT_DOMAIN, \
1240Sstevel@tonic-gate 			"Unrecognized ACL operation '%c' in %s\n")
1250Sstevel@tonic-gate #define ACL_SYN_ERR_MSG dgettext(TEXT_DOMAIN, \
1260Sstevel@tonic-gate 			"%s: syntax error at line %d <%10s...>\n")
1270Sstevel@tonic-gate #define ACL_CANTOPEN_MSG dgettext(TEXT_DOMAIN, \
1280Sstevel@tonic-gate 			"\007cannot open ACL file")
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate /*
1322881Smp153739  * kadm5int_acl_get_line() - Get a line from the ACL file.
1330Sstevel@tonic-gate  *			Lines ending with \ are continued on the next line
1340Sstevel@tonic-gate  */
1350Sstevel@tonic-gate static char *
kadm5int_acl_get_line(fp,lnp)1362881Smp153739 kadm5int_acl_get_line(fp, lnp)
1370Sstevel@tonic-gate     FILE	*fp;
1380Sstevel@tonic-gate     int		*lnp;		/* caller should set to 1 before first call */
1390Sstevel@tonic-gate {
1400Sstevel@tonic-gate     int		i, domore;
1410Sstevel@tonic-gate     static int	line_incr = 0;
1420Sstevel@tonic-gate     static char acl_buf[BUFSIZ];
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate     *lnp += line_incr;
1450Sstevel@tonic-gate     line_incr = 0;
1460Sstevel@tonic-gate     for (domore = 1; domore && !feof(fp); ) {
1470Sstevel@tonic-gate 	/* Copy in the line, with continuations */
1480Sstevel@tonic-gate 	for (i=0; ((i < sizeof acl_buf) && !feof(fp)); i++ ) {
1490Sstevel@tonic-gate 	    acl_buf[i] = fgetc(fp);
1500Sstevel@tonic-gate 	    if (acl_buf[i] == (char)EOF) {
1510Sstevel@tonic-gate 		if (i > 0 && acl_buf[i-1] == '\\')
1520Sstevel@tonic-gate 		    i--;
1530Sstevel@tonic-gate 		break;		/* it gets nulled-out below */
1540Sstevel@tonic-gate 	    }
1550Sstevel@tonic-gate 	    else if (acl_buf[i] == '\n') {
1560Sstevel@tonic-gate 		if (i == 0 || acl_buf[i-1] != '\\')
1570Sstevel@tonic-gate 		    break;	/* empty line or normal end of line */
1580Sstevel@tonic-gate 		else {
1590Sstevel@tonic-gate 		    i -= 2;	/* back up over "\\\n" and continue */
1600Sstevel@tonic-gate 		    line_incr++;
1610Sstevel@tonic-gate 		}
1620Sstevel@tonic-gate 	    }
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 	/* Check if we exceeded our buffer size */
1650Sstevel@tonic-gate 	if (i == sizeof acl_buf && (i--, !feof(fp))) {
1660Sstevel@tonic-gate 	    int	c1 = acl_buf[i], c2;
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	    krb5_klog_syslog(LOG_ERR, ACL_LINE2LONG_MSG, acl_acl_file, *lnp);
1690Sstevel@tonic-gate 	    while ((c2 = fgetc(fp)) != EOF) {
1700Sstevel@tonic-gate 		if (c2 == '\n') {
1710Sstevel@tonic-gate 		    if (c1 != '\\')
1720Sstevel@tonic-gate 			break;
1730Sstevel@tonic-gate 		    line_incr++;
1740Sstevel@tonic-gate 		}
1750Sstevel@tonic-gate 		c1 = c2;
1760Sstevel@tonic-gate 	    }
1770Sstevel@tonic-gate 	}
1780Sstevel@tonic-gate 	acl_buf[i] = '\0';
1790Sstevel@tonic-gate 	if (acl_buf[0] == (char) EOF)	/* ptooey */
1800Sstevel@tonic-gate 	    acl_buf[0] = '\0';
1810Sstevel@tonic-gate 	else
1820Sstevel@tonic-gate 	    line_incr++;
1830Sstevel@tonic-gate 	if ((acl_buf[0] != '#') && (acl_buf[0] != '\0'))
1840Sstevel@tonic-gate 	    domore = 0;
1850Sstevel@tonic-gate     }
1860Sstevel@tonic-gate     if (domore || (strlen(acl_buf) == 0))
1870Sstevel@tonic-gate 	return((char *) NULL);
1880Sstevel@tonic-gate     else
1890Sstevel@tonic-gate 	return(acl_buf);
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate /*
1932881Smp153739  * kadm5int_acl_parse_line() - Parse the contents of an ACL line.
1940Sstevel@tonic-gate  */
1950Sstevel@tonic-gate static aent_t *
kadm5int_acl_parse_line(lp)1962881Smp153739 kadm5int_acl_parse_line(lp)
1970Sstevel@tonic-gate     const char *lp;
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate     static char acle_principal[BUFSIZ];
2000Sstevel@tonic-gate     static char acle_ops[BUFSIZ];
2010Sstevel@tonic-gate     static char acle_object[BUFSIZ];
2020Sstevel@tonic-gate     static char acle_restrictions[BUFSIZ];
2030Sstevel@tonic-gate     aent_t	*acle;
2040Sstevel@tonic-gate     char	*op;
2050Sstevel@tonic-gate     int		t, found, opok, nmatch;
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate     DPRINT(DEBUG_CALLS, acl_debug_level,
2082881Smp153739 	   ("* kadm5int_acl_parse_line(line=%20s)\n", lp));
2090Sstevel@tonic-gate     /*
2100Sstevel@tonic-gate      * Format is still simple:
2110Sstevel@tonic-gate      *  entry ::= [<whitespace>] <principal> <whitespace> <opstring>
2120Sstevel@tonic-gate      *		  [<whitespace> <target> [<whitespace> <restrictions>
2130Sstevel@tonic-gate      *					  [<whitespace>]]]
2140Sstevel@tonic-gate      */
2150Sstevel@tonic-gate     acle = (aent_t *) NULL;
2160Sstevel@tonic-gate     acle_object[0] = '\0';
2170Sstevel@tonic-gate     nmatch = sscanf(lp, "%s %s %s %[^\n]", acle_principal, acle_ops,
2180Sstevel@tonic-gate 		    acle_object, acle_restrictions);
2190Sstevel@tonic-gate     if (nmatch >= 2) {
2200Sstevel@tonic-gate 	acle = (aent_t *) malloc(sizeof(aent_t));
2210Sstevel@tonic-gate 	if (acle) {
2220Sstevel@tonic-gate 	    acle->ae_next = (aent_t *) NULL;
2230Sstevel@tonic-gate 	    acle->ae_op_allowed = (krb5_int32) 0;
2240Sstevel@tonic-gate 	    acle->ae_target =
2250Sstevel@tonic-gate 		(nmatch >= 3) ? strdup(acle_object) : (char *) NULL;
2260Sstevel@tonic-gate 	    acle->ae_target_bad = 0;
2270Sstevel@tonic-gate 	    acle->ae_target_princ = (krb5_principal) NULL;
2280Sstevel@tonic-gate 	    opok = 1;
2290Sstevel@tonic-gate 	    for (op=acle_ops; *op; op++) {
2300Sstevel@tonic-gate 		char rop;
2310Sstevel@tonic-gate 
232*7934SMark.Phalan@Sun.COM 		rop = (isupper((unsigned char) *op)) ? tolower((unsigned char) *op) : *op;
2330Sstevel@tonic-gate 		found = 0;
2340Sstevel@tonic-gate 		for (t=0; acl_op_table[t].ao_op; t++) {
2350Sstevel@tonic-gate 		    if (rop == acl_op_table[t].ao_op) {
2360Sstevel@tonic-gate 			found = 1;
2370Sstevel@tonic-gate 			if (rop == *op)
2380Sstevel@tonic-gate 			    acle->ae_op_allowed |= acl_op_table[t].ao_mask;
2390Sstevel@tonic-gate 			else
2400Sstevel@tonic-gate 			    acle->ae_op_allowed &= ~acl_op_table[t].ao_mask;
2410Sstevel@tonic-gate 		    }
2420Sstevel@tonic-gate 		}
2430Sstevel@tonic-gate 		if (!found) {
2440Sstevel@tonic-gate 		    krb5_klog_syslog(LOG_ERR, ACL_OP_BAD_MSG, *op, lp);
2450Sstevel@tonic-gate 		    opok = 0;
2460Sstevel@tonic-gate 		}
2470Sstevel@tonic-gate 	    }
2480Sstevel@tonic-gate 	    if (opok) {
2490Sstevel@tonic-gate 		acle->ae_name = (char *) malloc(strlen(acle_principal)+1);
2500Sstevel@tonic-gate 		if (acle->ae_name) {
2510Sstevel@tonic-gate 		    strcpy(acle->ae_name, acle_principal);
2520Sstevel@tonic-gate 		    acle->ae_principal = (krb5_principal) NULL;
2530Sstevel@tonic-gate 		    acle->ae_name_bad = 0;
2540Sstevel@tonic-gate 		    DPRINT(DEBUG_ACL, acl_debug_level,
2550Sstevel@tonic-gate 			   ("A ACL entry %s -> opmask %x\n",
2560Sstevel@tonic-gate 			    acle->ae_name, acle->ae_op_allowed));
2570Sstevel@tonic-gate 		}
2580Sstevel@tonic-gate 		else {
2590Sstevel@tonic-gate 		    if (acle->ae_target)
2600Sstevel@tonic-gate 			free(acle->ae_target);
2610Sstevel@tonic-gate 		    free(acle);
2620Sstevel@tonic-gate 		    acle = (aent_t *) NULL;
2630Sstevel@tonic-gate 		}
2640Sstevel@tonic-gate 	    }
2650Sstevel@tonic-gate 	    else {
2660Sstevel@tonic-gate 		if (acle->ae_target)
2670Sstevel@tonic-gate 		    free(acle->ae_target);
2680Sstevel@tonic-gate 		free(acle);
2690Sstevel@tonic-gate 		acle = (aent_t *) NULL;
2700Sstevel@tonic-gate 	    }
2710Sstevel@tonic-gate 	    if ( nmatch >= 4 ) {
2720Sstevel@tonic-gate 		char	*trailing;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 		trailing = &acle_restrictions[strlen(acle_restrictions)-1];
2752881Smp153739 		while ( isspace((int) *trailing) )
2760Sstevel@tonic-gate 		    trailing--;
2770Sstevel@tonic-gate 		trailing[1] = '\0';
2780Sstevel@tonic-gate 		acle->ae_restriction_string = strdup(acle_restrictions);
2790Sstevel@tonic-gate 	    }
2800Sstevel@tonic-gate 	    else {
2810Sstevel@tonic-gate 		acle->ae_restriction_string = (char *) NULL;
2820Sstevel@tonic-gate 	    }
2830Sstevel@tonic-gate 	    acle->ae_restriction_bad = 0;
2840Sstevel@tonic-gate 	    acle->ae_restrictions = (restriction_t *) NULL;
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate     }
2870Sstevel@tonic-gate     DPRINT(DEBUG_CALLS, acl_debug_level,
2882881Smp153739 	   ("X kadm5int_acl_parse_line() = %x\n", (long) acle));
2890Sstevel@tonic-gate     return(acle);
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate /*
2932881Smp153739  * kadm5int_acl_parse_restrictions() - Parse optional restrictions field
2940Sstevel@tonic-gate  *
2950Sstevel@tonic-gate  * Allowed restrictions are:
2960Sstevel@tonic-gate  *	[+-]flagname		(recognized by krb5_string_to_flags)
2970Sstevel@tonic-gate  *				flag is forced to indicated value
2980Sstevel@tonic-gate  *	-clearpolicy		policy is forced clear
2990Sstevel@tonic-gate  *	-policy pol		policy is forced to be "pol"
3000Sstevel@tonic-gate  *	-{expire,pwexpire,maxlife,maxrenewlife} deltat
3010Sstevel@tonic-gate  *				associated value will be forced to
3020Sstevel@tonic-gate  *				MIN(deltat, requested value)
3030Sstevel@tonic-gate  *
3040Sstevel@tonic-gate  * Returns: 0 on success, or system errors
3050Sstevel@tonic-gate  */
3060Sstevel@tonic-gate static krb5_error_code
kadm5int_acl_parse_restrictions(s,rpp)3072881Smp153739 kadm5int_acl_parse_restrictions(s, rpp)
3080Sstevel@tonic-gate     char		*s;
3090Sstevel@tonic-gate     restriction_t	**rpp;
3100Sstevel@tonic-gate {
3110Sstevel@tonic-gate     char		*sp, *tp, *ap;
3120Sstevel@tonic-gate     static const char	*delims = "\t\n\f\v\r ,";
3130Sstevel@tonic-gate     krb5_deltat		dt;
3140Sstevel@tonic-gate     krb5_flags		flag;
3150Sstevel@tonic-gate     krb5_error_code	code;
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate    DPRINT(DEBUG_CALLS, acl_debug_level,
3182881Smp153739 	   ("* kadm5int_acl_parse_restrictions(s=%20s, rpp=0x%08x)\n", s, (long)rpp));
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate     *rpp = (restriction_t *) NULL;
3210Sstevel@tonic-gate     code = 0;
3222881Smp153739     if (s) {
3230Sstevel@tonic-gate 	if (!(sp = strdup(s))	/* Don't munge the original */
3240Sstevel@tonic-gate 	    || !(*rpp = (restriction_t *) malloc(sizeof(restriction_t)))) {
3250Sstevel@tonic-gate 	    code = ENOMEM;
3260Sstevel@tonic-gate 	} else {
3270Sstevel@tonic-gate 	    memset(*rpp, 0, sizeof(**rpp));
3280Sstevel@tonic-gate 	    for (tp=strtok(sp, delims); tp; tp=strtok((char *)NULL, delims)) {
3290Sstevel@tonic-gate 		flag = 0;
3300Sstevel@tonic-gate 		if (!krb5_string_to_flags(tp, "+", "-", &flag)) {
3310Sstevel@tonic-gate 		    /* OK, but was it in the positive or negative sense? */
3320Sstevel@tonic-gate 		    if (flag) {
3330Sstevel@tonic-gate 			(*rpp)->require_attrs |= flag;
3340Sstevel@tonic-gate 		    } else {
3350Sstevel@tonic-gate 			flag = ~0;
3360Sstevel@tonic-gate 			(void) krb5_string_to_flags(tp, "+", "-", &flag);
3370Sstevel@tonic-gate 			(*rpp)->forbid_attrs |= ~flag;
3380Sstevel@tonic-gate 		    }
3390Sstevel@tonic-gate 		    (*rpp)->mask |= KADM5_ATTRIBUTES;
3400Sstevel@tonic-gate 		} else if (!strcmp(tp, "-clearpolicy")) {
3410Sstevel@tonic-gate 		    (*rpp)->mask |= KADM5_POLICY_CLR;
3420Sstevel@tonic-gate 		} else {
3430Sstevel@tonic-gate 		    /* everything else needs an argument ... */
3440Sstevel@tonic-gate 		    if (!(ap = strtok((char *)NULL, delims))) {
3450Sstevel@tonic-gate 			code = EINVAL;
3460Sstevel@tonic-gate 			break;
3470Sstevel@tonic-gate 		    }
3480Sstevel@tonic-gate 		    if (!strcmp(tp, "-policy")) {
3490Sstevel@tonic-gate 			if (!((*rpp)->policy = strdup(ap))) {
3500Sstevel@tonic-gate 			    code = ENOMEM;
3510Sstevel@tonic-gate 			    break;
3520Sstevel@tonic-gate 			}
3530Sstevel@tonic-gate 			(*rpp)->mask |= KADM5_POLICY;
3540Sstevel@tonic-gate 		    } else {
3550Sstevel@tonic-gate 			/* all other arguments must be a deltat ... */
3560Sstevel@tonic-gate 			if (krb5_string_to_deltat(ap, &dt)) {
3570Sstevel@tonic-gate 			    code = EINVAL;
3580Sstevel@tonic-gate 			    break;
3590Sstevel@tonic-gate 			}
3600Sstevel@tonic-gate 			if (!strcmp(tp, "-expire")) {
3610Sstevel@tonic-gate 			    (*rpp)->princ_lifetime = dt;
3620Sstevel@tonic-gate 			    (*rpp)->mask |= KADM5_PRINC_EXPIRE_TIME;
3630Sstevel@tonic-gate 			} else if (!strcmp(tp, "-pwexpire")) {
3640Sstevel@tonic-gate 			    (*rpp)->pw_lifetime = dt;
3650Sstevel@tonic-gate 			    (*rpp)->mask |= KADM5_PW_EXPIRATION;
3660Sstevel@tonic-gate 			} else if (!strcmp(tp, "-maxlife")) {
3670Sstevel@tonic-gate 			    (*rpp)->max_life = dt;
3680Sstevel@tonic-gate 			    (*rpp)->mask |= KADM5_MAX_LIFE;
3690Sstevel@tonic-gate 			} else if (!strcmp(tp, "-maxrenewlife")) {
3700Sstevel@tonic-gate 			    (*rpp)->max_renewable_life = dt;
3710Sstevel@tonic-gate 			    (*rpp)->mask |= KADM5_MAX_RLIFE;
3720Sstevel@tonic-gate 			} else {
3730Sstevel@tonic-gate 			    code = EINVAL;
3740Sstevel@tonic-gate 			    break;
3750Sstevel@tonic-gate 			}
3760Sstevel@tonic-gate 		    }
3770Sstevel@tonic-gate 		}
3780Sstevel@tonic-gate 	    }
3790Sstevel@tonic-gate 	}
3802881Smp153739     }
3810Sstevel@tonic-gate     if (sp)
3820Sstevel@tonic-gate 	free(sp);
3830Sstevel@tonic-gate     if (*rpp && code) {
3840Sstevel@tonic-gate 	if ((*rpp)->policy)
3850Sstevel@tonic-gate 	    free((*rpp)->policy);
3860Sstevel@tonic-gate 	free(*rpp);
3870Sstevel@tonic-gate 	*rpp = (restriction_t *) NULL;
3880Sstevel@tonic-gate     }
3890Sstevel@tonic-gate     DPRINT(DEBUG_CALLS, acl_debug_level,
3902881Smp153739 	   ("X kadm5int_acl_parse_restrictions() = %d, mask=0x%08x\n",
3910Sstevel@tonic-gate 	    code, (*rpp) ? (*rpp)->mask : 0));
3920Sstevel@tonic-gate     return code;
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate /*
3962881Smp153739  * kadm5int_acl_impose_restrictions()	- impose restrictions, modifying *recp, *maskp
3970Sstevel@tonic-gate  *
3980Sstevel@tonic-gate  * Returns: 0 on success;
3990Sstevel@tonic-gate  *	    malloc or timeofday errors
4000Sstevel@tonic-gate  */
4010Sstevel@tonic-gate krb5_error_code
kadm5int_acl_impose_restrictions(kcontext,recp,maskp,rp)4022881Smp153739 kadm5int_acl_impose_restrictions(kcontext, recp, maskp, rp)
4030Sstevel@tonic-gate      krb5_context		kcontext;
4040Sstevel@tonic-gate      kadm5_principal_ent_rec	*recp;
4050Sstevel@tonic-gate      long			*maskp;
4060Sstevel@tonic-gate      restriction_t		*rp;
4070Sstevel@tonic-gate {
4080Sstevel@tonic-gate     krb5_error_code	code;
4090Sstevel@tonic-gate     krb5_int32		now;
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate     DPRINT(DEBUG_CALLS, acl_debug_level,
4122881Smp153739 	   ("* kadm5int_acl_impose_restrictions(..., *maskp=0x%08x, rp=0x%08x)\n",
4130Sstevel@tonic-gate 	    *maskp, (long)rp));
4140Sstevel@tonic-gate     if (!rp)
4150Sstevel@tonic-gate 	return 0;
4160Sstevel@tonic-gate     if (rp->mask & (KADM5_PRINC_EXPIRE_TIME|KADM5_PW_EXPIRATION))
4170Sstevel@tonic-gate 	if ((code = krb5_timeofday(kcontext, &now)))
4180Sstevel@tonic-gate 	    return code;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate     if (rp->mask & KADM5_ATTRIBUTES) {
4210Sstevel@tonic-gate 	recp->attributes |= rp->require_attrs;
4220Sstevel@tonic-gate 	recp->attributes &= ~(rp->forbid_attrs);
4230Sstevel@tonic-gate 	*maskp |= KADM5_ATTRIBUTES;
4240Sstevel@tonic-gate     }
4250Sstevel@tonic-gate     if (rp->mask & KADM5_POLICY_CLR) {
4260Sstevel@tonic-gate 	*maskp &= ~KADM5_POLICY;
4270Sstevel@tonic-gate 	*maskp |= KADM5_POLICY_CLR;
4280Sstevel@tonic-gate     } else if (rp->mask & KADM5_POLICY) {
4290Sstevel@tonic-gate 	if (recp->policy && strcmp(recp->policy, rp->policy)) {
4300Sstevel@tonic-gate 		free(recp->policy);
4310Sstevel@tonic-gate 		recp->policy = (char *) NULL;
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 	if (!recp->policy) {
4340Sstevel@tonic-gate 	    recp->policy = strdup(rp->policy);  /* XDR will free it */
4350Sstevel@tonic-gate 	    if (!recp->policy)
4360Sstevel@tonic-gate 		return ENOMEM;
4370Sstevel@tonic-gate 	}
4380Sstevel@tonic-gate 	*maskp |= KADM5_POLICY;
4390Sstevel@tonic-gate     }
4400Sstevel@tonic-gate     if (rp->mask & KADM5_PRINC_EXPIRE_TIME) {
4410Sstevel@tonic-gate 	if (!(*maskp & KADM5_PRINC_EXPIRE_TIME)
4420Sstevel@tonic-gate 	    || (recp->princ_expire_time > (now + rp->princ_lifetime)))
4430Sstevel@tonic-gate 	    recp->princ_expire_time = now + rp->princ_lifetime;
4440Sstevel@tonic-gate 	*maskp |= KADM5_PRINC_EXPIRE_TIME;
4450Sstevel@tonic-gate     }
4460Sstevel@tonic-gate     if (rp->mask & KADM5_PW_EXPIRATION) {
4470Sstevel@tonic-gate 	if (!(*maskp & KADM5_PW_EXPIRATION)
4480Sstevel@tonic-gate 	    || (recp->pw_expiration > (now + rp->pw_lifetime)))
4490Sstevel@tonic-gate 	    recp->pw_expiration = now + rp->pw_lifetime;
4500Sstevel@tonic-gate 	*maskp |= KADM5_PW_EXPIRATION;
4510Sstevel@tonic-gate     }
4520Sstevel@tonic-gate     if (rp->mask & KADM5_MAX_LIFE) {
4530Sstevel@tonic-gate 	if (!(*maskp & KADM5_MAX_LIFE)
4540Sstevel@tonic-gate 	    || (recp->max_life > rp->max_life))
4550Sstevel@tonic-gate 	    recp->max_life = rp->max_life;
4560Sstevel@tonic-gate 	*maskp |= KADM5_MAX_LIFE;
4570Sstevel@tonic-gate     }
4580Sstevel@tonic-gate     if (rp->mask & KADM5_MAX_RLIFE) {
4590Sstevel@tonic-gate 	if (!(*maskp & KADM5_MAX_RLIFE)
4600Sstevel@tonic-gate 	    || (recp->max_renewable_life > rp->max_renewable_life))
4610Sstevel@tonic-gate 	    recp->max_renewable_life = rp->max_renewable_life;
4620Sstevel@tonic-gate 	*maskp |= KADM5_MAX_RLIFE;
4630Sstevel@tonic-gate     }
4640Sstevel@tonic-gate     DPRINT(DEBUG_CALLS, acl_debug_level,
4652881Smp153739 	   ("X kadm5int_acl_impose_restrictions() = 0, *maskp=0x%08x\n", *maskp));
4660Sstevel@tonic-gate     return 0;
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate /*
4702881Smp153739  * kadm5int_acl_free_entries() - Free all ACL entries.
4710Sstevel@tonic-gate  */
4720Sstevel@tonic-gate static void
kadm5int_acl_free_entries()4732881Smp153739 kadm5int_acl_free_entries()
4740Sstevel@tonic-gate {
4750Sstevel@tonic-gate     aent_t	*ap;
4760Sstevel@tonic-gate     aent_t	*np;
4770Sstevel@tonic-gate 
4782881Smp153739     DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_free_entries()\n"));
4790Sstevel@tonic-gate     for (ap=acl_list_head; ap; ap = np) {
4800Sstevel@tonic-gate 	if (ap->ae_name)
4810Sstevel@tonic-gate 	    free(ap->ae_name);
4820Sstevel@tonic-gate 	if (ap->ae_principal)
4830Sstevel@tonic-gate 	    krb5_free_principal((krb5_context) NULL, ap->ae_principal);
4840Sstevel@tonic-gate 	if (ap->ae_target)
4850Sstevel@tonic-gate 	    free(ap->ae_target);
4860Sstevel@tonic-gate 	if (ap->ae_target_princ)
4870Sstevel@tonic-gate 	    krb5_free_principal((krb5_context) NULL, ap->ae_target_princ);
4880Sstevel@tonic-gate 	if (ap->ae_restriction_string)
4890Sstevel@tonic-gate 	    free(ap->ae_restriction_string);
4900Sstevel@tonic-gate 	if (ap->ae_restrictions) {
4910Sstevel@tonic-gate 	    if (ap->ae_restrictions->policy)
4920Sstevel@tonic-gate 		free(ap->ae_restrictions->policy);
4930Sstevel@tonic-gate 	    free(ap->ae_restrictions);
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 	np = ap->ae_next;
4960Sstevel@tonic-gate 	free(ap);
4970Sstevel@tonic-gate     }
4980Sstevel@tonic-gate     acl_list_head = acl_list_tail = (aent_t *) NULL;
4990Sstevel@tonic-gate     acl_inited = 0;
5002881Smp153739     DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_free_entries()\n"));
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate /*
5042881Smp153739  * kadm5int_acl_load_acl_file()	- Open and parse the ACL file.
5050Sstevel@tonic-gate  */
5060Sstevel@tonic-gate static int
kadm5int_acl_load_acl_file()5072881Smp153739 kadm5int_acl_load_acl_file()
5080Sstevel@tonic-gate {
5090Sstevel@tonic-gate     FILE 	*afp;
5100Sstevel@tonic-gate     char 	*alinep;
5110Sstevel@tonic-gate     aent_t	**aentpp;
5120Sstevel@tonic-gate     int		alineno;
5130Sstevel@tonic-gate     int		retval = 1;
5140Sstevel@tonic-gate 
5152881Smp153739     DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_load_acl_file()\n"));
5160Sstevel@tonic-gate     /* Open the ACL file for read */
517*7934SMark.Phalan@Sun.COM     afp = fopen(acl_acl_file, "rF"); /* Solaris Kerberos */
5182881Smp153739     if (afp) {
5190Sstevel@tonic-gate 	alineno = 1;
5200Sstevel@tonic-gate 	aentpp = &acl_list_head;
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	/* Get a non-comment line */
5232881Smp153739 	while ((alinep = kadm5int_acl_get_line(afp, &alineno))) {
5240Sstevel@tonic-gate 	    /* Parse it */
5252881Smp153739 	    *aentpp = kadm5int_acl_parse_line(alinep);
5260Sstevel@tonic-gate 	    /* If syntax error, then fall out */
5270Sstevel@tonic-gate 	    if (!*aentpp) {
5280Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, ACL_SYN_ERR_MSG,
5290Sstevel@tonic-gate 			acl_acl_file, alineno, alinep);
5300Sstevel@tonic-gate 		retval = 0;
5310Sstevel@tonic-gate 		break;
5320Sstevel@tonic-gate 	    }
5330Sstevel@tonic-gate 	    acl_list_tail = *aentpp;
5340Sstevel@tonic-gate 	    aentpp = &(*aentpp)->ae_next;
5350Sstevel@tonic-gate 	}
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	fclose(afp);
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	if (acl_catchall_entry) {
5402881Smp153739 	     *aentpp = kadm5int_acl_parse_line(acl_catchall_entry);
5412881Smp153739 	     if (*aentpp) {
5420Sstevel@tonic-gate 		  acl_list_tail = *aentpp;
5430Sstevel@tonic-gate 	     }
5440Sstevel@tonic-gate 	     else {
5450Sstevel@tonic-gate 		  retval = 0;
5460Sstevel@tonic-gate 		  DPRINT(DEBUG_OPERATION, acl_debug_level,
5470Sstevel@tonic-gate 			 ("> catchall acl entry (%s) load failed\n",
5480Sstevel@tonic-gate 			  acl_catchall_entry));
5490Sstevel@tonic-gate 	     }
5500Sstevel@tonic-gate 	}
5510Sstevel@tonic-gate     }
5520Sstevel@tonic-gate     else {
5530Sstevel@tonic-gate 	krb5_klog_syslog(LOG_ERR,  ACL_CANTOPEN_MSG,
5540Sstevel@tonic-gate 			 error_message(errno), acl_acl_file);
5550Sstevel@tonic-gate 	if (acl_catchall_entry &&
5562881Smp153739 	    (acl_list_head = kadm5int_acl_parse_line((char *)acl_catchall_entry))) {
5570Sstevel@tonic-gate 	    acl_list_tail = acl_list_head;
5580Sstevel@tonic-gate 	}
5590Sstevel@tonic-gate 	else {
5600Sstevel@tonic-gate 	    retval = 0;
5610Sstevel@tonic-gate 	    DPRINT(DEBUG_OPERATION, acl_debug_level,
5620Sstevel@tonic-gate 		   ("> catchall acl entry (%s) load failed\n",
5630Sstevel@tonic-gate 		    acl_catchall_entry));
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate     }
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate     if (!retval) {
5682881Smp153739 	kadm5int_acl_free_entries();
5690Sstevel@tonic-gate     }
5700Sstevel@tonic-gate     DPRINT(DEBUG_CALLS, acl_debug_level,
5712881Smp153739 	   ("X kadm5int_acl_load_acl_file() = %d\n", retval));
5720Sstevel@tonic-gate     return(retval);
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate /*
5762881Smp153739  * kadm5int_acl_match_data()	- See if two data entries match.
5770Sstevel@tonic-gate  *
5780Sstevel@tonic-gate  * Wildcarding is only supported for a whole component.
5790Sstevel@tonic-gate  */
5800Sstevel@tonic-gate static krb5_boolean
kadm5int_acl_match_data(e1,e2,targetflag,ws)5812881Smp153739 kadm5int_acl_match_data(e1, e2, targetflag, ws)
5820Sstevel@tonic-gate     krb5_data	*e1, *e2;
5830Sstevel@tonic-gate     int		targetflag;
5840Sstevel@tonic-gate     wildstate_t	*ws;
5850Sstevel@tonic-gate {
5860Sstevel@tonic-gate     krb5_boolean	retval;
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate     DPRINT(DEBUG_CALLS, acl_debug_level,
5890Sstevel@tonic-gate 	   ("* acl_match_entry(%s, %s)\n", e1->data, e2->data));
5900Sstevel@tonic-gate     retval = 0;
5910Sstevel@tonic-gate     if (!strncmp(e1->data, "*", e1->length)) {
5920Sstevel@tonic-gate 	retval = 1;
5930Sstevel@tonic-gate 	if (ws && !targetflag) {
5940Sstevel@tonic-gate 	    if (ws->nwild >= 9) {
595*7934SMark.Phalan@Sun.COM 		/* Solaris Kerberos */
5960Sstevel@tonic-gate 		DPRINT(DEBUG_ACL, acl_debug_level,
5972881Smp153739 		    ("Too many wildcards in ACL entry %s\n", e1->data));
5980Sstevel@tonic-gate 	    }
5990Sstevel@tonic-gate 	    else
6000Sstevel@tonic-gate 		ws->backref[ws->nwild++] = e2;
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate     }
6030Sstevel@tonic-gate     else if (ws && targetflag && (e1->length == 2) && (e1->data[0] == '*') &&
6040Sstevel@tonic-gate 	     (e1->data[1] >= '1') && (e1->data[1] <= '9')) {
6050Sstevel@tonic-gate 	int	n = e1->data[1] - '1';
6060Sstevel@tonic-gate 	if (n >= ws->nwild) {
607*7934SMark.Phalan@Sun.COM 	    /* Solaris Kerberos */
6080Sstevel@tonic-gate 	    DPRINT(DEBUG_ACL, acl_debug_level,
6092881Smp153739 		   ("Too many backrefs in ACL entry %s\n", e1->data));
6100Sstevel@tonic-gate 	}
6110Sstevel@tonic-gate 	else if ((ws->backref[n]->length == e2->length) &&
6120Sstevel@tonic-gate 		 (!strncmp(ws->backref[n]->data, e2->data, e2->length)))
6130Sstevel@tonic-gate 	    retval = 1;
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate     }
6160Sstevel@tonic-gate     else {
6170Sstevel@tonic-gate 	if ((e1->length == e2->length) &&
6180Sstevel@tonic-gate 	    (!strncmp(e1->data, e2->data, e1->length)))
6190Sstevel@tonic-gate 	    retval = 1;
6200Sstevel@tonic-gate     }
6210Sstevel@tonic-gate     DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_match_entry()=%d\n",retval));
6220Sstevel@tonic-gate     return(retval);
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate /*
6262881Smp153739  * kadm5int_acl_find_entry()	- Find a matching entry.
6270Sstevel@tonic-gate  */
6280Sstevel@tonic-gate static aent_t *
kadm5int_acl_find_entry(kcontext,principal,dest_princ)6292881Smp153739 kadm5int_acl_find_entry(kcontext, principal, dest_princ)
6300Sstevel@tonic-gate     krb5_context	kcontext;
6310Sstevel@tonic-gate     krb5_principal	principal;
6320Sstevel@tonic-gate     krb5_principal	dest_princ;
6330Sstevel@tonic-gate {
6340Sstevel@tonic-gate     aent_t		*entry;
6350Sstevel@tonic-gate     krb5_error_code	kret;
6360Sstevel@tonic-gate     int			i;
6370Sstevel@tonic-gate     int			matchgood;
6380Sstevel@tonic-gate     wildstate_t		state;
6390Sstevel@tonic-gate 
6402881Smp153739     DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_find_entry()\n"));
6410Sstevel@tonic-gate     memset((char *)&state, 0, sizeof state);
6420Sstevel@tonic-gate     for (entry=acl_list_head; entry; entry = entry->ae_next) {
6430Sstevel@tonic-gate 	if (entry->ae_name_bad)
6440Sstevel@tonic-gate 	    continue;
6450Sstevel@tonic-gate 	if (!strcmp(entry->ae_name, "*")) {
6460Sstevel@tonic-gate 	    DPRINT(DEBUG_ACL, acl_debug_level, ("A wildcard ACL match\n"));
6470Sstevel@tonic-gate 	    matchgood = 1;
6480Sstevel@tonic-gate 	}
6490Sstevel@tonic-gate 	else {
6500Sstevel@tonic-gate 	    if (!entry->ae_principal && !entry->ae_name_bad) {
6510Sstevel@tonic-gate 		kret = krb5_parse_name(kcontext,
6520Sstevel@tonic-gate 				       entry->ae_name,
6530Sstevel@tonic-gate 				       &entry->ae_principal);
6540Sstevel@tonic-gate 		if (kret)
6550Sstevel@tonic-gate 		    entry->ae_name_bad = 1;
6560Sstevel@tonic-gate 	    }
6570Sstevel@tonic-gate 	    if (entry->ae_name_bad) {
6580Sstevel@tonic-gate 		DPRINT(DEBUG_ACL, acl_debug_level,
6590Sstevel@tonic-gate 		       ("Bad ACL entry %s\n", entry->ae_name));
6600Sstevel@tonic-gate 		continue;
6610Sstevel@tonic-gate 	    }
6620Sstevel@tonic-gate 	    matchgood = 0;
6632881Smp153739 	    if (kadm5int_acl_match_data(&entry->ae_principal->realm,
6640Sstevel@tonic-gate 			       &principal->realm, 0, (wildstate_t *)0) &&
6650Sstevel@tonic-gate 		(entry->ae_principal->length == principal->length)) {
6660Sstevel@tonic-gate 		matchgood = 1;
6670Sstevel@tonic-gate 		for (i=0; i<principal->length; i++) {
6682881Smp153739 		    if (!kadm5int_acl_match_data(&entry->ae_principal->data[i],
6690Sstevel@tonic-gate 					&principal->data[i], 0, &state)) {
6700Sstevel@tonic-gate 			matchgood = 0;
6710Sstevel@tonic-gate 			break;
6720Sstevel@tonic-gate 		    }
6730Sstevel@tonic-gate 		}
6740Sstevel@tonic-gate 	    }
6750Sstevel@tonic-gate 	}
6760Sstevel@tonic-gate 	if (!matchgood)
6770Sstevel@tonic-gate 	    continue;
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	/* We've matched the principal.  If we have a target, then try it */
6802881Smp153739 	if (entry->ae_target && strcmp(entry->ae_target, "*")) {
6810Sstevel@tonic-gate 	    if (!entry->ae_target_princ && !entry->ae_target_bad) {
6820Sstevel@tonic-gate 		kret = krb5_parse_name(kcontext, entry->ae_target,
6830Sstevel@tonic-gate 				       &entry->ae_target_princ);
6840Sstevel@tonic-gate 		if (kret)
6850Sstevel@tonic-gate 		    entry->ae_target_bad = 1;
6860Sstevel@tonic-gate 	    }
6872881Smp153739 	    if (entry->ae_target_bad) {
6882881Smp153739 	        DPRINT(DEBUG_ACL, acl_debug_level,
6892881Smp153739 		       ("Bad target in ACL entry for %s\n", entry->ae_name));
6902881Smp153739 	        entry->ae_name_bad = 1;
6912881Smp153739 	        continue;
6922881Smp153739 	    }
6932881Smp153739 	    if (!dest_princ)
6942881Smp153739 	        matchgood = 0;
6952881Smp153739 	    else if (entry->ae_target_princ && dest_princ) {
6962881Smp153739 	        if (kadm5int_acl_match_data(&entry->ae_target_princ->realm,
6972881Smp153739 			           &dest_princ->realm, 1, (wildstate_t *)0) &&
6982881Smp153739 		    (entry->ae_target_princ->length == dest_princ->length)) {
6992881Smp153739 		    for (i=0; i<dest_princ->length; i++) {
7002881Smp153739 		        if (!kadm5int_acl_match_data(&entry->ae_target_princ->data[i],
7012881Smp153739 			  		    &dest_princ->data[i], 1, &state)) {
7022881Smp153739 			    matchgood = 0;
7032881Smp153739 			    break;
7042881Smp153739 		        }
7050Sstevel@tonic-gate 		    }
7062881Smp153739 	        }
7072881Smp153739 	        else
7082881Smp153739 		    matchgood = 0;
7090Sstevel@tonic-gate 	    }
7102881Smp153739         }
7110Sstevel@tonic-gate 	if (!matchgood)
7120Sstevel@tonic-gate 	    continue;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	if (entry->ae_restriction_string
7150Sstevel@tonic-gate 	    && !entry->ae_restriction_bad
7160Sstevel@tonic-gate 	    && !entry->ae_restrictions
7172881Smp153739 	    && kadm5int_acl_parse_restrictions(entry->ae_restriction_string,
7180Sstevel@tonic-gate 				      &entry->ae_restrictions)) {
7190Sstevel@tonic-gate 	    DPRINT(DEBUG_ACL, acl_debug_level,
7200Sstevel@tonic-gate 		   ("Bad restrictions in ACL entry for %s\n", entry->ae_name));
7210Sstevel@tonic-gate 	    entry->ae_restriction_bad = 1;
7220Sstevel@tonic-gate 	}
7230Sstevel@tonic-gate 	if (entry->ae_restriction_bad) {
7240Sstevel@tonic-gate 	    entry->ae_name_bad = 1;
7250Sstevel@tonic-gate 	    continue;
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 	break;
7280Sstevel@tonic-gate     }
7292881Smp153739     DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_find_entry()=%x\n",entry));
7300Sstevel@tonic-gate     return(entry);
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate /*
7342881Smp153739  * kadm5int_acl_init()	- Initialize ACL context.
7350Sstevel@tonic-gate  */
7360Sstevel@tonic-gate krb5_error_code
kadm5int_acl_init(kcontext,debug_level,acl_file)7372881Smp153739 kadm5int_acl_init(kcontext, debug_level, acl_file)
7380Sstevel@tonic-gate     krb5_context	kcontext;
7390Sstevel@tonic-gate     int			debug_level;
7400Sstevel@tonic-gate     char		*acl_file;
7410Sstevel@tonic-gate {
7420Sstevel@tonic-gate     krb5_error_code	kret;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate     kret = 0;
7450Sstevel@tonic-gate     acl_debug_level = debug_level;
7460Sstevel@tonic-gate     DPRINT(DEBUG_CALLS, acl_debug_level,
7472881Smp153739 	   ("* kadm5int_acl_init(afile=%s)\n",
7480Sstevel@tonic-gate 	    ((acl_file) ? acl_file : "(null)")));
7490Sstevel@tonic-gate     acl_acl_file = (acl_file) ? acl_file : (char *) KRB5_DEFAULT_ADMIN_ACL;
7502881Smp153739     acl_inited = kadm5int_acl_load_acl_file();
7510Sstevel@tonic-gate 
7522881Smp153739     DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_init() = %d\n", kret));
7530Sstevel@tonic-gate     return(kret);
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate /*
7572881Smp153739  * kadm5int_acl_finish	- Terminate ACL context.
7580Sstevel@tonic-gate  */
7590Sstevel@tonic-gate void
kadm5int_acl_finish(kcontext,debug_level)7602881Smp153739 kadm5int_acl_finish(kcontext, debug_level)
7610Sstevel@tonic-gate     krb5_context	kcontext;
7620Sstevel@tonic-gate     int			debug_level;
7630Sstevel@tonic-gate {
7642881Smp153739     DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_finish()\n"));
7652881Smp153739     kadm5int_acl_free_entries();
7662881Smp153739     DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_finish()\n"));
7670Sstevel@tonic-gate }
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate /*
7702881Smp153739  * kadm5int_acl_check()	- Is this operation permitted for this principal?
7710Sstevel@tonic-gate  *			this code used not to be based on gssapi.  In order
7720Sstevel@tonic-gate  *			to minimize porting hassles, I've put all the
7730Sstevel@tonic-gate  *			gssapi hair in this function.  This might not be
7740Sstevel@tonic-gate  *			the best medium-term solution.  (The best long-term
7750Sstevel@tonic-gate  *			solution is, of course, a real authorization service.)
7760Sstevel@tonic-gate  */
7770Sstevel@tonic-gate krb5_boolean
kadm5int_acl_check(kcontext,caller,opmask,principal,restrictions)7782881Smp153739 kadm5int_acl_check(kcontext, caller, opmask, principal, restrictions)
7790Sstevel@tonic-gate     krb5_context	kcontext;
7800Sstevel@tonic-gate     gss_name_t		caller;
7810Sstevel@tonic-gate     krb5_int32		opmask;
7820Sstevel@tonic-gate     krb5_principal	principal;
7830Sstevel@tonic-gate     restriction_t	**restrictions;
7840Sstevel@tonic-gate {
7850Sstevel@tonic-gate     krb5_boolean	retval;
7860Sstevel@tonic-gate     aent_t		*aentry;
7870Sstevel@tonic-gate     gss_buffer_desc	caller_buf;
7880Sstevel@tonic-gate     gss_OID		caller_oid;
7890Sstevel@tonic-gate     OM_uint32		emaj, emin;
7900Sstevel@tonic-gate     krb5_error_code	code;
7910Sstevel@tonic-gate     krb5_principal	caller_princ;
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate     DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_op_permitted()\n"));
7940Sstevel@tonic-gate 
795*7934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
7960Sstevel@tonic-gate     if (restrictions)
7970Sstevel@tonic-gate         *restrictions = NULL;
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate     if (GSS_ERROR(emaj = gss_display_name(&emin, caller, &caller_buf,
8000Sstevel@tonic-gate 					  &caller_oid)))
8010Sstevel@tonic-gate        return(1);
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate     code = krb5_parse_name(kcontext, (char *) caller_buf.value,
8040Sstevel@tonic-gate 			   &caller_princ);
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate     gss_release_buffer(&emin, &caller_buf);
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate     if (code)
8090Sstevel@tonic-gate        return(code);
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate     retval = 0;
8122881Smp153739 
8132881Smp153739     aentry = kadm5int_acl_find_entry(kcontext, caller_princ, principal);
8142881Smp153739     if (aentry) {
8150Sstevel@tonic-gate 	if ((aentry->ae_op_allowed & opmask) == opmask) {
8160Sstevel@tonic-gate 	    retval = 1;
8170Sstevel@tonic-gate 	    if (restrictions) {
8180Sstevel@tonic-gate 		*restrictions =
8190Sstevel@tonic-gate 		    (aentry->ae_restrictions && aentry->ae_restrictions->mask)
8200Sstevel@tonic-gate 		    ? aentry->ae_restrictions
8210Sstevel@tonic-gate 		    : (restriction_t *) NULL;
8220Sstevel@tonic-gate 	    }
8230Sstevel@tonic-gate 	}
8240Sstevel@tonic-gate     }
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate     krb5_free_principal(kcontext, caller_princ);
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate     DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_op_permitted()=%d\n",
8290Sstevel@tonic-gate 					  retval));
8300Sstevel@tonic-gate     return(retval);
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate kadm5_ret_t
kadm5_get_privs(void * server_handle,long * privs)8340Sstevel@tonic-gate kadm5_get_privs(void *server_handle, long *privs)
8350Sstevel@tonic-gate {
8360Sstevel@tonic-gate      CHECK_HANDLE(server_handle);
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate      /* this is impossible to do with the current interface.  For now,
8390Sstevel@tonic-gate 	return all privs, which will confuse some clients, but not
8400Sstevel@tonic-gate 	deny any access to users of "smart" clients which try to cache */
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate      *privs = ~0;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate      return KADM5_OK;
8450Sstevel@tonic-gate }
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate /* SUNWresync121 (SEAM1.0) XXX */
8480Sstevel@tonic-gate kadm5_ret_t
__kadm5_get_priv(void * server_handle,long * privs,gss_name_t client)8490Sstevel@tonic-gate __kadm5_get_priv(void *server_handle, long *privs, gss_name_t client)
8500Sstevel@tonic-gate {
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	aent_t		*aentry;
8530Sstevel@tonic-gate 	gss_buffer_desc	caller_buff;
8540Sstevel@tonic-gate 	gss_OID		caller_oid;
8550Sstevel@tonic-gate 	krb5_principal	caller_principal;
8560Sstevel@tonic-gate 	OM_uint32	minor, major;
8570Sstevel@tonic-gate 	krb5_error_code	k_error;
8580Sstevel@tonic-gate 	kadm5_ret_t	retval = KADM5_FAILURE;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate      kadm5_server_handle_t handle = server_handle;
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate      CHECK_HANDLE(server_handle);
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	if (GSS_ERROR(major = gss_display_name(&minor, client, &caller_buff,
8650Sstevel@tonic-gate 						&caller_oid)))
8660Sstevel@tonic-gate 		return(retval);
8670Sstevel@tonic-gate 	k_error = krb5_parse_name(handle->context,
8680Sstevel@tonic-gate 					(char *) caller_buff.value,
8690Sstevel@tonic-gate 					&caller_principal);
8700Sstevel@tonic-gate 	gss_release_buffer(&minor, &caller_buff);
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	if (k_error)
8730Sstevel@tonic-gate 		return(retval);
8740Sstevel@tonic-gate 
8752881Smp153739 	if (aentry = kadm5int_acl_find_entry(handle->context, caller_principal,
8760Sstevel@tonic-gate 					(krb5_principal)NULL))
8770Sstevel@tonic-gate 		*privs = aentry->ae_op_allowed;
8780Sstevel@tonic-gate 	krb5_free_principal(handle->context, caller_principal);
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	return (KADM5_OK);
8810Sstevel@tonic-gate }
882