]>
Commit | Line | Data |
---|---|---|
f27bd5ab | 1 | /* |
5934328c | 2 | * "$Id: policy.c,v 1.1.2.8 2004/06/30 21:18:31 mike Exp $" |
f27bd5ab | 3 | * |
4 | * Policy routines for the Common UNIX Printing System (CUPS). | |
5 | * | |
9639c4de | 6 | * Copyright 1997-2004 by Easy Software Products, all rights reserved. |
f27bd5ab | 7 | * |
8 | * These coded instructions, statements, and computer programs are the | |
9 | * property of Easy Software Products and are protected by Federal | |
10 | * copyright law. Distribution and use rights are outlined in the file | |
11 | * "LICENSE.txt" which should have been included with this file. If this | |
12 | * file is missing or damaged please contact Easy Software Products | |
13 | * at: | |
14 | * | |
15 | * Attn: CUPS Licensing Information | |
16 | * Easy Software Products | |
17 | * 44141 Airport View Drive, Suite 204 | |
9639c4de | 18 | * Hollywood, Maryland 20636-3142 USA |
f27bd5ab | 19 | * |
9639c4de | 20 | * Voice: (301) 373-9600 |
f27bd5ab | 21 | * EMail: cups-info@cups.org |
22 | * WWW: http://www.cups.org | |
23 | * | |
24 | * Contents: | |
25 | * | |
26 | */ | |
27 | ||
28 | /* | |
29 | * Include necessary headers... | |
30 | */ | |
31 | ||
32 | #include "cupsd.h" | |
33 | #include <pwd.h> | |
34 | #include <grp.h> | |
35 | #ifdef HAVE_USERSEC_H | |
36 | # include <usersec.h> | |
37 | #endif /* HAVE_USERSEC_H */ | |
38 | ||
39 | ||
40 | /* | |
41 | * Local functions... | |
42 | */ | |
43 | ||
4b6bdd9f | 44 | static int check_group(const char *name, const char *group); |
45 | static int check_op(policyop_t *po, int allow_deny, const char *name, | |
46 | const char *owner); | |
53ca8055 | 47 | |
f27bd5ab | 48 | |
49 | /* | |
50 | * 'AddPolicy()' - Add a policy to the system. | |
51 | */ | |
52 | ||
53 | policy_t * /* O - Policy */ | |
54 | AddPolicy(const char *policy) /* I - Name of policy */ | |
55 | { | |
4b6bdd9f | 56 | policy_t *temp, /* Pointer to policy */ |
57 | **tempa; /* Pointer to policy array */ | |
53ca8055 | 58 | |
59 | ||
60 | if (policy == NULL) | |
61 | return (NULL); | |
62 | ||
63 | if (NumPolicies == 0) | |
4b6bdd9f | 64 | tempa = malloc(sizeof(policy_t *)); |
53ca8055 | 65 | else |
4b6bdd9f | 66 | tempa = realloc(Policies, sizeof(policy_t *) * (NumPolicies + 1)); |
53ca8055 | 67 | |
4b6bdd9f | 68 | if (tempa == NULL) |
69 | return (NULL); | |
70 | ||
71 | Policies = tempa; | |
72 | tempa += NumPolicies; | |
73 | ||
74 | if ((temp = calloc(1, sizeof(policy_t))) != NULL) | |
53ca8055 | 75 | { |
4b6bdd9f | 76 | temp->name = strdup(policy); |
77 | *tempa = temp; | |
53ca8055 | 78 | |
4b6bdd9f | 79 | NumPolicies ++; |
53ca8055 | 80 | } |
81 | ||
82 | return (temp); | |
f27bd5ab | 83 | } |
84 | ||
85 | ||
86 | /* | |
87 | * 'AddPolicyOp()' - Add an operation to a policy. | |
88 | */ | |
89 | ||
90 | policyop_t * /* O - New policy operation */ | |
4b6bdd9f | 91 | AddPolicyOp(policy_t *p, /* I - Policy */ |
92 | policyop_t *po, /* I - Policy operation to copy */ | |
93 | ipp_op_t op) /* I - IPP operation code */ | |
f27bd5ab | 94 | { |
4b6bdd9f | 95 | int i; /* Looping var */ |
96 | policyop_t *temp, /* New policy operation */ | |
97 | **tempa; /* New policy operation array */ | |
53ca8055 | 98 | |
99 | ||
100 | if (p == NULL) | |
101 | return (NULL); | |
102 | ||
103 | if (p->num_ops == 0) | |
4b6bdd9f | 104 | tempa = malloc(sizeof(policyop_t *)); |
53ca8055 | 105 | else |
4b6bdd9f | 106 | tempa = realloc(p->ops, sizeof(policyop_t *) * (p->num_ops + 1)); |
53ca8055 | 107 | |
4b6bdd9f | 108 | if (tempa == NULL) |
109 | return (NULL); | |
110 | ||
111 | p->ops = tempa; | |
112 | ||
113 | if ((temp = calloc(1, sizeof(policyop_t))) != NULL) | |
53ca8055 | 114 | { |
4b6bdd9f | 115 | p->ops = tempa; |
116 | tempa[p->num_ops] = temp; | |
53ca8055 | 117 | p->num_ops ++; |
118 | ||
53ca8055 | 119 | temp->op = op; |
4b6bdd9f | 120 | |
121 | if (po) | |
122 | { | |
123 | /* | |
124 | * Copy the specified policy to the new one... | |
125 | */ | |
126 | ||
127 | temp->order_type = po->order_type; | |
128 | temp->authenticate = po->authenticate; | |
129 | for (i = 0; i < po->num_names; i ++) | |
130 | AddPolicyOpName(temp, po->names[i].allow_deny, po->names[i].name); | |
131 | } | |
53ca8055 | 132 | } |
133 | ||
134 | return (temp); | |
f27bd5ab | 135 | } |
136 | ||
137 | ||
138 | /* | |
139 | * 'AddPolicyOpName()' - Add a name to a policy operation. | |
140 | */ | |
141 | ||
142 | void | |
143 | AddPolicyOpName(policyop_t *po, /* I - Policy operation */ | |
4b6bdd9f | 144 | int allow_deny, /* I - POLICY_ALLOW or POLICY_DENY */ |
f27bd5ab | 145 | const char *name) /* I - Name to add */ |
146 | { | |
4b6bdd9f | 147 | policyname_t *temp; /* New name array */ |
53ca8055 | 148 | |
149 | ||
150 | if (po == NULL || name == NULL) | |
151 | return; | |
152 | ||
153 | if (po->num_names == 0) | |
4b6bdd9f | 154 | temp = malloc(sizeof(policyname_t)); |
53ca8055 | 155 | else |
4b6bdd9f | 156 | temp = realloc(po->names, sizeof(policyname_t) * (po->num_names + 1)); |
53ca8055 | 157 | |
158 | if (temp != NULL) | |
159 | { | |
160 | po->names = temp; | |
161 | temp += po->num_names; | |
162 | po->num_names ++; | |
163 | ||
4b6bdd9f | 164 | temp->allow_deny = allow_deny; |
165 | temp->name = strdup(name); | |
53ca8055 | 166 | } |
f27bd5ab | 167 | } |
168 | ||
169 | ||
170 | /* | |
171 | * 'CheckPolicy()' - Check the IPP operation and username against a policy. | |
172 | */ | |
173 | ||
174 | int /* I - 1 if OK, 0 otherwise */ | |
175 | CheckPolicy(policy_t *p, /* I - Policy */ | |
bd5510a5 | 176 | client_t *con, /* I - Client connection */ |
53ca8055 | 177 | const char *owner) /* I - Owner of object */ |
f27bd5ab | 178 | { |
bd5510a5 | 179 | ipp_op_t op; /* IPP operation */ |
180 | const char *name; /* Username */ | |
181 | int authenticated; /* Authenticated? */ | |
182 | ipp_attribute_t *attr; /* IPP attribute */ | |
4b6bdd9f | 183 | int status; /* Status */ |
53ca8055 | 184 | policyop_t *po; /* Current policy operation */ |
53ca8055 | 185 | |
186 | ||
187 | /* | |
188 | * Range check... | |
189 | */ | |
190 | ||
bd5510a5 | 191 | if (!p || !con) |
53ca8055 | 192 | return (0); |
193 | ||
bd5510a5 | 194 | /* |
195 | * Collect info from the request... | |
196 | */ | |
197 | ||
198 | op = con->request->request.op.operation_id; | |
199 | ||
200 | if (con->username[0]) | |
201 | { | |
202 | name = con->username; | |
203 | authenticated = 1; | |
204 | } | |
205 | else if ((attr = ippFindAttribute(con->request, "requesting-user-name", | |
206 | IPP_TAG_NAME)) != NULL) | |
207 | { | |
208 | name = attr->values[0].string.text; | |
209 | authenticated = 0; | |
210 | } | |
211 | else | |
212 | { | |
213 | name = "anonymous"; | |
214 | authenticated = 0; | |
215 | } | |
216 | ||
5934328c | 217 | LogMessage(L_DEBUG2, "CheckPolicy: op=%04x, name=\"%s\", authenticated=%d, owner=\"%s\"", |
218 | op, name, authenticated, owner ? owner : ""); | |
219 | ||
53ca8055 | 220 | /* |
4b6bdd9f | 221 | * Find a match for the operation... |
53ca8055 | 222 | */ |
223 | ||
4b6bdd9f | 224 | if ((po = FindPolicyOp(p, op)) == NULL) |
5934328c | 225 | { |
226 | LogMessage(L_DEBUG2, "CheckPolicy: No matching operation, returning 0!"); | |
4b6bdd9f | 227 | return (0); |
5934328c | 228 | } |
4b6bdd9f | 229 | |
230 | /* | |
231 | * Check the policy against the current user, etc. | |
232 | */ | |
233 | ||
234 | if (po->authenticate && !authenticated) | |
5934328c | 235 | { |
236 | LogMessage(L_DEBUG2, "CheckPolicy: Operation requires authentication, returning 0!"); | |
4b6bdd9f | 237 | return (0); |
5934328c | 238 | } |
4b6bdd9f | 239 | |
240 | switch (status = po->order_type) | |
241 | { | |
242 | default : | |
243 | case POLICY_ALLOW : | |
244 | if (check_op(po, POLICY_DENY, name, owner)) | |
245 | status = POLICY_DENY; | |
246 | if (check_op(po, POLICY_ALLOW, name, owner)) | |
247 | status = POLICY_ALLOW; | |
248 | break; | |
249 | ||
250 | case POLICY_DENY : | |
251 | if (check_op(po, POLICY_ALLOW, name, owner)) | |
252 | status = POLICY_ALLOW; | |
253 | if (check_op(po, POLICY_DENY, name, owner)) | |
254 | status = POLICY_DENY; | |
255 | break; | |
256 | } | |
53ca8055 | 257 | |
258 | /* | |
4b6bdd9f | 259 | * Return the status of the check... |
53ca8055 | 260 | */ |
261 | ||
5934328c | 262 | LogMessage(L_DEBUG2, "CheckPolicy: Returning %d...", !status); |
263 | ||
4b6bdd9f | 264 | return (!status); |
f27bd5ab | 265 | } |
266 | ||
267 | ||
268 | /* | |
269 | * 'DeleteAllPolicies()' - Delete all policies in memory. | |
270 | */ | |
271 | ||
272 | void | |
273 | DeleteAllPolicies(void) | |
274 | { | |
4b6bdd9f | 275 | int i, j, k; /* Looping vars */ |
276 | policy_t **p; /* Current policy */ | |
277 | policyop_t **po; /* Current policy operation */ | |
278 | policyname_t *pn; /* Current policy name */ | |
53ca8055 | 279 | |
280 | ||
281 | if (NumPolicies == 0) | |
282 | return; | |
283 | ||
284 | for (i = NumPolicies, p = Policies; i > 0; i --, p ++) | |
285 | { | |
4b6bdd9f | 286 | for (j = (*p)->num_ops, po = (*p)->ops; j > 0; j --, po ++) |
53ca8055 | 287 | { |
4b6bdd9f | 288 | for (k = (*po)->num_names, pn = (*po)->names; k > 0; k --, pn ++) |
289 | free(pn->name); | |
290 | ||
291 | if ((*po)->num_names > 0) | |
292 | free((*po)->names); | |
53ca8055 | 293 | |
4b6bdd9f | 294 | free(*po); |
53ca8055 | 295 | } |
296 | ||
4b6bdd9f | 297 | if ((*p)->num_ops > 0) |
298 | free((*p)->ops); | |
299 | ||
300 | free(*p); | |
53ca8055 | 301 | } |
302 | ||
303 | free(Policies); | |
304 | ||
305 | NumPolicies = 0; | |
306 | Policies = NULL; | |
f27bd5ab | 307 | } |
308 | ||
309 | ||
310 | /* | |
311 | * 'FindPolicy()' - Find a named policy. | |
312 | */ | |
313 | ||
314 | policy_t * /* O - Policy */ | |
315 | FindPolicy(const char *policy) /* I - Name of policy */ | |
316 | { | |
53ca8055 | 317 | int i; /* Looping var */ |
4b6bdd9f | 318 | policy_t **p; /* Current policy */ |
53ca8055 | 319 | |
320 | ||
321 | /* | |
322 | * Range check... | |
323 | */ | |
324 | ||
325 | if (policy == NULL) | |
326 | return (NULL); | |
327 | ||
328 | /* | |
329 | * Check the operation against the available policies... | |
330 | */ | |
331 | ||
332 | for (i = NumPolicies, p = Policies; i > 0; i --, p ++) | |
4b6bdd9f | 333 | if (strcasecmp(policy, (*p)->name) == 0) |
334 | return (*p); | |
53ca8055 | 335 | |
336 | return (NULL); | |
f27bd5ab | 337 | } |
338 | ||
339 | ||
340 | /* | |
341 | * 'FindPolicyOp()' - Find a policy operation. | |
342 | */ | |
343 | ||
344 | policyop_t * /* O - Policy operation */ | |
345 | FindPolicyOp(policy_t *p, /* I - Policy */ | |
346 | ipp_op_t op) /* I - IPP operation */ | |
347 | { | |
53ca8055 | 348 | int i; /* Looping var */ |
4b6bdd9f | 349 | policyop_t **po; /* Current policy operation */ |
53ca8055 | 350 | |
351 | ||
352 | /* | |
353 | * Range check... | |
354 | */ | |
355 | ||
356 | if (p == NULL) | |
357 | return (NULL); | |
358 | ||
359 | /* | |
360 | * Check the operation against the available policies... | |
361 | */ | |
362 | ||
363 | for (i = p->num_ops, po = p->ops; i > 0; i --, po ++) | |
4b6bdd9f | 364 | if ((*po)->op == op) |
365 | return (*po); | |
366 | ||
367 | for (i = p->num_ops, po = p->ops; i > 0; i --, po ++) | |
368 | if ((*po)->op == IPP_ANY_OPERATION) | |
369 | return (*po); | |
53ca8055 | 370 | |
371 | return (NULL); | |
372 | } | |
373 | ||
374 | ||
375 | /* | |
376 | * 'validate_user()' - Validate the user for the request. | |
377 | */ | |
378 | ||
379 | static int /* O - 1 if permitted, 0 otherwise */ | |
380 | check_group(const char *username, /* I - Authenticated username */ | |
381 | const char *groupname) /* I - Group name */ | |
382 | { | |
383 | int i; /* Looping var */ | |
384 | struct passwd *user; /* User info */ | |
385 | struct group *group; /* System group info */ | |
69d2b731 | 386 | char junk[33]; /* MD5 password (not used) */ |
53ca8055 | 387 | |
388 | ||
389 | LogMessage(L_DEBUG2, "check_group(%s, %s)\n", username, groupname); | |
390 | ||
391 | /* | |
392 | * Validate input... | |
393 | */ | |
394 | ||
395 | if (username == NULL || groupname == NULL) | |
396 | return (0); | |
397 | ||
398 | /* | |
399 | * Check to see if the user is a member of the named group... | |
400 | */ | |
401 | ||
402 | user = getpwnam(username); | |
403 | endpwent(); | |
404 | ||
405 | group = getgrnam(groupname); | |
406 | endgrent(); | |
407 | ||
408 | if (group != NULL) | |
409 | { | |
410 | /* | |
411 | * Group exists, check it... | |
412 | */ | |
413 | ||
414 | for (i = 0; group->gr_mem[i]; i ++) | |
4b6bdd9f | 415 | if (strcasecmp(username, group->gr_mem[i]) == 0) |
53ca8055 | 416 | return (1); |
417 | } | |
418 | ||
419 | /* | |
420 | * Group doesn't exist or user not in group list, check the group ID | |
421 | * against the user's group ID... | |
422 | */ | |
423 | ||
424 | if (user != NULL && group != NULL && group->gr_gid == user->pw_gid) | |
425 | return (1); | |
426 | ||
427 | /* | |
69d2b731 | 428 | * Username not found, group not found, or user is not part of the |
429 | * system group... Check for a user and group in the MD5 password | |
430 | * file... | |
53ca8055 | 431 | */ |
432 | ||
69d2b731 | 433 | if (GetMD5Passwd(username, groupname, junk) != NULL) |
434 | return (1); | |
435 | ||
53ca8055 | 436 | /* |
437 | * If we get this far, then the user isn't part of the named group... | |
438 | */ | |
439 | ||
440 | return (0); | |
bd5510a5 | 441 | |
442 | ||
443 | #if 0 //// OLD OLD OLD OLD OLD | |
444 | if (strcasecmp(username, owner) != 0 && strcasecmp(username, "root") != 0) | |
445 | { | |
446 | /* | |
447 | * Not the owner or root; check to see if the user is a member of the | |
448 | * system group... | |
449 | */ | |
450 | ||
451 | user = getpwnam(username); | |
452 | endpwent(); | |
453 | ||
454 | for (i = 0, j = 0, group = NULL; i < NumSystemGroups; i ++) | |
455 | { | |
456 | group = getgrnam(SystemGroups[i]); | |
457 | endgrent(); | |
458 | ||
459 | if (group != NULL) | |
460 | { | |
461 | for (j = 0; group->gr_mem[j]; j ++) | |
462 | if (strcasecmp(username, group->gr_mem[j]) == 0) | |
463 | break; | |
464 | ||
465 | if (group->gr_mem[j]) | |
466 | break; | |
467 | } | |
468 | else | |
469 | j = 0; | |
470 | } | |
471 | ||
472 | if (user == NULL || group == NULL || | |
473 | (group->gr_mem[j] == NULL && group->gr_gid != user->pw_gid)) | |
474 | { | |
475 | /* | |
476 | * Username not found, group not found, or user is not part of the | |
477 | * system group... Check for a user and group in the MD5 password | |
478 | * file... | |
479 | */ | |
480 | ||
481 | for (i = 0; i < NumSystemGroups; i ++) | |
482 | if (GetMD5Passwd(username, SystemGroups[i], junk) != NULL) | |
483 | return (1); | |
484 | ||
485 | /* | |
486 | * Nope, not an MD5 user, either. Return 0 indicating no-go... | |
487 | */ | |
488 | ||
489 | return (0); | |
490 | } | |
491 | } | |
492 | ||
493 | return (1); | |
494 | #endif //// 0 | |
f27bd5ab | 495 | } |
496 | ||
497 | ||
498 | /* | |
4b6bdd9f | 499 | * 'check_op()' - Check the current operation. |
500 | */ | |
501 | ||
502 | static int /* O - 1 if match, 0 if not */ | |
503 | check_op(policyop_t *po, /* I - Policy operation */ | |
504 | int allow_deny, /* I - POLICY_ALLOW or POLICY_DENY */ | |
505 | const char *name, /* I - User name */ | |
506 | const char *owner) /* I - Owner name */ | |
507 | { | |
508 | int i; /* Looping vars */ | |
509 | policyname_t *pn; /* Current policy name */ | |
510 | ||
511 | ||
512 | for (i = po->num_names, pn = po->names; i > 0; i --, pn ++) | |
513 | { | |
514 | if (pn->allow_deny != allow_deny) | |
515 | continue; | |
516 | ||
517 | if (!strcasecmp(pn->name, "@OWNER")) | |
518 | { | |
519 | if (owner && !strcasecmp(name, owner)) | |
520 | return (1); | |
521 | } | |
522 | else if (pn->name[0] == '@') | |
523 | { | |
524 | if (check_group(name, pn->name + 1)) | |
525 | return (1); | |
526 | } | |
527 | else if (!strcasecmp(name, pn->name)) | |
528 | return (1); | |
529 | } | |
530 | ||
531 | return (0); | |
532 | } | |
533 | ||
534 | ||
535 | /* | |
5934328c | 536 | * End of "$Id: policy.c,v 1.1.2.8 2004/06/30 21:18:31 mike Exp $". |
f27bd5ab | 537 | */ |