Sophie

Sophie

distrib > Mandriva > 2010.0 > i586 > media > contrib-release > by-pkgid > 4517eeffd76dc810f1f5ab232e377f67 > files > 6

libmille-xterm-print1-1.0-0.2137.2mdv2010.0.i586.rpm

libhideprinters: 	Hides printers from applications
Copyright (C) 2005 Revolution Linux inc, Jean-Michel Dault
	      jmdault@revolutionlinux.com

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

----------------------------------------------------------------------------

RATIONALE:

Most organizations have multile printers. When an organization has a
mix of machines under different operating systems, setting up a central
Cups server makes sense. Mac and Linux users can natively use Cups, while
Windows users can print to a Samba server that is mapped to Cups.

Unfortunately, even though Cups has an access mechanism to control who can
print to which printers, it has no such mechanism for browsing. Even if
the user doesn't have access to a printer, he still sees it on the printer
list of his application.

Imagine a school district with 50 different schools, and multiple printers
per school. Some printers are available only to students, some are for
administrative use, etc. 

If we setup all these printers on a Cups server, all applications will see
every printer. Imagine having 1,000 printers in Mozilla and having to choose
the right one! Was it 007450OptraN, or maybe 069352HP4L? 

PARTIAL SOLUTIONS:

Some programs, like gtklp and kdeprint in kiosk mode, have configurable
filters so that the user will only see the printers he has access to.

However, these programs replace only lpr, and that's not enough:
- Mozilla, Gimp and Scribus call cupsGetDests to fill its printer list
- Some versions of OpenOffice use cups, while others fallback to
  doing a "lpc status"
- kprinter uses cupsDoRequest and directly parses the cups attributes

So even though lpr is modified, they can still see all the printers!

It's possible to use brute-force and do a:
perl -pi -e "s|libcups|libkups|g;"
on the binaries to get rid ot the printer list and have only a default
printer and to call gtklp/kprinter and choose the printer afterwards, 
but then the problem is you have a double window problem: the user
first prints on the default printer, then needs choose the right printer.

But with this approach, you have to modify every application and redo the
job each time someone upgrades any application. 

Another problem is that Mozilla and OpenOffice call lpr in a blocking way:
they wait for the result code of the program. Meanwhile, if the user moves
the kprinter or gtklp window, the backgound does not refresh and it gives
the impression that the application is frozen.

OK, it's possible to write a wrapper script that calls gtklp or lpr in the
background, but then you have to make sure that printing a file works as
well as printing from standard output, that everything is escaped properly,
etc. 

So we needed to find something better!

THE FULL SOLUTION:

We decided to create a shim that wraps around libcups, and lists only
specified printers. 

It works, since:
- lpr-cups, lpstat-cups, lpc-cups, lp-cups are all replacement for
  standard lp/lpr programs, and use cups directly
- gtklp uses cups
- kprinter uses cups
- Mozilla uses cups
- OpenOffice uses cups

HOW IT WORKS:

We modify the /etc/profile scripts to have:
LD_PRELOAD=libhidebups.so
The library is loaded by the linker for every program and overrides
functions in the standard cups library.

We disable listing of every printer unless there is a file with the printer
name in the .gtklp/accept directory in the user's home. We chose this
scructure because that's what gtklp uses, and it's much easier to do a
stat() on a file than it is to parse a config file.

For example, if there are three printers (foo, bar and baz), there is a file
called /home/peter/.gtklp/accept/bar on the system, peter can only print on
the printer called "bar".

This way, we can easily have scripts that fetch the permissions from an LDAP
directory and create a file for each printer the user has access to. 

This is an example of a script that is placed in Xsession:
---------- snip -------------
rm -f $HOME/.gtklp/accept/*
export PRINTER=`/usr/bin/ldap_getdefaultprinter $USER $MACHINE`
touch $HOME/.gtklp/accept/$PRINTER
for printer in `/usr/bin/ldap_getallprinters $USER $MACHINE`
do 
  touch $HOME/.gtklp/accept/$printer
done
---------- snip -------------

The script ldap_getallprinters returns a list of printers, one by line,
while the ldap_getdefaultprinter returns only the default printer. The
$MACHINE variable lets us select printers depending on where the user is
logged on.

These scripts are not supplied with this software, because they vary greatly
from organization to organization. However, our consulting department can
integrate our system into any environment: see below for our contact
information.

If a user has no /home or no .gtklp/accept/*, he will not be able to see any
printers, but will be able to save in PostScript of PDF via most
applications.

LIMITATIONS:

- This version is limited to 2048 printers. If there are more than 2048
printers, some will not be shown. Modify the MAX_PRT definition in
libhideprinters.c to increase it.

TECHNICAL INFO:

The libhideprinters.so shim does this:

- Override cupsDoFileRequest so we can remove unwanted printers.

  This function intercepts all requests to the Cups server. For every printer, 
  it checks for the presence of a file named $HOME/.gtklp/accept/<NAME>. If 
  the file doesn't exist, it removes the printer from the Cups request.

  A cups request consists of a series of attributes, grouped together. The
  structure in memory is a list, and each record contains a pointer to the
  next attribute. To hide a printer, we set the pointer so it skips to the
  next printer's first attribute, or NULL if it is the last printer.


- Override cupsGetDest because if we remove the default printer in
  the previous function, there will be no default printer. Mozilla
  absolutely needs one, otherwise it will segfault.

  Cups uses the PRINTER environment variable by default. If the variable is
  not present, or the printer does not exist, it will use the default 
  printer in Cups. If there is none, it returns NULL.

  We check for this NULL value and replace it instead with the first 
  available printer.


CREDITS:

- This program is based on some code found in Linux Journal:
  "Modifying a Dynamic Library Without Changing the Source Code"
  http://www.linuxjournal.com/article/7795

- Code for showprinters.c was taken from the Mozilla Cups patch from
  Michael Kaply (IBM) <mozilla@kaply.com>


CONTACT US:

Don't hesitate to contact the authors for more information, questions or
suggestions for this program.

Commercial support contracts are also available for this product.

Jean-Michel Dault
jmdault@revolutionlinux.com
Revolution Linux inc.
145 Sauve
Sherbrooke (Quebec)
J!J 1L6 CANADA
(819) 780-8955