]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/policy.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / scheduler / policy.c
CommitLineData
ef416fc2 1/*
f627443d 2 * Policy routines for the CUPS scheduler.
ef416fc2 3 *
f627443d
MS
4 * Copyright 2007-2011, 2014 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
ef416fc2 6 *
e3101897 7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
ef416fc2 8 */
9
10/*
11 * Include necessary headers...
12 */
13
14#include "cupsd.h"
10d09e33 15#include <pwd.h>
ef416fc2 16
17
2e4ff8af
MS
18/*
19 * Local functions...
20 */
21
22static int compare_ops(cupsd_location_t *a, cupsd_location_t *b);
23static int compare_policies(cupsd_policy_t *a, cupsd_policy_t *b);
10d09e33 24static void free_policy(cupsd_policy_t *p);
2e4ff8af
MS
25static int hash_op(cupsd_location_t *op);
26
27
ef416fc2 28/*
f627443d 29 * 'cupsdAddPolicy()' - Add a policy to the system.
ef416fc2 30 */
31
32cupsd_policy_t * /* O - Policy */
33cupsdAddPolicy(const char *policy) /* I - Name of policy */
34{
2e4ff8af 35 cupsd_policy_t *temp; /* Pointer to policy */
ef416fc2 36
37
2e4ff8af 38 if (!policy)
ef416fc2 39 return (NULL);
40
2e4ff8af 41 if (!Policies)
10d09e33
MS
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);
ef416fc2 46
2e4ff8af 47 if (!Policies)
ef416fc2 48 return (NULL);
49
ef416fc2 50 if ((temp = calloc(1, sizeof(cupsd_policy_t))) != NULL)
51 {
2e4ff8af
MS
52 cupsdSetString(&temp->name, policy);
53 cupsArrayAdd(Policies, temp);
ef416fc2 54 }
55
56 return (temp);
57}
58
59
60/*
61 * 'cupsdAddPolicyOp()' - Add an operation to a policy.
62 */
63
64cupsd_location_t * /* O - New policy operation */
65cupsdAddPolicyOp(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{
2e4ff8af 69 cupsd_location_t *temp; /* New policy operation */
ef416fc2 70
71
72 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPolicyOp(p=%p, po=%p, op=%x(%s))",
73 p, po, op, ippOpString(op));
74
2e4ff8af 75 if (!p)
ef416fc2 76 return (NULL);
77
2e4ff8af 78 if (!p->ops)
10d09e33
MS
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);
ef416fc2 83
2e4ff8af 84 if (!p->ops)
ef416fc2 85 return (NULL);
86
10d09e33 87 if ((temp = cupsdCopyLocation(po)) != NULL)
ef416fc2 88 {
ef416fc2 89 temp->op = op;
5bd77a73 90 temp->limit = CUPSD_AUTH_LIMIT_IPP;
ef416fc2 91
2e4ff8af 92 cupsArrayAdd(p->ops, temp);
ef416fc2 93 }
94
95 return (temp);
96}
97
98
99/*
100 * 'cupsdCheckPolicy()' - Check the IPP operation and username against a policy.
101 */
102
103http_status_t /* I - 1 if OK, 0 otherwise */
104cupsdCheckPolicy(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 {
f627443d 117 cupsdLogMessage(CUPSD_LOG_CRIT, "cupsdCheckPolicy: p=%p, con=%p.", p, con);
ef416fc2 118
d09495fa 119 return ((http_status_t)0);
ef416fc2 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 {
f627443d 128 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckPolicy: No matching operation, returning 0.");
d09495fa 129 return ((http_status_t)0);
ef416fc2 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
146void
147cupsdDeleteAllPolicies(void)
148{
ba55dc12 149 cupsd_printer_t *printer; /* Current printer */
ef416fc2 150
151
2e4ff8af 152 if (!Policies)
ef416fc2 153 return;
154
ba55dc12
MS
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
10d09e33
MS
164 DefaultPolicyPtr = NULL;
165
ba55dc12
MS
166 /*
167 * Then free all of the policies...
168 */
169
2e4ff8af 170 cupsArrayDelete(Policies);
ef416fc2 171
2e4ff8af 172 Policies = NULL;
ef416fc2 173}
174
175
176/*
177 * 'cupsdFindPolicy()' - Find a named policy.
178 */
179
180cupsd_policy_t * /* O - Policy */
181cupsdFindPolicy(const char *policy) /* I - Name of policy */
182{
2e4ff8af 183 cupsd_policy_t key; /* Search key */
ef416fc2 184
185
186 /*
187 * Range check...
188 */
189
2e4ff8af 190 if (!policy)
ef416fc2 191 return (NULL);
192
193 /*
2e4ff8af 194 * Look it up...
ef416fc2 195 */
196
2e4ff8af
MS
197 key.name = (char *)policy;
198 return ((cupsd_policy_t *)cupsArrayFind(Policies, &key));
ef416fc2 199}
200
201
202/*
203 * 'cupsdFindPolicyOp()' - Find a policy operation.
204 */
205
206cupsd_location_t * /* O - Policy operation */
207cupsdFindPolicyOp(cupsd_policy_t *p, /* I - Policy */
208 ipp_op_t op) /* I - IPP operation */
209{
2e4ff8af
MS
210 cupsd_location_t key, /* Search key... */
211 *po; /* Current policy operation */
ef416fc2 212
213
75bd9771 214 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp(p=%p, op=%x(%s))",
ef416fc2 215 p, op, ippOpString(op));
216
217 /*
218 * Range check...
219 */
220
2e4ff8af 221 if (!p)
ef416fc2 222 return (NULL);
223
224 /*
225 * Check the operation against the available policies...
226 */
227
2e4ff8af
MS
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 }
ef416fc2 235
2e4ff8af
MS
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 }
ef416fc2 243
f627443d 244 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp: No match found.");
ef416fc2 245
246 return (NULL);
247}
248
249
10d09e33
MS
250/*
251 * 'cupsdGetPrivateAttrs()' - Get the private attributes for the current
252 * request.
253 */
254
255cups_array_t * /* O - Array or NULL for no restrictions */
256cupsdGetPrivateAttrs(
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,
996acce8 274 con->number, printer, printer ? printer->name : "", owner);
10d09e33
MS
275#endif /* DEBUG */
276
f627443d
MS
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
10d09e33
MS
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 &&
88f9aafc 312 !_cups_strcasecmp(name, "none"))
10d09e33
MS
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
88f9aafc 358 if (printer && !_cups_strcasecmp(name, "@ACL"))
10d09e33
MS
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 }
88f9aafc 384 else if (!_cups_strcasecmp(username, acl))
10d09e33
MS
385 break;
386 }
387 }
88f9aafc
MS
388 else if (owner && !_cups_strcasecmp(name, "@OWNER") &&
389 !_cups_strcasecmp(username, owner))
10d09e33
MS
390 {
391#ifdef DEBUG
392 cupsdLogMessage(CUPSD_LOG_DEBUG2,
393 "cupsdGetPrivateAttrs: Returning NULL.");
394#endif /* DEBUG */
395
396 return (NULL);
397 }
88f9aafc 398 else if (!_cups_strcasecmp(name, "@SYSTEM"))
10d09e33
MS
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 }
88f9aafc 425 else if (!_cups_strcasecmp(username, name))
10d09e33
MS
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
ef416fc2 447/*
2e4ff8af
MS
448 * 'compare_ops()' - Compare two operations.
449 */
450
451static int /* O - Result of comparison */
452compare_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
463static int /* O - Result of comparison */
464compare_policies(cupsd_policy_t *a, /* I - First policy */
465 cupsd_policy_t *b) /* I - Second policy */
466{
88f9aafc 467 return (_cups_strcasecmp(a->name, b->name));
2e4ff8af
MS
468}
469
470
10d09e33
MS
471/*
472 * 'free_policy()' - Free the memory used by a policy.
473 */
474
475static void
476free_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
2e4ff8af
MS
488/*
489 * 'hash_op()' - Generate a lookup hash for the operation.
490 */
491
492static int /* O - Hash value */
493hash_op(cupsd_location_t *op) /* I - Operation */
494{
495 return (((op->op >> 6) & 0x40) | (op->op & 0x3f));
496}