server_acl.c revision 56a424cca6b3f91f31bdab72a4626c48c779fe8b
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
*
* Openvision retains the copyright to derivative works of
* this source code. Do *NOT* create a derivative of this
* source code before consulting with your legal department.
* Do *NOT* integrate *ANY* of this source code into another
* product before consulting with your legal department.
*
* For further information, read the top-level Openvision
* copyright which is contained in the top-level MIT Kerberos
* copyright.
*
* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
*
*/
/*
*
* Copyright 1995 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
*/
/*
* srv_acl.c - Handle Kerberos ACL related functions.
*/
#include <stdio.h>
#include <syslog.h>
#include <gssapi_krb5.h>
#include "k5-int.h"
#include <kadm5/server_internal.h>
#include <adm_proto.h> /* SUNWresync121 XXX */
#include "server_acl.h"
#include <ctype.h>
#include <libintl.h> /* SUNWresync121 XXX */
typedef struct _acl_op_table {
char ao_op;
} aop_t;
typedef struct _acl_entry {
struct _acl_entry *ae_next;
char *ae_name;
char *ae_target;
char *ae_restriction_string;
/* eg: "-maxlife 3h -service +proxiable" */
} aent_t;
static const aop_t acl_op_table[] = {
{ 'a', ACL_ADD },
{ 'd', ACL_DELETE },
{ 'm', ACL_MODIFY },
{ 'c', ACL_CHANGEPW },
{ 'i', ACL_INQUIRE },
{ 'l', ACL_LIST },
{ 's', ACL_SETKEY },
{ 'x', ACL_ALL_MASK },
{ '*', ACL_ALL_MASK },
{ '\0', 0 }
};
typedef struct _wildstate {
int nwild;
} wildstate_t;
static const char *acl_acl_file = (char *) NULL;
static int acl_inited = 0;
static int acl_debug_level = 0;
/*
* This is the catchall entry. If nothing else appropriate is found, or in
* the case where the ACL file is not present, this entry controls what can
* be done.
*/
static const char *acl_catchall_entry = NULL;
"%s: line %d too long, truncated\n")
"Unrecognized ACL operation '%c' in %s\n")
"%s: syntax error at line %d <%10s...>\n")
"\007cannot open ACL file")
/*
* kadm5int_acl_get_line() - Get a line from the ACL file.
* Lines ending with \ are continued on the next line
*/
static char *
int *lnp; /* caller should set to 1 before first call */
{
int i, domore;
static int line_incr = 0;
line_incr = 0;
/* Copy in the line, with continuations */
i--;
break; /* it gets nulled-out below */
}
else if (acl_buf[i] == '\n') {
break; /* empty line or normal end of line */
else {
i -= 2; /* back up over "\\\n" and continue */
line_incr++;
}
}
}
/* Check if we exceeded our buffer size */
if (c2 == '\n') {
if (c1 != '\\')
break;
line_incr++;
}
}
}
acl_buf[i] = '\0';
acl_buf[0] = '\0';
else
line_incr++;
domore = 0;
}
return((char *) NULL);
else
return(acl_buf);
}
/*
* kadm5int_acl_parse_line() - Parse the contents of an ACL line.
*/
static aent_t *
const char *lp;
{
static char acle_principal[BUFSIZ];
static char acle_object[BUFSIZ];
static char acle_restrictions[BUFSIZ];
char *op;
("* kadm5int_acl_parse_line(line=%20s)\n", lp));
/*
* Format is still simple:
* entry ::= [<whitespace>] <principal> <whitespace> <opstring>
* [<whitespace> <target> [<whitespace> <restrictions>
* [<whitespace>]]]
*/
acle_object[0] = '\0';
if (nmatch >= 2) {
if (acle) {
acle->ae_target_bad = 0;
opok = 1;
char rop;
found = 0;
for (t=0; acl_op_table[t].ao_op; t++) {
found = 1;
else
}
}
if (!found) {
opok = 0;
}
}
if (opok) {
acle->ae_name_bad = 0;
("A ACL entry %s -> opmask %x\n",
}
else {
}
}
else {
}
if ( nmatch >= 4 ) {
char *trailing;
trailing--;
}
else {
}
acle->ae_restriction_bad = 0;
}
}
("X kadm5int_acl_parse_line() = %x\n", (long) acle));
return(acle);
}
/*
* kadm5int_acl_parse_restrictions() - Parse optional restrictions field
*
* Allowed restrictions are:
* [+-]flagname (recognized by krb5_string_to_flags)
* flag is forced to indicated value
* -clearpolicy policy is forced clear
* -policy pol policy is forced to be "pol"
* -{expire,pwexpire,maxlife,maxrenewlife} deltat
* associated value will be forced to
* MIN(deltat, requested value)
*
* Returns: 0 on success, or system errors
*/
static krb5_error_code
char *s;
restriction_t **rpp;
{
static const char *delims = "\t\n\f\v\r ,";
("* kadm5int_acl_parse_restrictions(s=%20s, rpp=0x%08x)\n", s, (long)rpp));
code = 0;
if (s) {
} else {
flag = 0;
/* OK, but was it in the positive or negative sense? */
if (flag) {
} else {
flag = ~0;
}
} else {
/* everything else needs an argument ... */
break;
}
break;
}
} else {
/* all other arguments must be a deltat ... */
break;
}
} else {
break;
}
}
}
}
}
}
if (sp)
}
("X kadm5int_acl_parse_restrictions() = %d, mask=0x%08x\n",
return code;
}
/*
* kadm5int_acl_impose_restrictions() - impose restrictions, modifying *recp, *maskp
*
* Returns: 0 on success;
* malloc or timeofday errors
*/
long *maskp;
{
("* kadm5int_acl_impose_restrictions(..., *maskp=0x%08x, rp=0x%08x)\n",
if (!rp)
return 0;
return code;
*maskp |= KADM5_ATTRIBUTES;
}
*maskp &= ~KADM5_POLICY;
*maskp |= KADM5_POLICY_CLR;
}
return ENOMEM;
}
*maskp |= KADM5_POLICY;
}
if (!(*maskp & KADM5_PRINC_EXPIRE_TIME)
}
if (!(*maskp & KADM5_PW_EXPIRATION)
*maskp |= KADM5_PW_EXPIRATION;
}
if (!(*maskp & KADM5_MAX_LIFE)
*maskp |= KADM5_MAX_LIFE;
}
if (!(*maskp & KADM5_MAX_RLIFE)
*maskp |= KADM5_MAX_RLIFE;
}
("X kadm5int_acl_impose_restrictions() = 0, *maskp=0x%08x\n", *maskp));
return 0;
}
/*
* kadm5int_acl_free_entries() - Free all ACL entries.
*/
static void
{
if (ap->ae_principal)
if (ap->ae_target_princ)
if (ap->ae_restriction_string)
if (ap->ae_restrictions) {
}
}
acl_inited = 0;
}
/*
* kadm5int_acl_load_acl_file() - Open and parse the ACL file.
*/
static int
{
char *alinep;
int alineno;
int retval = 1;
/* Open the ACL file for read */
if (afp) {
alineno = 1;
aentpp = &acl_list_head;
/* Get a non-comment line */
/* Parse it */
/* If syntax error, then fall out */
if (!*aentpp) {
retval = 0;
break;
}
acl_list_tail = *aentpp;
}
if (acl_catchall_entry) {
if (*aentpp) {
acl_list_tail = *aentpp;
}
else {
retval = 0;
("> catchall acl entry (%s) load failed\n",
}
}
}
else {
if (acl_catchall_entry &&
}
else {
retval = 0;
("> catchall acl entry (%s) load failed\n",
}
}
if (!retval) {
}
("X kadm5int_acl_load_acl_file() = %d\n", retval));
return(retval);
}
/*
* kadm5int_acl_match_data() - See if two data entries match.
*
* Wildcarding is only supported for a whole component.
*/
static krb5_boolean
int targetflag;
{
retval = 0;
retval = 1;
if (ws && !targetflag) {
}
else
}
}
}
retval = 1;
}
else {
retval = 1;
}
return(retval);
}
/*
* kadm5int_acl_find_entry() - Find a matching entry.
*/
static aent_t *
{
int i;
int matchgood;
if (entry->ae_name_bad)
continue;
matchgood = 1;
}
else {
&entry->ae_principal);
if (kret)
}
if (entry->ae_name_bad) {
continue;
}
matchgood = 0;
matchgood = 1;
matchgood = 0;
break;
}
}
}
}
if (!matchgood)
continue;
/* We've matched the principal. If we have a target, then try it */
&entry->ae_target_princ);
if (kret)
}
if (entry->ae_target_bad) {
continue;
}
if (!dest_princ)
matchgood = 0;
for (i=0; i<dest_princ->length; i++) {
matchgood = 0;
break;
}
}
}
else
matchgood = 0;
}
}
if (!matchgood)
continue;
&& !entry->ae_restriction_bad
&& !entry->ae_restrictions
&entry->ae_restrictions)) {
}
if (entry->ae_restriction_bad) {
continue;
}
break;
}
return(entry);
}
/*
* kadm5int_acl_init() - Initialize ACL context.
*/
int debug_level;
char *acl_file;
{
kret = 0;
("* kadm5int_acl_init(afile=%s)\n",
return(kret);
}
/*
* kadm5int_acl_finish - Terminate ACL context.
*/
void
int debug_level;
{
}
/*
* kadm5int_acl_check() - Is this operation permitted for this principal?
* this code used not to be based on gssapi. In order
* to minimize porting hassles, I've put all the
* gssapi hair in this function. This might not be
* the best medium-term solution. (The best long-term
* solution is, of course, a real authorization service.)
*/
{
if (restrictions)
*restrictions = NULL;
&caller_oid)))
return(1);
&caller_princ);
if (code)
return(code);
retval = 0;
if (aentry) {
retval = 1;
if (restrictions) {
*restrictions =
: (restriction_t *) NULL;
}
}
}
retval));
return(retval);
}
{
/* this is impossible to do with the current interface. For now,
return all privs, which will confuse some clients, but not
deny any access to users of "smart" clients which try to cache */
*privs = ~0;
return KADM5_OK;
}
/* SUNWresync121 (SEAM1.0) XXX */
{
&caller_oid)))
return(retval);
(char *) caller_buff.value,
if (k_error)
return(retval);
return (KADM5_OK);
}