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