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