/*
- * "$Id: policy.c 4871 2005-12-07 00:41:11Z mike $"
+ * "$Id$"
*
- * Policy routines for the Common UNIX Printing System (CUPS).
+ * Policy routines for the CUPS scheduler.
*
- * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ * Copyright 2007-2011, 2014 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
*
- * These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
- * "LICENSE.txt" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
- *
- * Contents:
- *
- * cupsdAddPolicy() - Add a policy to the system.
- * cupsdAddPolicyOp() - Add an operation to a policy.
- * cupsdCheckPolicy() - Check the IPP operation and username against
- * a policy.
- * cupsdDeleteAllPolicies() - Delete all policies in memory.
- * cupsdFindPolicy() - Find a named policy.
- * cupsdFindPolicyOp() - Find a policy operation.
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*/
/*
*/
#include "cupsd.h"
+#include <pwd.h>
+
+
+/*
+ * Local functions...
+ */
+
+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);
/*
- * 'AddPolicy()' - Add a policy to the system.
+ * 'cupsdAddPolicy()' - Add a policy to the system.
*/
cupsd_policy_t * /* O - Policy */
cupsdAddPolicy(const char *policy) /* I - Name of policy */
{
- cupsd_policy_t *temp, /* Pointer to policy */
- **tempa; /* Pointer to policy array */
+ cupsd_policy_t *temp; /* Pointer to policy */
- if (policy == NULL)
+ if (!policy)
return (NULL);
- if (NumPolicies == 0)
- tempa = malloc(sizeof(cupsd_policy_t *));
- else
- tempa = realloc(Policies, sizeof(cupsd_policy_t *) * (NumPolicies + 1));
+ 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 (tempa == NULL)
+ if (!Policies)
return (NULL);
- Policies = tempa;
- tempa += NumPolicies;
-
if ((temp = calloc(1, sizeof(cupsd_policy_t))) != NULL)
{
- temp->name = strdup(policy);
- *tempa = temp;
-
- NumPolicies ++;
+ cupsdSetString(&temp->name, policy);
+ cupsArrayAdd(Policies, temp);
}
return (temp);
cupsd_location_t *po, /* I - Policy operation to copy */
ipp_op_t op) /* I - IPP operation code */
{
- int i; /* Looping var */
- cupsd_location_t *temp, /* New policy operation */
- **tempa; /* New policy operation array */
- char name[1024]; /* Interface name */
+ cupsd_location_t *temp; /* New policy operation */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPolicyOp(p=%p, po=%p, op=%x(%s))",
p, po, op, ippOpString(op));
- if (p == NULL)
+ if (!p)
return (NULL);
- if (p->num_ops == 0)
- tempa = malloc(sizeof(cupsd_location_t *));
- else
- tempa = realloc(p->ops, sizeof(cupsd_location_t *) * (p->num_ops + 1));
+ 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 (tempa == NULL)
+ if (!p->ops)
return (NULL);
- p->ops = tempa;
-
- if ((temp = calloc(1, sizeof(cupsd_location_t))) != NULL)
+ if ((temp = cupsdCopyLocation(po)) != NULL)
{
- p->ops = tempa;
- tempa[p->num_ops] = temp;
- p->num_ops ++;
-
temp->op = op;
- temp->limit = AUTH_LIMIT_IPP;
-
- if (po)
- {
- /*
- * Copy the specified policy to the new one...
- */
+ temp->limit = CUPSD_AUTH_LIMIT_IPP;
- temp->order_type = po->order_type;
- temp->type = po->type;
- temp->level = po->level;
- temp->satisfy = po->satisfy;
- temp->encryption = po->encryption;
-
- for (i = 0; i < po->num_names; i ++)
- cupsdAddName(temp, po->names[i]);
-
- for (i = 0; i < po->num_allow; i ++)
- switch (po->allow[i].type)
- {
- case AUTH_IP :
- cupsdAllowIP(temp, po->allow[i].mask.ip.address,
- po->allow[i].mask.ip.netmask);
- break;
-
- case AUTH_INTERFACE :
- snprintf(name, sizeof(name), "@IF(%s)",
- po->allow[i].mask.name.name);
- cupsdAllowHost(temp, name);
- break;
-
- default :
- cupsdAllowHost(temp, po->allow[i].mask.name.name);
- break;
- }
-
- for (i = 0; i < po->num_deny; i ++)
- switch (po->deny[i].type)
- {
- case AUTH_IP :
- cupsdDenyIP(temp, po->deny[i].mask.ip.address,
- po->deny[i].mask.ip.netmask);
- break;
-
- case AUTH_INTERFACE :
- snprintf(name, sizeof(name), "@IF(%s)",
- po->deny[i].mask.name.name);
- cupsdDenyHost(temp, name);
- break;
-
- default :
- cupsdDenyHost(temp, po->deny[i].mask.name.name);
- break;
- }
- }
+ cupsArrayAdd(p->ops, temp);
}
return (temp);
if (!p || !con)
{
- cupsdLogMessage(CUPSD_LOG_CRIT, "cupsdCheckPolicy: p=%p, con=%p!", p, con);
+ cupsdLogMessage(CUPSD_LOG_CRIT, "cupsdCheckPolicy: p=%p, con=%p.", p, con);
- return (0);
+ 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 (0);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckPolicy: No matching operation, returning 0.");
+ return ((http_status_t)0);
}
con->best = po;
void
cupsdDeleteAllPolicies(void)
{
- int i, j; /* Looping vars */
- cupsd_policy_t **p; /* Current policy */
- cupsd_location_t **po; /* Current policy op */
+ cupsd_printer_t *printer; /* Current printer */
- if (NumPolicies == 0)
+ if (!Policies)
return;
- for (i = NumPolicies, p = Policies; i > 0; i --, p ++)
- {
- for (j = (*p)->num_ops, po = (*p)->ops; j > 0; j --, po ++)
- {
- cupsdDeleteLocation(*po);
- free(*po);
- }
+ /*
+ * First clear the policy pointers for all printers...
+ */
- if ((*p)->num_ops > 0)
- free((*p)->ops);
+ for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ printer;
+ printer = (cupsd_printer_t *)cupsArrayNext(Printers))
+ printer->op_policy_ptr = NULL;
- free(*p);
- }
+ DefaultPolicyPtr = NULL;
+
+ /*
+ * Then free all of the policies...
+ */
- free(Policies);
+ cupsArrayDelete(Policies);
- NumPolicies = 0;
- Policies = NULL;
+ Policies = NULL;
}
cupsd_policy_t * /* O - Policy */
cupsdFindPolicy(const char *policy) /* I - Name of policy */
{
- int i; /* Looping var */
- cupsd_policy_t **p; /* Current policy */
+ cupsd_policy_t key; /* Search key */
/*
* Range check...
*/
- if (policy == NULL)
+ if (!policy)
return (NULL);
/*
- * Check the operation against the available policies...
+ * Look it up...
*/
- for (i = NumPolicies, p = Policies; i > 0; i --, p ++)
- if (!strcasecmp(policy, (*p)->name))
- return (*p);
-
- return (NULL);
+ key.name = (char *)policy;
+ return ((cupsd_policy_t *)cupsArrayFind(Policies, &key));
}
cupsdFindPolicyOp(cupsd_policy_t *p, /* I - Policy */
ipp_op_t op) /* I - IPP operation */
{
- int i; /* Looping var */
- cupsd_location_t **po; /* Current policy operation */
+ cupsd_location_t key, /* Search key... */
+ *po; /* Current policy operation */
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp(p=%p, op=%x(%s))\n",
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp(p=%p, op=%x(%s))",
p, op, ippOpString(op));
/*
* Range check...
*/
- if (p == NULL)
+ if (!p)
return (NULL);
/*
* Check the operation against the available policies...
*/
- for (i = p->num_ops, po = p->ops; i > 0; i --, po ++)
- if ((*po)->op == op)
+ 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);
+}
+
+
+/*
+ * 'cupsdGetPrivateAttrs()' - Get the private attributes for the current
+ * request.
+ */
+
+cups_array_t * /* O - Array or NULL for no restrictions */
+cupsdGetPrivateAttrs(
+ cupsd_policy_t *policy, /* I - Policy */
+ cupsd_client_t *con, /* I - Client connection */
+ cupsd_printer_t *printer, /* I - Printer, if any */
+ const char *owner) /* I - Owner of object */
+{
+ char *name; /* Current name in access list */
+ cups_array_t *access_ptr, /* Access array */
+ *attrs_ptr; /* Attributes array */
+ const char *username; /* Username associated with request */
+ ipp_attribute_t *attr; /* Attribute from request */
+ struct passwd *pw; /* User info */
+
+
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdGetPrivateAttrs(policy=%p(%s), con=%p(%d), "
+ "printer=%p(%s), owner=\"%s\")", policy, policy->name, con,
+ con->number, printer, printer ? printer->name : "", owner);
+#endif /* DEBUG */
+
+ if (!policy)
+ {
+ cupsdLogMessage(CUPSD_LOG_CRIT, "cupsdGetPrivateAttrs: policy=%p, con=%p, printer=%p, owner=\"%s\", DefaultPolicyPtr=%p: This should never happen, please report a bug.", policy, con, printer, owner, DefaultPolicyPtr);
+ policy = DefaultPolicyPtr;
+ }
+
+ /*
+ * Get the access and attributes lists that correspond to the request...
+ */
+
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: %s",
+ ippOpString(con->request->request.op.operation_id));
+#endif /* DEBUG */
+
+ 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 none of the attributes are private, return NULL now...
+ */
+
+ if ((name = (char *)cupsArrayFirst(attrs_ptr)) != NULL &&
+ !_cups_strcasecmp(name, "none"))
+ {
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+ return (NULL);
+ }
+
+ /*
+ * Otherwise check the user against the access list...
+ */
+
+ 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 /* DEBUG */
+
+ /*
+ * Otherwise check the user against the access list...
+ */
+
+ for (name = (char *)cupsArrayFirst(access_ptr);
+ name;
+ name = (char *)cupsArrayNext(access_ptr))
+ {
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: name=%s", name);
+#endif /* DEBUG */
+
+ if (printer && !_cups_strcasecmp(name, "@ACL"))
+ {
+ char *acl; /* Current ACL user/group */
+
+ for (acl = (char *)cupsArrayFirst(printer->users);
+ acl;
+ acl = (char *)cupsArrayNext(printer->users))
+ {
+ if (acl[0] == '@')
+ {
+ /*
+ * Check group membership...
+ */
+
+ if (cupsdCheckGroup(username, pw, acl + 1))
+ break;
+ }
+ else if (acl[0] == '#')
+ {
+ /*
+ * Check UUID...
+ */
+
+ 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,
- "cupsdFindPolicyOp: Found exact match...");
- return (*po);
+ "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+ return (NULL);
}
+ else if (!_cups_strcasecmp(name, "@SYSTEM"))
+ {
+ int i; /* Looping var */
- for (i = p->num_ops, po = p->ops; i > 0; i --, po ++)
- if ((*po)->op == IPP_ANY_OPERATION)
+ for (i = 0; i < NumSystemGroups; i ++)
+ if (cupsdCheckGroup(username, pw, SystemGroups[i]))
+ {
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+ return (NULL);
+ }
+ }
+ else if (name[0] == '@')
{
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdFindPolicyOp: Found wildcard match...");
- return (*po);
+ if (cupsdCheckGroup(username, pw, name + 1))
+ {
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+ return (NULL);
+ }
}
+ else if (!_cups_strcasecmp(username, name))
+ {
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp: No match found!");
+ return (NULL);
+ }
+ }
- return (NULL);
+ /*
+ * No direct access, so return private attributes list...
+ */
+
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning list.");
+#endif /* DEBUG */
+
+ return (attrs_ptr);
+}
+
+
+/*
+ * 'compare_ops()' - Compare two operations.
+ */
+
+static int /* O - Result of comparison */
+compare_ops(cupsd_location_t *a, /* I - First operation */
+ cupsd_location_t *b) /* I - Second operation */
+{
+ return (a->op - b->op);
+}
+
+
+/*
+ * 'compare_policies()' - Compare two policies.
+ */
+
+static int /* O - Result of comparison */
+compare_policies(cupsd_policy_t *a, /* I - First policy */
+ cupsd_policy_t *b) /* I - Second policy */
+{
+ return (_cups_strcasecmp(a->name, b->name));
+}
+
+
+/*
+ * 'free_policy()' - Free the memory used by a policy.
+ */
+
+static void
+free_policy(cupsd_policy_t *p) /* I - Policy to free */
+{
+ cupsArrayDelete(p->job_access);
+ cupsArrayDelete(p->job_attrs);
+ cupsArrayDelete(p->sub_access);
+ cupsArrayDelete(p->sub_attrs);
+ cupsArrayDelete(p->ops);
+ cupsdClearString(&p->name);
+ free(p);
+}
+
+
+/*
+ * 'hash_op()' - Generate a lookup hash for the operation.
+ */
+
+static int /* O - Hash value */
+hash_op(cupsd_location_t *op) /* I - Operation */
+{
+ return (((op->op >> 6) & 0x40) | (op->op & 0x3f));
}
/*
- * End of "$Id: policy.c 4871 2005-12-07 00:41:11Z mike $".
+ * End of "$Id$".
*/