]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
1a18c85c | 2 | * "$Id: policy.c 11681 2014-03-05 19:07:24Z msweet $" |
ef416fc2 | 3 | * |
71f63681 | 4 | * Policy routines for the CUPS scheduler. |
ef416fc2 | 5 | * |
71f63681 MS |
6 | * Copyright 2007-2011, 2014 by Apple Inc. |
7 | * Copyright 1997-2006 by Easy Software Products, all rights reserved. | |
ef416fc2 | 8 | * |
71f63681 MS |
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/". | |
ef416fc2 | 14 | */ |
15 | ||
16 | /* | |
17 | * Include necessary headers... | |
18 | */ | |
19 | ||
20 | #include "cupsd.h" | |
10d09e33 | 21 | #include <pwd.h> |
ef416fc2 | 22 | |
23 | ||
2e4ff8af MS |
24 | /* |
25 | * Local functions... | |
26 | */ | |
27 | ||
28 | static int compare_ops(cupsd_location_t *a, cupsd_location_t *b); | |
29 | static int compare_policies(cupsd_policy_t *a, cupsd_policy_t *b); | |
10d09e33 | 30 | static void free_policy(cupsd_policy_t *p); |
2e4ff8af MS |
31 | static int hash_op(cupsd_location_t *op); |
32 | ||
33 | ||
ef416fc2 | 34 | /* |
71f63681 | 35 | * 'cupsdAddPolicy()' - Add a policy to the system. |
ef416fc2 | 36 | */ |
37 | ||
38 | cupsd_policy_t * /* O - Policy */ | |
39 | cupsdAddPolicy(const char *policy) /* I - Name of policy */ | |
40 | { | |
2e4ff8af | 41 | cupsd_policy_t *temp; /* Pointer to policy */ |
ef416fc2 | 42 | |
43 | ||
2e4ff8af | 44 | if (!policy) |
ef416fc2 | 45 | return (NULL); |
46 | ||
2e4ff8af | 47 | if (!Policies) |
10d09e33 MS |
48 | Policies = cupsArrayNew3((cups_array_func_t)compare_policies, NULL, |
49 | (cups_ahash_func_t)NULL, 0, | |
50 | (cups_acopy_func_t)NULL, | |
51 | (cups_afree_func_t)free_policy); | |
ef416fc2 | 52 | |
2e4ff8af | 53 | if (!Policies) |
ef416fc2 | 54 | return (NULL); |
55 | ||
ef416fc2 | 56 | if ((temp = calloc(1, sizeof(cupsd_policy_t))) != NULL) |
57 | { | |
2e4ff8af MS |
58 | cupsdSetString(&temp->name, policy); |
59 | cupsArrayAdd(Policies, temp); | |
ef416fc2 | 60 | } |
61 | ||
62 | return (temp); | |
63 | } | |
64 | ||
65 | ||
66 | /* | |
67 | * 'cupsdAddPolicyOp()' - Add an operation to a policy. | |
68 | */ | |
69 | ||
70 | cupsd_location_t * /* O - New policy operation */ | |
71 | cupsdAddPolicyOp(cupsd_policy_t *p, /* I - Policy */ | |
72 | cupsd_location_t *po, /* I - Policy operation to copy */ | |
73 | ipp_op_t op) /* I - IPP operation code */ | |
74 | { | |
2e4ff8af | 75 | cupsd_location_t *temp; /* New policy operation */ |
ef416fc2 | 76 | |
77 | ||
78 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPolicyOp(p=%p, po=%p, op=%x(%s))", | |
79 | p, po, op, ippOpString(op)); | |
80 | ||
2e4ff8af | 81 | if (!p) |
ef416fc2 | 82 | return (NULL); |
83 | ||
2e4ff8af | 84 | if (!p->ops) |
10d09e33 MS |
85 | p->ops = cupsArrayNew3((cups_array_func_t)compare_ops, NULL, |
86 | (cups_ahash_func_t)hash_op, 128, | |
87 | (cups_acopy_func_t)NULL, | |
88 | (cups_afree_func_t)cupsdFreeLocation); | |
ef416fc2 | 89 | |
2e4ff8af | 90 | if (!p->ops) |
ef416fc2 | 91 | return (NULL); |
92 | ||
10d09e33 | 93 | if ((temp = cupsdCopyLocation(po)) != NULL) |
ef416fc2 | 94 | { |
ef416fc2 | 95 | temp->op = op; |
5bd77a73 | 96 | temp->limit = CUPSD_AUTH_LIMIT_IPP; |
ef416fc2 | 97 | |
2e4ff8af | 98 | cupsArrayAdd(p->ops, temp); |
ef416fc2 | 99 | } |
100 | ||
101 | return (temp); | |
102 | } | |
103 | ||
104 | ||
105 | /* | |
106 | * 'cupsdCheckPolicy()' - Check the IPP operation and username against a policy. | |
107 | */ | |
108 | ||
109 | http_status_t /* I - 1 if OK, 0 otherwise */ | |
110 | cupsdCheckPolicy(cupsd_policy_t *p, /* I - Policy */ | |
111 | cupsd_client_t *con, /* I - Client connection */ | |
112 | const char *owner) /* I - Owner of object */ | |
113 | { | |
114 | cupsd_location_t *po; /* Current policy operation */ | |
115 | ||
116 | ||
117 | /* | |
118 | * Range check... | |
119 | */ | |
120 | ||
121 | if (!p || !con) | |
122 | { | |
71f63681 | 123 | cupsdLogMessage(CUPSD_LOG_CRIT, "cupsdCheckPolicy: p=%p, con=%p.", p, con); |
ef416fc2 | 124 | |
d09495fa | 125 | return ((http_status_t)0); |
ef416fc2 | 126 | } |
127 | ||
128 | /* | |
129 | * Find a match for the operation... | |
130 | */ | |
131 | ||
132 | if ((po = cupsdFindPolicyOp(p, con->request->request.op.operation_id)) == NULL) | |
133 | { | |
71f63681 | 134 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckPolicy: No matching operation, returning 0."); |
d09495fa | 135 | return ((http_status_t)0); |
ef416fc2 | 136 | } |
137 | ||
138 | con->best = po; | |
139 | ||
140 | /* | |
141 | * Return the status of the check... | |
142 | */ | |
143 | ||
144 | return (cupsdIsAuthorized(con, owner)); | |
145 | } | |
146 | ||
147 | ||
148 | /* | |
149 | * 'cupsdDeleteAllPolicies()' - Delete all policies in memory. | |
150 | */ | |
151 | ||
152 | void | |
153 | cupsdDeleteAllPolicies(void) | |
154 | { | |
ba55dc12 | 155 | cupsd_printer_t *printer; /* Current printer */ |
ef416fc2 | 156 | |
157 | ||
2e4ff8af | 158 | if (!Policies) |
ef416fc2 | 159 | return; |
160 | ||
ba55dc12 MS |
161 | /* |
162 | * First clear the policy pointers for all printers... | |
163 | */ | |
164 | ||
165 | for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers); | |
166 | printer; | |
167 | printer = (cupsd_printer_t *)cupsArrayNext(Printers)) | |
168 | printer->op_policy_ptr = NULL; | |
169 | ||
10d09e33 MS |
170 | DefaultPolicyPtr = NULL; |
171 | ||
ba55dc12 MS |
172 | /* |
173 | * Then free all of the policies... | |
174 | */ | |
175 | ||
2e4ff8af | 176 | cupsArrayDelete(Policies); |
ef416fc2 | 177 | |
2e4ff8af | 178 | Policies = NULL; |
ef416fc2 | 179 | } |
180 | ||
181 | ||
182 | /* | |
183 | * 'cupsdFindPolicy()' - Find a named policy. | |
184 | */ | |
185 | ||
186 | cupsd_policy_t * /* O - Policy */ | |
187 | cupsdFindPolicy(const char *policy) /* I - Name of policy */ | |
188 | { | |
2e4ff8af | 189 | cupsd_policy_t key; /* Search key */ |
ef416fc2 | 190 | |
191 | ||
192 | /* | |
193 | * Range check... | |
194 | */ | |
195 | ||
2e4ff8af | 196 | if (!policy) |
ef416fc2 | 197 | return (NULL); |
198 | ||
199 | /* | |
2e4ff8af | 200 | * Look it up... |
ef416fc2 | 201 | */ |
202 | ||
2e4ff8af MS |
203 | key.name = (char *)policy; |
204 | return ((cupsd_policy_t *)cupsArrayFind(Policies, &key)); | |
ef416fc2 | 205 | } |
206 | ||
207 | ||
208 | /* | |
209 | * 'cupsdFindPolicyOp()' - Find a policy operation. | |
210 | */ | |
211 | ||
212 | cupsd_location_t * /* O - Policy operation */ | |
213 | cupsdFindPolicyOp(cupsd_policy_t *p, /* I - Policy */ | |
214 | ipp_op_t op) /* I - IPP operation */ | |
215 | { | |
2e4ff8af MS |
216 | cupsd_location_t key, /* Search key... */ |
217 | *po; /* Current policy operation */ | |
ef416fc2 | 218 | |
219 | ||
75bd9771 | 220 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp(p=%p, op=%x(%s))", |
ef416fc2 | 221 | p, op, ippOpString(op)); |
222 | ||
223 | /* | |
224 | * Range check... | |
225 | */ | |
226 | ||
2e4ff8af | 227 | if (!p) |
ef416fc2 | 228 | return (NULL); |
229 | ||
230 | /* | |
231 | * Check the operation against the available policies... | |
232 | */ | |
233 | ||
2e4ff8af MS |
234 | key.op = op; |
235 | if ((po = (cupsd_location_t *)cupsArrayFind(p->ops, &key)) != NULL) | |
236 | { | |
237 | cupsdLogMessage(CUPSD_LOG_DEBUG2, | |
238 | "cupsdFindPolicyOp: Found exact match..."); | |
239 | return (po); | |
240 | } | |
ef416fc2 | 241 | |
2e4ff8af MS |
242 | key.op = IPP_ANY_OPERATION; |
243 | if ((po = (cupsd_location_t *)cupsArrayFind(p->ops, &key)) != NULL) | |
244 | { | |
245 | cupsdLogMessage(CUPSD_LOG_DEBUG2, | |
246 | "cupsdFindPolicyOp: Found wildcard match..."); | |
247 | return (po); | |
248 | } | |
ef416fc2 | 249 | |
71f63681 | 250 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp: No match found."); |
ef416fc2 | 251 | |
252 | return (NULL); | |
253 | } | |
254 | ||
255 | ||
10d09e33 MS |
256 | /* |
257 | * 'cupsdGetPrivateAttrs()' - Get the private attributes for the current | |
258 | * request. | |
259 | */ | |
260 | ||
261 | cups_array_t * /* O - Array or NULL for no restrictions */ | |
262 | cupsdGetPrivateAttrs( | |
263 | cupsd_policy_t *policy, /* I - Policy */ | |
264 | cupsd_client_t *con, /* I - Client connection */ | |
265 | cupsd_printer_t *printer, /* I - Printer, if any */ | |
266 | const char *owner) /* I - Owner of object */ | |
267 | { | |
268 | char *name; /* Current name in access list */ | |
269 | cups_array_t *access_ptr, /* Access array */ | |
270 | *attrs_ptr; /* Attributes array */ | |
271 | const char *username; /* Username associated with request */ | |
272 | ipp_attribute_t *attr; /* Attribute from request */ | |
273 | struct passwd *pw; /* User info */ | |
274 | ||
275 | ||
276 | #ifdef DEBUG | |
277 | cupsdLogMessage(CUPSD_LOG_DEBUG2, | |
278 | "cupsdGetPrivateAttrs(policy=%p(%s), con=%p(%d), " | |
279 | "printer=%p(%s), owner=\"%s\")", policy, policy->name, con, | |
1a18c85c | 280 | con->number, printer, printer ? printer->name : "", owner); |
10d09e33 MS |
281 | #endif /* DEBUG */ |
282 | ||
71f63681 MS |
283 | if (!policy) |
284 | { | |
285 | 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); | |
286 | policy = DefaultPolicyPtr; | |
287 | } | |
288 | ||
10d09e33 MS |
289 | /* |
290 | * Get the access and attributes lists that correspond to the request... | |
291 | */ | |
292 | ||
293 | #ifdef DEBUG | |
294 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: %s", | |
295 | ippOpString(con->request->request.op.operation_id)); | |
296 | #endif /* DEBUG */ | |
297 | ||
298 | switch (con->request->request.op.operation_id) | |
299 | { | |
300 | case IPP_GET_SUBSCRIPTIONS : | |
301 | case IPP_GET_SUBSCRIPTION_ATTRIBUTES : | |
302 | case IPP_GET_NOTIFICATIONS : | |
303 | access_ptr = policy->sub_access; | |
304 | attrs_ptr = policy->sub_attrs; | |
305 | break; | |
306 | ||
307 | default : | |
308 | access_ptr = policy->job_access; | |
309 | attrs_ptr = policy->job_attrs; | |
310 | break; | |
311 | } | |
312 | ||
313 | /* | |
314 | * If none of the attributes are private, return NULL now... | |
315 | */ | |
316 | ||
317 | if ((name = (char *)cupsArrayFirst(attrs_ptr)) != NULL && | |
88f9aafc | 318 | !_cups_strcasecmp(name, "none")) |
10d09e33 MS |
319 | { |
320 | #ifdef DEBUG | |
321 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL."); | |
322 | #endif /* DEBUG */ | |
323 | ||
324 | return (NULL); | |
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 | ||
88f9aafc | 364 | if (printer && !_cups_strcasecmp(name, "@ACL")) |
10d09e33 MS |
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 | } | |
88f9aafc | 390 | else if (!_cups_strcasecmp(username, acl)) |
10d09e33 MS |
391 | break; |
392 | } | |
393 | } | |
88f9aafc MS |
394 | else if (owner && !_cups_strcasecmp(name, "@OWNER") && |
395 | !_cups_strcasecmp(username, owner)) | |
10d09e33 MS |
396 | { |
397 | #ifdef DEBUG | |
398 | cupsdLogMessage(CUPSD_LOG_DEBUG2, | |
399 | "cupsdGetPrivateAttrs: Returning NULL."); | |
400 | #endif /* DEBUG */ | |
401 | ||
402 | return (NULL); | |
403 | } | |
88f9aafc | 404 | else if (!_cups_strcasecmp(name, "@SYSTEM")) |
10d09e33 MS |
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 | } | |
88f9aafc | 431 | else if (!_cups_strcasecmp(username, name)) |
10d09e33 MS |
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 | ||
ef416fc2 | 453 | /* |
2e4ff8af MS |
454 | * 'compare_ops()' - Compare two operations. |
455 | */ | |
456 | ||
457 | static int /* O - Result of comparison */ | |
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 */ | |
470 | compare_policies(cupsd_policy_t *a, /* I - First policy */ | |
471 | cupsd_policy_t *b) /* I - Second policy */ | |
472 | { | |
88f9aafc | 473 | return (_cups_strcasecmp(a->name, b->name)); |
2e4ff8af MS |
474 | } |
475 | ||
476 | ||
10d09e33 MS |
477 | /* |
478 | * 'free_policy()' - Free the memory used by a policy. | |
479 | */ | |
480 | ||
481 | static void | |
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 | ||
2e4ff8af MS |
494 | /* |
495 | * 'hash_op()' - Generate a lookup hash for the operation. | |
496 | */ | |
497 | ||
498 | static int /* O - Hash value */ | |
499 | hash_op(cupsd_location_t *op) /* I - Operation */ | |
500 | { | |
501 | return (((op->op >> 6) & 0x40) | (op->op & 0x3f)); | |
502 | } | |
503 | ||
504 | ||
505 | /* | |
1a18c85c | 506 | * End of "$Id: policy.c 11681 2014-03-05 19:07:24Z msweet $". |
ef416fc2 | 507 | */ |