#include "cupsd.h"
#include <pwd.h>
static int compare_ops(cupsd_location_t *a, cupsd_location_t *b);
static int compare_policies(cupsd_policy_t *a, cupsd_policy_t *b);
static void free_policy(cupsd_policy_t *p);
static int hash_op(cupsd_location_t *op);
cupsd_policy_t *
cupsdAddPolicy(const char *policy)
{
cupsd_policy_t *temp;
if (!policy)
return (NULL);
if (!Policies)
Policies = cupsArrayNew3((cups_array_func_t)compare_policies, NULL,
(cups_ahash_func_t)NULL, 0,
(cups_acopy_func_t)NULL,
(cups_afree_func_t)free_policy);
if (!Policies)
return (NULL);
if ((temp = calloc(1, sizeof(cupsd_policy_t))) != NULL)
{
cupsdSetString(&temp->name, policy);
cupsArrayAdd(Policies, temp);
}
return (temp);
}
cupsd_location_t *
cupsdAddPolicyOp(cupsd_policy_t *p,
cupsd_location_t *po,
ipp_op_t op)
{
cupsd_location_t *temp;
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPolicyOp(p=%p, po=%p, op=%x(%s))",
p, po, op, ippOpString(op));
if (!p)
return (NULL);
if (!p->ops)
p->ops = cupsArrayNew3((cups_array_func_t)compare_ops, NULL,
(cups_ahash_func_t)hash_op, 128,
(cups_acopy_func_t)NULL,
(cups_afree_func_t)cupsdFreeLocation);
if (!p->ops)
return (NULL);
if ((temp = cupsdCopyLocation(po)) != NULL)
{
temp->op = op;
temp->limit = CUPSD_AUTH_LIMIT_IPP;
cupsArrayAdd(p->ops, temp);
}
return (temp);
}
http_status_t
cupsdCheckPolicy(cupsd_policy_t *p,
cupsd_client_t *con,
const char *owner)
{
cupsd_location_t *po;
if (!p || !con)
{
cupsdLogMessage(CUPSD_LOG_CRIT, "cupsdCheckPolicy: p=%p, con=%p!", p, con);
return ((http_status_t)0);
}
if ((po = cupsdFindPolicyOp(p, con->request->request.op.operation_id)) == NULL)
{
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckPolicy: No matching operation, returning 0!");
return ((http_status_t)0);
}
con->best = po;
return (cupsdIsAuthorized(con, owner));
}
void
cupsdDeleteAllPolicies(void)
{
cupsd_printer_t *printer;
if (!Policies)
return;
for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
printer;
printer = (cupsd_printer_t *)cupsArrayNext(Printers))
printer->op_policy_ptr = NULL;
DefaultPolicyPtr = NULL;
cupsArrayDelete(Policies);
Policies = NULL;
}
cupsd_policy_t *
cupsdFindPolicy(const char *policy)
{
cupsd_policy_t key;
if (!policy)
return (NULL);
key.name = (char *)policy;
return ((cupsd_policy_t *)cupsArrayFind(Policies, &key));
}
cupsd_location_t *
cupsdFindPolicyOp(cupsd_policy_t *p,
ipp_op_t op)
{
cupsd_location_t key,
*po;
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp(p=%p, op=%x(%s))",
p, op, ippOpString(op));
if (!p)
return (NULL);
key.op = op;
if ((po = (cupsd_location_t *)cupsArrayFind(p->ops, &key)) != NULL)
{
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdFindPolicyOp: Found exact match...");
return (po);
}
key.op = IPP_ANY_OPERATION;
if ((po = (cupsd_location_t *)cupsArrayFind(p->ops, &key)) != NULL)
{
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdFindPolicyOp: Found wildcard match...");
return (po);
}
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp: No match found!");
return (NULL);
}
cups_array_t *
cupsdGetPrivateAttrs(
cupsd_policy_t *policy,
cupsd_client_t *con,
cupsd_printer_t *printer,
const char *owner)
{
char *name;
cups_array_t *access_ptr,
*attrs_ptr;
const char *username;
ipp_attribute_t *attr;
struct passwd *pw;
#ifdef DEBUG
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdGetPrivateAttrs(policy=%p(%s), con=%p(%d), "
"printer=%p(%s), owner=\"%s\")", policy, policy->name, con,
con->http.fd, printer, printer ? printer->name : "", owner);
#endif
#ifdef DEBUG
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: %s",
ippOpString(con->request->request.op.operation_id));
#endif
switch (con->request->request.op.operation_id)
{
case IPP_GET_SUBSCRIPTIONS :
case IPP_GET_SUBSCRIPTION_ATTRIBUTES :
case IPP_GET_NOTIFICATIONS :
access_ptr = policy->sub_access;
attrs_ptr = policy->sub_attrs;
break;
default :
access_ptr = policy->job_access;
attrs_ptr = policy->job_attrs;
break;
}
if ((name = (char *)cupsArrayFirst(attrs_ptr)) != NULL &&
!_cups_strcasecmp(name, "none"))
{
#ifdef DEBUG
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL.");
#endif
return (NULL);
}
if (con->username[0])
username = con->username;
else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
IPP_TAG_NAME)) != NULL)
username = attr->values[0].string.text;
else
username = "anonymous";
if (username[0])
{
pw = getpwnam(username);
endpwent();
}
else
pw = NULL;
#ifdef DEBUG
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: username=\"%s\"",
username);
#endif
for (name = (char *)cupsArrayFirst(access_ptr);
name;
name = (char *)cupsArrayNext(access_ptr))
{
#ifdef DEBUG
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: name=%s", name);
#endif
if (printer && !_cups_strcasecmp(name, "@ACL"))
{
char *acl;
for (acl = (char *)cupsArrayFirst(printer->users);
acl;
acl = (char *)cupsArrayNext(printer->users))
{
if (acl[0] == '@')
{
if (cupsdCheckGroup(username, pw, acl + 1))
break;
}
else if (acl[0] == '#')
{
if (cupsdCheckGroup(username, pw, acl))
break;
}
else if (!_cups_strcasecmp(username, acl))
break;
}
}
else if (owner && !_cups_strcasecmp(name, "@OWNER") &&
!_cups_strcasecmp(username, owner))
{
#ifdef DEBUG
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdGetPrivateAttrs: Returning NULL.");
#endif
return (NULL);
}
else if (!_cups_strcasecmp(name, "@SYSTEM"))
{
int i;
for (i = 0; i < NumSystemGroups; i ++)
if (cupsdCheckGroup(username, pw, SystemGroups[i]))
{
#ifdef DEBUG
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdGetPrivateAttrs: Returning NULL.");
#endif
return (NULL);
}
}
else if (name[0] == '@')
{
if (cupsdCheckGroup(username, pw, name + 1))
{
#ifdef DEBUG
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdGetPrivateAttrs: Returning NULL.");
#endif
return (NULL);
}
}
else if (!_cups_strcasecmp(username, name))
{
#ifdef DEBUG
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL.");
#endif
return (NULL);
}
}
#ifdef DEBUG
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning list.");
#endif
return (attrs_ptr);
}
static int
compare_ops(cupsd_location_t *a,
cupsd_location_t *b)
{
return (a->op - b->op);
}
static int
compare_policies(cupsd_policy_t *a,
cupsd_policy_t *b)
{
return (_cups_strcasecmp(a->name, b->name));
}
static void
free_policy(cupsd_policy_t *p)
{
cupsArrayDelete(p->job_access);
cupsArrayDelete(p->job_attrs);
cupsArrayDelete(p->sub_access);
cupsArrayDelete(p->sub_attrs);
cupsArrayDelete(p->ops);
cupsdClearString(&p->name);
free(p);
}
static int
hash_op(cupsd_location_t *op)
{
return (((op->op >> 6) & 0x40) | (op->op & 0x3f));
}