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