2022-05-13 20:08:20 +08:00
/*
* Policy routines for the CUPS scheduler .
*
* Copyright 2007 - 2011 , 2014 by Apple Inc .
* Copyright 1997 - 2006 by Easy Software Products , all rights reserved .
*
* Licensed under Apache License v2 .0 . See the file " LICENSE " for more information .
*/
/*
* Include necessary headers . . .
*/
# include "cupsd.h"
# include <pwd.h>
/*
* Local functions . . .
*/
static int compare_ops ( cupsd_location_t * a , cupsd_location_t * b ) ;
static int compare_policies ( cupsd_policy_t * a , cupsd_policy_t * b ) ;
static void free_policy ( cupsd_policy_t * p ) ;
static int hash_op ( cupsd_location_t * op ) ;
/*
* ' cupsdAddPolicy ( ) ' - Add a policy to the system .
*/
cupsd_policy_t * /* O - Policy */
cupsdAddPolicy ( const char * policy ) /* I - Name of policy */
{
cupsd_policy_t * temp ; /* Pointer to policy */
if ( ! policy )
return ( NULL ) ;
if ( ! Policies )
Policies = cupsArrayNew3 ( ( cups_array_func_t ) compare_policies , NULL ,
( cups_ahash_func_t ) NULL , 0 ,
( cups_acopy_func_t ) NULL ,
( cups_afree_func_t ) free_policy ) ;
if ( ! Policies )
return ( NULL ) ;
if ( ( temp = calloc ( 1 , sizeof ( cupsd_policy_t ) ) ) ! = NULL )
{
cupsdSetString ( & temp - > name , policy ) ;
cupsArrayAdd ( Policies , temp ) ;
}
return ( temp ) ;
}
/*
* ' cupsdAddPolicyOp ( ) ' - Add an operation to a policy .
*/
cupsd_location_t * /* O - New policy operation */
cupsdAddPolicyOp ( cupsd_policy_t * p , /* I - Policy */
cupsd_location_t * po , /* I - Policy operation to copy */
ipp_op_t op ) /* I - IPP operation code */
{
cupsd_location_t * temp ; /* New policy operation */
cupsdLogMessage ( CUPSD_LOG_DEBUG2 , " cupsdAddPolicyOp(p=%p, po=%p, op=%x(%s)) " ,
p , po , op , ippOpString ( op ) ) ;
if ( ! p )
return ( NULL ) ;
if ( ! p - > ops )
p - > ops = cupsArrayNew3 ( ( cups_array_func_t ) compare_ops , NULL ,
( cups_ahash_func_t ) hash_op , 128 ,
( cups_acopy_func_t ) NULL ,
( cups_afree_func_t ) cupsdFreeLocation ) ;
if ( ! p - > ops )
return ( NULL ) ;
if ( ( temp = cupsdCopyLocation ( po ) ) ! = NULL )
{
temp - > op = op ;
temp - > limit = CUPSD_AUTH_LIMIT_IPP ;
cupsArrayAdd ( p - > ops , temp ) ;
}
return ( temp ) ;
}
/*
* ' cupsdCheckPolicy ( ) ' - Check the IPP operation and username against a policy .
*/
http_status_t /* I - 1 if OK, 0 otherwise */
cupsdCheckPolicy ( cupsd_policy_t * p , /* I - Policy */
cupsd_client_t * con , /* I - Client connection */
const char * owner ) /* I - Owner of object */
{
cupsd_location_t * po ; /* Current policy operation */
/*
* Range check . . .
*/
if ( ! p | | ! con )
{
cupsdLogMessage ( CUPSD_LOG_CRIT , " cupsdCheckPolicy: p=%p, con=%p. " , p , con ) ;
2023-10-26 10:19:35 +08:00
return ( HTTP_STATUS_SERVER_ERROR ) ;
2022-05-13 20:08:20 +08:00
}
/*
* Find a match for the operation . . .
*/
if ( ( po = cupsdFindPolicyOp ( p , con - > request - > request . op . operation_id ) ) = = NULL )
{
cupsdLogMessage ( CUPSD_LOG_DEBUG2 , " cupsdCheckPolicy: No matching operation, returning 0. " ) ;
2023-10-26 10:19:35 +08:00
return ( HTTP_STATUS_OK ) ;
2022-05-13 20:08:20 +08:00
}
con - > best = po ;
/*
* Return the status of the check . . .
*/
return ( cupsdIsAuthorized ( con , owner ) ) ;
}
/*
* ' cupsdDeleteAllPolicies ( ) ' - Delete all policies in memory .
*/
void
cupsdDeleteAllPolicies ( void )
{
cupsd_printer_t * printer ; /* Current printer */
if ( ! Policies )
return ;
/*
* First clear the policy pointers for all printers . . .
*/
for ( printer = ( cupsd_printer_t * ) cupsArrayFirst ( Printers ) ;
printer ;
printer = ( cupsd_printer_t * ) cupsArrayNext ( Printers ) )
printer - > op_policy_ptr = NULL ;
DefaultPolicyPtr = NULL ;
/*
* Then free all of the policies . . .
*/
cupsArrayDelete ( Policies ) ;
Policies = NULL ;
}
/*
* ' cupsdFindPolicy ( ) ' - Find a named policy .
*/
cupsd_policy_t * /* O - Policy */
cupsdFindPolicy ( const char * policy ) /* I - Name of policy */
{
cupsd_policy_t key ; /* Search key */
/*
* Range check . . .
*/
if ( ! policy )
return ( NULL ) ;
/*
* Look it up . . .
*/
key . name = ( char * ) policy ;
return ( ( cupsd_policy_t * ) cupsArrayFind ( Policies , & key ) ) ;
}
/*
* ' cupsdFindPolicyOp ( ) ' - Find a policy operation .
*/
cupsd_location_t * /* O - Policy operation */
cupsdFindPolicyOp ( cupsd_policy_t * p , /* I - Policy */
ipp_op_t op ) /* I - IPP operation */
{
cupsd_location_t key , /* Search key... */
* po ; /* Current policy operation */
cupsdLogMessage ( CUPSD_LOG_DEBUG2 , " cupsdFindPolicyOp(p=%p, op=%x(%s)) " ,
p , op , ippOpString ( op ) ) ;
/*
* Range check . . .
*/
if ( ! p )
return ( NULL ) ;
/*
* Check the operation against the available policies . . .
*/
key . op = op ;
if ( ( po = ( cupsd_location_t * ) cupsArrayFind ( p - > ops , & key ) ) ! = NULL )
{
cupsdLogMessage ( CUPSD_LOG_DEBUG2 ,
" cupsdFindPolicyOp: Found exact match... " ) ;
return ( po ) ;
}
key . op = IPP_ANY_OPERATION ;
if ( ( po = ( cupsd_location_t * ) cupsArrayFind ( p - > ops , & key ) ) ! = NULL )
{
cupsdLogMessage ( CUPSD_LOG_DEBUG2 ,
" cupsdFindPolicyOp: Found wildcard match... " ) ;
return ( po ) ;
}
cupsdLogMessage ( CUPSD_LOG_DEBUG2 , " cupsdFindPolicyOp: No match found. " ) ;
return ( NULL ) ;
}
/*
* ' cupsdGetPrivateAttrs ( ) ' - Get the private attributes for the current
* request .
*/
cups_array_t * /* O - Array or NULL for no restrictions */
cupsdGetPrivateAttrs (
cupsd_policy_t * policy , /* I - Policy */
cupsd_client_t * con , /* I - Client connection */
cupsd_printer_t * printer , /* I - Printer, if any */
const char * owner ) /* I - Owner of object */
{
char * name ; /* Current name in access list */
cups_array_t * access_ptr , /* Access array */
* attrs_ptr ; /* Attributes array */
const char * username ; /* Username associated with request */
ipp_attribute_t * attr ; /* Attribute from request */
struct passwd * pw ; /* User info */
# ifdef DEBUG
cupsdLogMessage ( CUPSD_LOG_DEBUG2 ,
" cupsdGetPrivateAttrs(policy=%p(%s), con=%p(%d), "
2023-10-26 10:19:35 +08:00
" printer=%p(%s), owner= \" %s \" ) " , policy , policy ? policy - > name : " " , con ,
2022-05-13 20:08:20 +08:00
con - > number , printer , printer ? printer - > name : " " , owner ) ;
# endif /* DEBUG */
if ( ! policy )
{
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 ) ;
policy = DefaultPolicyPtr ;
}
/*
* Get the access and attributes lists that correspond to the request . . .
*/
# ifdef DEBUG
cupsdLogMessage ( CUPSD_LOG_DEBUG2 , " cupsdGetPrivateAttrs: %s " ,
ippOpString ( con - > request - > request . op . operation_id ) ) ;
# endif /* DEBUG */
switch ( con - > request - > request . op . operation_id )
{
case IPP_GET_SUBSCRIPTIONS :
case IPP_GET_SUBSCRIPTION_ATTRIBUTES :
case IPP_GET_NOTIFICATIONS :
access_ptr = policy - > sub_access ;
attrs_ptr = policy - > sub_attrs ;
break ;
default :
access_ptr = policy - > job_access ;
attrs_ptr = policy - > job_attrs ;
break ;
}
/*
* If none of the attributes are private , return NULL now . . .
*/
if ( ( name = ( char * ) cupsArrayFirst ( attrs_ptr ) ) ! = NULL & &
! _cups_strcasecmp ( name , " none " ) )
{
# ifdef DEBUG
cupsdLogMessage ( CUPSD_LOG_DEBUG2 , " cupsdGetPrivateAttrs: Returning NULL. " ) ;
# endif /* DEBUG */
return ( NULL ) ;
}
/*
* Otherwise check the user against the access list . . .
*/
if ( con - > username [ 0 ] )
username = con - > username ;
else if ( ( attr = ippFindAttribute ( con - > request , " requesting-user-name " ,
IPP_TAG_NAME ) ) ! = NULL )
username = attr - > values [ 0 ] . string . text ;
else
username = " anonymous " ;
if ( username [ 0 ] )
{
pw = getpwnam ( username ) ;
endpwent ( ) ;
}
else
pw = NULL ;
# ifdef DEBUG
cupsdLogMessage ( CUPSD_LOG_DEBUG2 , " cupsdGetPrivateAttrs: username= \" %s \" " ,
username ) ;
# endif /* DEBUG */
/*
* Otherwise check the user against the access list . . .
*/
for ( name = ( char * ) cupsArrayFirst ( access_ptr ) ;
name ;
name = ( char * ) cupsArrayNext ( access_ptr ) )
{
# ifdef DEBUG
cupsdLogMessage ( CUPSD_LOG_DEBUG2 , " cupsdGetPrivateAttrs: name=%s " , name ) ;
# endif /* DEBUG */
if ( printer & & ! _cups_strcasecmp ( name , " @ACL " ) )
{
char * acl ; /* Current ACL user/group */
for ( acl = ( char * ) cupsArrayFirst ( printer - > users ) ;
acl ;
acl = ( char * ) cupsArrayNext ( printer - > users ) )
{
if ( acl [ 0 ] = = ' @ ' )
{
/*
* Check group membership . . .
*/
if ( cupsdCheckGroup ( username , pw , acl + 1 ) )
break ;
}
else if ( acl [ 0 ] = = ' # ' )
{
/*
* Check UUID . . .
*/
if ( cupsdCheckGroup ( username , pw , acl ) )
break ;
}
else if ( ! _cups_strcasecmp ( username , acl ) )
break ;
}
}
else if ( owner & & ! _cups_strcasecmp ( name , " @OWNER " ) & &
! _cups_strcasecmp ( username , owner ) )
{
# ifdef DEBUG
cupsdLogMessage ( CUPSD_LOG_DEBUG2 ,
" cupsdGetPrivateAttrs: Returning NULL. " ) ;
# endif /* DEBUG */
return ( NULL ) ;
}
else if ( ! _cups_strcasecmp ( name , " @SYSTEM " ) )
{
int i ; /* Looping var */
for ( i = 0 ; i < NumSystemGroups ; i + + )
if ( cupsdCheckGroup ( username , pw , SystemGroups [ i ] ) )
{
# ifdef DEBUG
cupsdLogMessage ( CUPSD_LOG_DEBUG2 ,
" cupsdGetPrivateAttrs: Returning NULL. " ) ;
# endif /* DEBUG */
return ( NULL ) ;
}
}
else if ( name [ 0 ] = = ' @ ' )
{
if ( cupsdCheckGroup ( username , pw , name + 1 ) )
{
# ifdef DEBUG
cupsdLogMessage ( CUPSD_LOG_DEBUG2 ,
" cupsdGetPrivateAttrs: Returning NULL. " ) ;
# endif /* DEBUG */
return ( NULL ) ;
}
}
else if ( ! _cups_strcasecmp ( username , name ) )
{
# ifdef DEBUG
cupsdLogMessage ( CUPSD_LOG_DEBUG2 , " cupsdGetPrivateAttrs: Returning NULL. " ) ;
# endif /* DEBUG */
return ( NULL ) ;
}
}
/*
* No direct access , so return private attributes list . . .
*/
# ifdef DEBUG
cupsdLogMessage ( CUPSD_LOG_DEBUG2 , " cupsdGetPrivateAttrs: Returning list. " ) ;
# endif /* DEBUG */
return ( attrs_ptr ) ;
}
/*
* ' compare_ops ( ) ' - Compare two operations .
*/
static int /* O - Result of comparison */
compare_ops ( cupsd_location_t * a , /* I - First operation */
cupsd_location_t * b ) /* I - Second operation */
{
return ( a - > op - b - > op ) ;
}
/*
* ' compare_policies ( ) ' - Compare two policies .
*/
static int /* O - Result of comparison */
compare_policies ( cupsd_policy_t * a , /* I - First policy */
cupsd_policy_t * b ) /* I - Second policy */
{
return ( _cups_strcasecmp ( a - > name , b - > name ) ) ;
}
/*
* ' free_policy ( ) ' - Free the memory used by a policy .
*/
static void
free_policy ( cupsd_policy_t * p ) /* I - Policy to free */
{
cupsArrayDelete ( p - > job_access ) ;
cupsArrayDelete ( p - > job_attrs ) ;
cupsArrayDelete ( p - > sub_access ) ;
cupsArrayDelete ( p - > sub_attrs ) ;
cupsArrayDelete ( p - > ops ) ;
cupsdClearString ( & p - > name ) ;
free ( p ) ;
}
/*
* ' hash_op ( ) ' - Generate a lookup hash for the operation .
*/
static int /* O - Hash value */
hash_op ( cupsd_location_t * op ) /* I - Operation */
{
return ( ( ( op - > op > > 6 ) & 0x40 ) | ( op - > op & 0x3f ) ) ;
}