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 */
cupsdAddPolicy(const char * 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 */
cupsdAddPolicyOp(cupsd_policy_t * p,cupsd_location_t * po,ipp_op_t op)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 */
cupsdCheckPolicy(cupsd_policy_t * p,cupsd_client_t * con,const char * owner)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
cupsdDeleteAllPolicies(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 */
cupsdFindPolicy(const char * 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 */
cupsdFindPolicyOp(cupsd_policy_t * p,ipp_op_t op)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 */
cupsdGetPrivateAttrs(cupsd_policy_t * policy,cupsd_client_t * con,cupsd_printer_t * printer,const char * owner)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 */
compare_ops(cupsd_location_t * a,cupsd_location_t * b)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 */
compare_policies(cupsd_policy_t * a,cupsd_policy_t * b)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
free_policy(cupsd_policy_t * p)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 */
hash_op(cupsd_location_t * op)493 hash_op(cupsd_location_t *op) /* I - Operation */
494 {
495 return (((op->op >> 6) & 0x40) | (op->op & 0x3f));
496 }
497