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