]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/policy.c
Sync changes and files from 1.1.x.
[thirdparty/cups.git] / scheduler / policy.c
CommitLineData
f27bd5ab 1/*
fd09381d 2 * "$Id: policy.c,v 1.1.2.9 2004/07/02 22:15:51 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 44static int check_group(const char *name, const char *group);
45static 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
53policy_t * /* O - Policy */
54AddPolicy(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
90policyop_t * /* O - New policy operation */
4b6bdd9f 91AddPolicyOp(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
142void
143AddPolicyOpName(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
174int /* I - 1 if OK, 0 otherwise */
175CheckPolicy(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)
fd09381d 192 {
193 LogMessage(L_CRIT, "CheckPolicy: p=%p, con=%p!", p, con);
194
53ca8055 195 return (0);
fd09381d 196 }
53ca8055 197
bd5510a5 198 /*
199 * Collect info from the request...
200 */
201
202 op = con->request->request.op.operation_id;
203
204 if (con->username[0])
205 {
206 name = con->username;
207 authenticated = 1;
208 }
209 else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
210 IPP_TAG_NAME)) != NULL)
211 {
212 name = attr->values[0].string.text;
213 authenticated = 0;
214 }
215 else
216 {
217 name = "anonymous";
218 authenticated = 0;
219 }
220
5934328c 221 LogMessage(L_DEBUG2, "CheckPolicy: op=%04x, name=\"%s\", authenticated=%d, owner=\"%s\"",
222 op, name, authenticated, owner ? owner : "");
223
53ca8055 224 /*
4b6bdd9f 225 * Find a match for the operation...
53ca8055 226 */
227
4b6bdd9f 228 if ((po = FindPolicyOp(p, op)) == NULL)
5934328c 229 {
230 LogMessage(L_DEBUG2, "CheckPolicy: No matching operation, returning 0!");
4b6bdd9f 231 return (0);
5934328c 232 }
4b6bdd9f 233
234 /*
235 * Check the policy against the current user, etc.
236 */
237
238 if (po->authenticate && !authenticated)
5934328c 239 {
240 LogMessage(L_DEBUG2, "CheckPolicy: Operation requires authentication, returning 0!");
4b6bdd9f 241 return (0);
5934328c 242 }
4b6bdd9f 243
244 switch (status = po->order_type)
245 {
246 default :
247 case POLICY_ALLOW :
248 if (check_op(po, POLICY_DENY, name, owner))
249 status = POLICY_DENY;
250 if (check_op(po, POLICY_ALLOW, name, owner))
251 status = POLICY_ALLOW;
252 break;
253
254 case POLICY_DENY :
255 if (check_op(po, POLICY_ALLOW, name, owner))
256 status = POLICY_ALLOW;
257 if (check_op(po, POLICY_DENY, name, owner))
258 status = POLICY_DENY;
259 break;
260 }
53ca8055 261
262 /*
4b6bdd9f 263 * Return the status of the check...
53ca8055 264 */
265
5934328c 266 LogMessage(L_DEBUG2, "CheckPolicy: Returning %d...", !status);
267
4b6bdd9f 268 return (!status);
f27bd5ab 269}
270
271
272/*
273 * 'DeleteAllPolicies()' - Delete all policies in memory.
274 */
275
276void
277DeleteAllPolicies(void)
278{
4b6bdd9f 279 int i, j, k; /* Looping vars */
280 policy_t **p; /* Current policy */
281 policyop_t **po; /* Current policy operation */
282 policyname_t *pn; /* Current policy name */
53ca8055 283
284
285 if (NumPolicies == 0)
286 return;
287
288 for (i = NumPolicies, p = Policies; i > 0; i --, p ++)
289 {
4b6bdd9f 290 for (j = (*p)->num_ops, po = (*p)->ops; j > 0; j --, po ++)
53ca8055 291 {
4b6bdd9f 292 for (k = (*po)->num_names, pn = (*po)->names; k > 0; k --, pn ++)
293 free(pn->name);
294
295 if ((*po)->num_names > 0)
296 free((*po)->names);
53ca8055 297
4b6bdd9f 298 free(*po);
53ca8055 299 }
300
4b6bdd9f 301 if ((*p)->num_ops > 0)
302 free((*p)->ops);
303
304 free(*p);
53ca8055 305 }
306
307 free(Policies);
308
309 NumPolicies = 0;
310 Policies = NULL;
f27bd5ab 311}
312
313
314/*
315 * 'FindPolicy()' - Find a named policy.
316 */
317
318policy_t * /* O - Policy */
319FindPolicy(const char *policy) /* I - Name of policy */
320{
53ca8055 321 int i; /* Looping var */
4b6bdd9f 322 policy_t **p; /* Current policy */
53ca8055 323
324
325 /*
326 * Range check...
327 */
328
329 if (policy == NULL)
330 return (NULL);
331
332 /*
333 * Check the operation against the available policies...
334 */
335
336 for (i = NumPolicies, p = Policies; i > 0; i --, p ++)
4b6bdd9f 337 if (strcasecmp(policy, (*p)->name) == 0)
338 return (*p);
53ca8055 339
340 return (NULL);
f27bd5ab 341}
342
343
344/*
345 * 'FindPolicyOp()' - Find a policy operation.
346 */
347
348policyop_t * /* O - Policy operation */
349FindPolicyOp(policy_t *p, /* I - Policy */
350 ipp_op_t op) /* I - IPP operation */
351{
53ca8055 352 int i; /* Looping var */
4b6bdd9f 353 policyop_t **po; /* Current policy operation */
53ca8055 354
355
356 /*
357 * Range check...
358 */
359
360 if (p == NULL)
361 return (NULL);
362
363 /*
364 * Check the operation against the available policies...
365 */
366
367 for (i = p->num_ops, po = p->ops; i > 0; i --, po ++)
4b6bdd9f 368 if ((*po)->op == op)
369 return (*po);
370
371 for (i = p->num_ops, po = p->ops; i > 0; i --, po ++)
372 if ((*po)->op == IPP_ANY_OPERATION)
373 return (*po);
53ca8055 374
375 return (NULL);
376}
377
378
379/*
380 * 'validate_user()' - Validate the user for the request.
381 */
382
383static int /* O - 1 if permitted, 0 otherwise */
384check_group(const char *username, /* I - Authenticated username */
385 const char *groupname) /* I - Group name */
386{
387 int i; /* Looping var */
388 struct passwd *user; /* User info */
389 struct group *group; /* System group info */
69d2b731 390 char junk[33]; /* MD5 password (not used) */
53ca8055 391
392
393 LogMessage(L_DEBUG2, "check_group(%s, %s)\n", username, groupname);
394
395 /*
396 * Validate input...
397 */
398
399 if (username == NULL || groupname == NULL)
400 return (0);
401
402 /*
403 * Check to see if the user is a member of the named group...
404 */
405
406 user = getpwnam(username);
407 endpwent();
408
409 group = getgrnam(groupname);
410 endgrent();
411
412 if (group != NULL)
413 {
414 /*
415 * Group exists, check it...
416 */
417
418 for (i = 0; group->gr_mem[i]; i ++)
4b6bdd9f 419 if (strcasecmp(username, group->gr_mem[i]) == 0)
53ca8055 420 return (1);
421 }
422
423 /*
424 * Group doesn't exist or user not in group list, check the group ID
425 * against the user's group ID...
426 */
427
428 if (user != NULL && group != NULL && group->gr_gid == user->pw_gid)
429 return (1);
430
431 /*
69d2b731 432 * Username not found, group not found, or user is not part of the
433 * system group... Check for a user and group in the MD5 password
434 * file...
53ca8055 435 */
436
69d2b731 437 if (GetMD5Passwd(username, groupname, junk) != NULL)
438 return (1);
439
53ca8055 440 /*
441 * If we get this far, then the user isn't part of the named group...
442 */
443
444 return (0);
bd5510a5 445
446
447#if 0 //// OLD OLD OLD OLD OLD
448 if (strcasecmp(username, owner) != 0 && strcasecmp(username, "root") != 0)
449 {
450 /*
451 * Not the owner or root; check to see if the user is a member of the
452 * system group...
453 */
454
455 user = getpwnam(username);
456 endpwent();
457
458 for (i = 0, j = 0, group = NULL; i < NumSystemGroups; i ++)
459 {
460 group = getgrnam(SystemGroups[i]);
461 endgrent();
462
463 if (group != NULL)
464 {
465 for (j = 0; group->gr_mem[j]; j ++)
466 if (strcasecmp(username, group->gr_mem[j]) == 0)
467 break;
468
469 if (group->gr_mem[j])
470 break;
471 }
472 else
473 j = 0;
474 }
475
476 if (user == NULL || group == NULL ||
477 (group->gr_mem[j] == NULL && group->gr_gid != user->pw_gid))
478 {
479 /*
480 * Username not found, group not found, or user is not part of the
481 * system group... Check for a user and group in the MD5 password
482 * file...
483 */
484
485 for (i = 0; i < NumSystemGroups; i ++)
486 if (GetMD5Passwd(username, SystemGroups[i], junk) != NULL)
487 return (1);
488
489 /*
490 * Nope, not an MD5 user, either. Return 0 indicating no-go...
491 */
492
493 return (0);
494 }
495 }
496
497 return (1);
498#endif //// 0
f27bd5ab 499}
500
501
502/*
4b6bdd9f 503 * 'check_op()' - Check the current operation.
504 */
505
506static int /* O - 1 if match, 0 if not */
507check_op(policyop_t *po, /* I - Policy operation */
508 int allow_deny, /* I - POLICY_ALLOW or POLICY_DENY */
509 const char *name, /* I - User name */
510 const char *owner) /* I - Owner name */
511{
512 int i; /* Looping vars */
513 policyname_t *pn; /* Current policy name */
514
515
516 for (i = po->num_names, pn = po->names; i > 0; i --, pn ++)
517 {
518 if (pn->allow_deny != allow_deny)
519 continue;
520
521 if (!strcasecmp(pn->name, "@OWNER"))
522 {
523 if (owner && !strcasecmp(name, owner))
524 return (1);
525 }
526 else if (pn->name[0] == '@')
527 {
528 if (check_group(name, pn->name + 1))
529 return (1);
530 }
531 else if (!strcasecmp(name, pn->name))
532 return (1);
533 }
534
535 return (0);
536}
537
538
539/*
fd09381d 540 * End of "$Id: policy.c,v 1.1.2.9 2004/07/02 22:15:51 mike Exp $".
f27bd5ab 541 */