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