Bump to cups 2.3.3
[platform/upstream/cups.git] / scheduler / policy.c
1 /*
2  * Policy routines for the CUPS scheduler.
3  *
4  * Copyright 2007-2011, 2014 by Apple Inc.
5  * Copyright 1997-2006 by Easy Software Products, all rights reserved.
6  *
7  * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
8  */
9
10 /*
11  * Include necessary headers...
12  */
13
14 #include "cupsd.h"
15 #include <pwd.h>
16
17
18 /*
19  * Local functions...
20  */
21
22 static int      compare_ops(cupsd_location_t *a, cupsd_location_t *b);
23 static int      compare_policies(cupsd_policy_t *a, cupsd_policy_t *b);
24 static void     free_policy(cupsd_policy_t *p);
25 static int      hash_op(cupsd_location_t *op);
26
27
28 /*
29  * 'cupsdAddPolicy()' - Add a policy to the system.
30  */
31
32 cupsd_policy_t *                        /* O - Policy */
33 cupsdAddPolicy(const char *policy)      /* I - Name of policy */
34 {
35   cupsd_policy_t        *temp;          /* Pointer to policy */
36
37
38   if (!policy)
39     return (NULL);
40
41   if (!Policies)
42     Policies = cupsArrayNew3((cups_array_func_t)compare_policies, NULL,
43                              (cups_ahash_func_t)NULL, 0,
44                              (cups_acopy_func_t)NULL,
45                              (cups_afree_func_t)free_policy);
46
47   if (!Policies)
48     return (NULL);
49
50   if ((temp = calloc(1, sizeof(cupsd_policy_t))) != NULL)
51   {
52     cupsdSetString(&temp->name, policy);
53     cupsArrayAdd(Policies, temp);
54   }
55
56   return (temp);
57 }
58
59
60 /*
61  * 'cupsdAddPolicyOp()' - Add an operation to a policy.
62  */
63
64 cupsd_location_t *                      /* O - New policy operation */
65 cupsdAddPolicyOp(cupsd_policy_t   *p,   /* I - Policy */
66                  cupsd_location_t *po,  /* I - Policy operation to copy */
67                  ipp_op_t         op)   /* I - IPP operation code */
68 {
69   cupsd_location_t      *temp;          /* New policy operation */
70
71
72   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPolicyOp(p=%p, po=%p, op=%x(%s))",
73                   p, po, op, ippOpString(op));
74
75   if (!p)
76     return (NULL);
77
78   if (!p->ops)
79     p->ops = cupsArrayNew3((cups_array_func_t)compare_ops, NULL,
80                            (cups_ahash_func_t)hash_op, 128,
81                            (cups_acopy_func_t)NULL,
82                            (cups_afree_func_t)cupsdFreeLocation);
83
84   if (!p->ops)
85     return (NULL);
86
87   if ((temp = cupsdCopyLocation(po)) != NULL)
88   {
89     temp->op    = op;
90     temp->limit = CUPSD_AUTH_LIMIT_IPP;
91
92     cupsArrayAdd(p->ops, temp);
93   }
94
95   return (temp);
96 }
97
98
99 /*
100  * 'cupsdCheckPolicy()' - Check the IPP operation and username against a policy.
101  */
102
103 http_status_t                           /* I - 1 if OK, 0 otherwise */
104 cupsdCheckPolicy(cupsd_policy_t *p,     /* I - Policy */
105                  cupsd_client_t *con,   /* I - Client connection */
106                  const char     *owner) /* I - Owner of object */
107 {
108   cupsd_location_t      *po;            /* Current policy operation */
109
110
111  /*
112   * Range check...
113   */
114
115   if (!p || !con)
116   {
117     cupsdLogMessage(CUPSD_LOG_CRIT, "cupsdCheckPolicy: p=%p, con=%p.", p, con);
118
119     return ((http_status_t)0);
120   }
121
122  /*
123   * Find a match for the operation...
124   */
125
126   if ((po = cupsdFindPolicyOp(p, con->request->request.op.operation_id)) == NULL)
127   {
128     cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckPolicy: No matching operation, returning 0.");
129     return ((http_status_t)0);
130   }
131
132   con->best = po;
133
134  /*
135   * Return the status of the check...
136   */
137
138   return (cupsdIsAuthorized(con, owner));
139 }
140
141
142 /*
143  * 'cupsdDeleteAllPolicies()' - Delete all policies in memory.
144  */
145
146 void
147 cupsdDeleteAllPolicies(void)
148 {
149   cupsd_printer_t       *printer;       /* Current printer */
150
151
152   if (!Policies)
153     return;
154
155  /*
156   * First clear the policy pointers for all printers...
157   */
158
159   for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
160        printer;
161        printer = (cupsd_printer_t *)cupsArrayNext(Printers))
162     printer->op_policy_ptr = NULL;
163
164   DefaultPolicyPtr = NULL;
165
166  /*
167   * Then free all of the policies...
168   */
169
170   cupsArrayDelete(Policies);
171
172   Policies = NULL;
173 }
174
175
176 /*
177  * 'cupsdFindPolicy()' - Find a named policy.
178  */
179
180 cupsd_policy_t *                        /* O - Policy */
181 cupsdFindPolicy(const char *policy)     /* I - Name of policy */
182 {
183   cupsd_policy_t        key;            /* Search key */
184
185
186  /*
187   * Range check...
188   */
189
190   if (!policy)
191     return (NULL);
192
193  /*
194   * Look it up...
195   */
196
197   key.name = (char *)policy;
198   return ((cupsd_policy_t *)cupsArrayFind(Policies, &key));
199 }
200
201
202 /*
203  * 'cupsdFindPolicyOp()' - Find a policy operation.
204  */
205
206 cupsd_location_t *                      /* O - Policy operation */
207 cupsdFindPolicyOp(cupsd_policy_t *p,    /* I - Policy */
208                   ipp_op_t       op)    /* I - IPP operation */
209 {
210   cupsd_location_t      key,            /* Search key... */
211                         *po;            /* Current policy operation */
212
213
214   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp(p=%p, op=%x(%s))",
215                   p, op, ippOpString(op));
216
217  /*
218   * Range check...
219   */
220
221   if (!p)
222     return (NULL);
223
224  /*
225   * Check the operation against the available policies...
226   */
227
228   key.op = op;
229   if ((po = (cupsd_location_t *)cupsArrayFind(p->ops, &key)) != NULL)
230   {
231     cupsdLogMessage(CUPSD_LOG_DEBUG2,
232                     "cupsdFindPolicyOp: Found exact match...");
233     return (po);
234   }
235
236   key.op = IPP_ANY_OPERATION;
237   if ((po = (cupsd_location_t *)cupsArrayFind(p->ops, &key)) != NULL)
238   {
239     cupsdLogMessage(CUPSD_LOG_DEBUG2,
240                     "cupsdFindPolicyOp: Found wildcard match...");
241     return (po);
242   }
243
244   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp: No match found.");
245
246   return (NULL);
247 }
248
249
250 /*
251  * 'cupsdGetPrivateAttrs()' - Get the private attributes for the current
252  *                            request.
253  */
254
255 cups_array_t *                          /* O - Array or NULL for no restrictions */
256 cupsdGetPrivateAttrs(
257     cupsd_policy_t  *policy,            /* I - Policy */
258     cupsd_client_t  *con,               /* I - Client connection */
259     cupsd_printer_t *printer,           /* I - Printer, if any */
260     const char      *owner)             /* I - Owner of object */
261 {
262   char          *name;                  /* Current name in access list */
263   cups_array_t  *access_ptr,            /* Access array */
264                 *attrs_ptr;             /* Attributes array */
265   const char    *username;              /* Username associated with request */
266   ipp_attribute_t *attr;                /* Attribute from request */
267   struct passwd *pw;                    /* User info */
268
269
270 #ifdef DEBUG
271   cupsdLogMessage(CUPSD_LOG_DEBUG2,
272                   "cupsdGetPrivateAttrs(policy=%p(%s), con=%p(%d), "
273                   "printer=%p(%s), owner=\"%s\")", policy, policy->name, con,
274                   con->number, printer, printer ? printer->name : "", owner);
275 #endif /* DEBUG */
276
277   if (!policy)
278   {
279     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);
280     policy = DefaultPolicyPtr;
281   }
282
283  /*
284   * Get the access and attributes lists that correspond to the request...
285   */
286
287 #ifdef DEBUG
288   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: %s",
289                   ippOpString(con->request->request.op.operation_id));
290 #endif /* DEBUG */
291
292   switch (con->request->request.op.operation_id)
293   {
294     case IPP_GET_SUBSCRIPTIONS :
295     case IPP_GET_SUBSCRIPTION_ATTRIBUTES :
296     case IPP_GET_NOTIFICATIONS :
297         access_ptr = policy->sub_access;
298         attrs_ptr  = policy->sub_attrs;
299         break;
300
301     default :
302         access_ptr = policy->job_access;
303         attrs_ptr  = policy->job_attrs;
304         break;
305   }
306
307  /*
308   * If none of the attributes are private, return NULL now...
309   */
310
311   if ((name = (char *)cupsArrayFirst(attrs_ptr)) != NULL &&
312       !_cups_strcasecmp(name, "none"))
313   {
314 #ifdef DEBUG
315     cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL.");
316 #endif /* DEBUG */
317
318     return (NULL);
319   }
320
321  /*
322   * Otherwise check the user against the access list...
323   */
324
325   if (con->username[0])
326     username = con->username;
327   else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
328                                     IPP_TAG_NAME)) != NULL)
329     username = attr->values[0].string.text;
330   else
331     username = "anonymous";
332
333   if (username[0])
334   {
335     pw = getpwnam(username);
336     endpwent();
337   }
338   else
339     pw = NULL;
340
341 #ifdef DEBUG
342   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: username=\"%s\"",
343                   username);
344 #endif /* DEBUG */
345
346  /*
347   * Otherwise check the user against the access list...
348   */
349
350   for (name = (char *)cupsArrayFirst(access_ptr);
351        name;
352        name = (char *)cupsArrayNext(access_ptr))
353   {
354 #ifdef DEBUG
355     cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: name=%s", name);
356 #endif /* DEBUG */
357
358     if (printer && !_cups_strcasecmp(name, "@ACL"))
359     {
360       char      *acl;                   /* Current ACL user/group */
361
362       for (acl = (char *)cupsArrayFirst(printer->users);
363            acl;
364            acl = (char *)cupsArrayNext(printer->users))
365       {
366         if (acl[0] == '@')
367         {
368          /*
369           * Check group membership...
370           */
371
372           if (cupsdCheckGroup(username, pw, acl + 1))
373             break;
374         }
375         else if (acl[0] == '#')
376         {
377          /*
378           * Check UUID...
379           */
380
381           if (cupsdCheckGroup(username, pw, acl))
382             break;
383         }
384         else if (!_cups_strcasecmp(username, acl))
385           break;
386       }
387     }
388     else if (owner && !_cups_strcasecmp(name, "@OWNER") &&
389              !_cups_strcasecmp(username, owner))
390     {
391 #ifdef DEBUG
392       cupsdLogMessage(CUPSD_LOG_DEBUG2,
393                       "cupsdGetPrivateAttrs: Returning NULL.");
394 #endif /* DEBUG */
395
396       return (NULL);
397     }
398     else if (!_cups_strcasecmp(name, "@SYSTEM"))
399     {
400       int i;                            /* Looping var */
401
402       for (i = 0; i < NumSystemGroups; i ++)
403         if (cupsdCheckGroup(username, pw, SystemGroups[i]))
404         {
405 #ifdef DEBUG
406           cupsdLogMessage(CUPSD_LOG_DEBUG2,
407                           "cupsdGetPrivateAttrs: Returning NULL.");
408 #endif /* DEBUG */
409
410           return (NULL);
411         }
412     }
413     else if (name[0] == '@')
414     {
415       if (cupsdCheckGroup(username, pw, name + 1))
416       {
417 #ifdef DEBUG
418         cupsdLogMessage(CUPSD_LOG_DEBUG2,
419                         "cupsdGetPrivateAttrs: Returning NULL.");
420 #endif /* DEBUG */
421
422         return (NULL);
423       }
424     }
425     else if (!_cups_strcasecmp(username, name))
426     {
427 #ifdef DEBUG
428       cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL.");
429 #endif /* DEBUG */
430
431       return (NULL);
432     }
433   }
434
435  /*
436   * No direct access, so return private attributes list...
437   */
438
439 #ifdef DEBUG
440   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning list.");
441 #endif /* DEBUG */
442
443   return (attrs_ptr);
444 }
445
446
447 /*
448  * 'compare_ops()' - Compare two operations.
449  */
450
451 static int                              /* O - Result of comparison */
452 compare_ops(cupsd_location_t *a,        /* I - First operation */
453             cupsd_location_t *b)        /* I - Second operation */
454 {
455   return (a->op - b->op);
456 }
457
458
459 /*
460  * 'compare_policies()' - Compare two policies.
461  */
462
463 static int                              /* O - Result of comparison */
464 compare_policies(cupsd_policy_t *a,     /* I - First policy */
465                  cupsd_policy_t *b)     /* I - Second policy */
466 {
467   return (_cups_strcasecmp(a->name, b->name));
468 }
469
470
471 /*
472  * 'free_policy()' - Free the memory used by a policy.
473  */
474
475 static void
476 free_policy(cupsd_policy_t *p)          /* I - Policy to free */
477 {
478   cupsArrayDelete(p->job_access);
479   cupsArrayDelete(p->job_attrs);
480   cupsArrayDelete(p->sub_access);
481   cupsArrayDelete(p->sub_attrs);
482   cupsArrayDelete(p->ops);
483   cupsdClearString(&p->name);
484   free(p);
485 }
486
487
488 /*
489  * 'hash_op()' - Generate a lookup hash for the operation.
490  */
491
492 static int                              /* O - Hash value */
493 hash_op(cupsd_location_t *op)           /* I - Operation */
494 {
495   return (((op->op >> 6) & 0x40) | (op->op & 0x3f));
496 }